changeset 122:52402232483f

WIP on the split up of e1000::set_up_device
author Louis Opter <louis@lse.epita.fr>
date Sun, 28 Jul 2013 02:50:43 -0700
parents 6f600f83a763
children 3816844250ff
files rathaxes_samples_e1000_split_set_up_device.patch
diffstat 1 files changed, 702 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/rathaxes_samples_e1000_split_set_up_device.patch	Sat Jul 27 16:08:40 2013 -0700
+++ b/rathaxes_samples_e1000_split_set_up_device.patch	Sun Jul 28 02:50:43 2013 -0700
@@ -1,20 +1,709 @@
 # HG changeset patch
-# Parent 069883bfa2ec71faaf7ab957bc35db087eacc3cc
+# Parent d62a08753da7cec4d44246b747ff79847d9b4238
 rathaxes: split and refactor e1000::set_up_device in {Rx,Tx}Ring methods
 
-
 diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt
 --- a/rathaxes/samples/e1000/e1000.blt
 +++ b/rathaxes/samples/e1000/e1000.blt
-@@ -752,8 +752,10 @@
-              */
-             for (i = 0; i != ${config.rx_ring_size}; ++i)
-             {
-+                /* XXX #46: */
-+                // hw_ctx->rx_ring.skbuffs[i].skbuff = ${rtx_ether_ctx.net_device.alloc_rx_skb(${config.rx_buffer_len})}; 
-                 hw_ctx->rx_ring.skbuffs[i].skbuff = (${Socket::AbstractSKBuff}*)netdev_alloc_skb(
+@@ -1,4 +1,4 @@
+-with e1000, Ethernet, Socket, PCI, LKM, Log, Builtin
++with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin
+ {
+     template type   e1000::RxDescriptor()
+     {
+@@ -96,8 +96,163 @@
+         {
+         }
+ 
++        chunk   Ethernet::adapter_init_rx(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++
++                /*
++                 * Receive initialization (section 14.4):
++                 *
++                 * 1. Program the receive address, in RAL/RAH;
++                 * 2. Initialize the Multicast Table Array;
++                 * 3. Program the interrupt mask register (done in
++                 *    e1000::activate_device_interruption);
++                 * 4. Allocate the receive descriptor ring and map it to make it
++                 *    accessible by the device;
++                 * 5. Write the start address of the ring in RDBAL/RDBAH and set
++                 *    RDLEN (Receive Descriptor Length) to the size of the ring;
++                 * 6. Set the RDH/RDT (Receive Descriptor Head/Tail) indexes to the
++                 *    beginning and end of the ring;
++                 * 7. Make sure that RCTL.BSIZE and .BSEX are at 0 to configure the
++                 *    receive buffer size to 2048 bytes (e1000::rx_buffer_len).
++                 * 8. Set RCTL.EN to enable the receiver.
++                 *
++                 * The ugly casts here are caused by the lack of CNorm unstrict.
++                 */
++
++                int i;
++
++                /* 1. Program the receive address */
++
++                /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */
++                rtx_e1000_register_write32(hw_ctx, E1000_RAL,
++                        *(unsigned int *)(${rtx_ether_ctx.dev_addr}));
++                /*
++                 * The 16 upper bits of RAH also store the AS bits (which should be
++                 * 0) and the AV bit (should be 1 to set the address as valid).
++                 */
++                rtx_e1000_register_write32(hw_ctx, E1000_RAH,
++                        *(unsigned short *)(&${rtx_ether_ctx.dev_addr}[4]));
++                rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV);
++
++                ${Log::info("adapter_init_rx: receive address programmed")};
++
++                /* 2. Initialize the MTA */
++
++                for (i = 0; i != 128; ++i)
++                    rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0);
++
++                ${Log::info("adapter_init_rx: MTA init done")};
++
++                /* 4. Setup the receive descriptor ring */
++
++                /* Allocate the descriptors */
++                hw_ctx->rx_ring.size = ${config.rx_ring_size} * sizeof(*hw_ctx->rx_ring.base);
++                hw_ctx->rx_ring.size = ALIGN(hw_ctx->rx_ring.size, 4096);
++                hw_ctx->rx_ring.base = dma_alloc_coherent(
++                        ${rtx_ether_ctx.device},
++                        hw_ctx->rx_ring.size,
++                        &hw_ctx->rx_ring.dma_base,
++                        GFP_KERNEL);
++                /* XXX
++                 * The first arg is recognized as Ethernet::Device instead of
++                 * Device::AbstractDevice.
++                 */
++                hw_ctx->rx_ring.base = ${DMA::alloc_coherent(
++                    rtx_ether_ctx.device, local.hw_ctx.rx_ring.size, local.hw_ctx.rx_ring.dma_base.dma_handle
++                )};
++                if (!hw_ctx->rx_ring.base)
++                {
++                    ${Log::info("adapter_init_rx: cannot allocate the descriptors for the rx ring")};
++                    goto err_rx_ring_alloc;
++                }
++
++                ${Log::info("adapter_init_rx: rx descriptors allocated")};
++
++                /*
++                 * Allocate the skbuffs, map them for DMA, and write their address
++                 * in the corresponding descriptor.
++                 */
++                for (i = 0; i != ${config.rx_ring_size}; ++i)
++                {
++                    // XXX #46: ${Socket::SKBuff.ref} skbuff = ${rtx_ether_ctx.net_device.alloc_rx_skbuff(config.rx_buffer_len)};
++                    ${Socket::AbstractSKBuff.ref} k_sk_buff = (${Socket::AbstractSKBuff.ref})netdev_alloc_skb(
++                        ${rtx_ether_ctx.net_device.k_net_dev}, ${config.rx_buffer_len}
++                    );
++                    if (!k_sk_buff)
++                    {
++                        ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")};
++                        goto err_skbuffs_alloc;
++                    }
++                    ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i];
++                    // XXX breaks rtxGen: ${local.skbuff.init(local.k_sk_buff)};
++                    skbuff->skbuff = k_sk_buff;
++                    skbuff->dma_handle = 0;
++                    // XXX #46: ${local.skbuff.map_from(rtx_ether_ctx.device)};
++                    if (rtx_socket_skbuff_map(${local.skbuff}, ${rtx_ether_ctx.device}, RTX_DMA_FROM_DEVICE))
++                    {
++                        ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")};
++                        goto err_skbuffs_map;
++                    }
++                    hw_ctx->rx_ring.base[i].buff_addr = cpu_to_le64(${local.skbuff.sk_buff});
++                }
++
++                ${Log::info("adapter_init_rx: skbuffs allocated")};
++
++                /* 5. Save the emplacement and the size of the ring in RDBA/RDLEN */
++                rtx_e1000_register_write32(hw_ctx, E1000_RDBAL, hw_ctx->rx_ring.dma_base & 0xffffffff);
++                rtx_e1000_register_write32(hw_ctx, E1000_RDBAH, hw_ctx->rx_ring.dma_base >> 32);
++                rtx_e1000_register_write32(hw_ctx, E1000_RDLEN, hw_ctx->rx_ring.size);
++
++                /* 6. Setup RDH/RDT */
++                rtx_e1000_register_write32(hw_ctx, E1000_RDH, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_RDT, ${config.rx_ring_size} - 1);
++
++                /* 7. Configure the buffer size, */
++                rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_BSIZE_${config.rx_buffer_len});
++
++                /* 8. Enable the receiver */
++                rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_EN);
++
++                ${Log::info("adapter_init_rx: receive registers configured and receiver enabled")};
++
++                /*
++                 * XXX: We can't return here since we are not in a function but
++                 * in a chunk of code (injected in a function).
++                 */
++                goto init_rx_ok;
++
++            err_skbuffs_alloc:
++                while (i--)
++                {
++                    dma_unmap_single(
++                            ${rtx_ether_ctx.device},
++                            hw_ctx->rx_ring.skbuffs[i].dma_handle,
++                            ${config.rx_buffer_len},
++                            DMA_FROM_DEVICE);
++            err_skbuffs_map:
++                    /* XXX leaking cast: */
++                    dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff);
++                }
++
++                dma_free_coherent(${rtx_ether_ctx.device}, hw_ctx->rx_ring.size,
++                        hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base);
++            err_rx_ring_alloc:
++                /*
++                 * XXX: Likewise, if there is something else to rollback in the
++                 * enclosing function, this won't be done.
++                 */
++                return -ENOMEM;
++
++            init_rx_ok: (void)0; /* NOP, to make this a valid label. */
++            }
++        }
++
+         map
+         {
++            size: ((${self}).size);
++            dma_base: ((${self}).dma_base);
+         }
+     }
+ 
+@@ -208,7 +363,62 @@
+             }
+         }
+ 
+-        method   clean()
++        chunk   Ethernet::adapter_init_tx(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++
++                /*
++                 * Transmission initialization (section 14.5):
++                 *
++                 * 1. Allocate the transmit descriptors ring and map it to make it
++                 *    accessible by the device;
++                 * 2. Write the start address of the ring in TDBAL/TDBAH and set
++                 *    TDLEN to the size of the ring;
++                 * 3. Set the TDH/TDT indexes to the beginning and end of the ring;
++                 * 4. Set TCTL.PSP to pad short packets and TCTL.EN to enable the
++                 *    transmitter.
++                 */
++
++                /* 1. Allocate the tx ring */
++                hw_ctx->tx_ring.size = ${config.tx_ring_size} * sizeof(*hw_ctx->tx_ring.base);
++                hw_ctx->tx_ring.size = ALIGN(hw_ctx->tx_ring.size, 4096);
++                hw_ctx->tx_ring.base = dma_alloc_coherent(
++                        ${rtx_ether_ctx.device},
++                        hw_ctx->tx_ring.size,
++                        &hw_ctx->tx_ring.dma_base,
++                        GFP_KERNEL);
++                if (!hw_ctx->rx_ring.base)
++                {
++                    ${Log::info("adapter_init_tx: cannot allocate the descriptors for the tx ring")};
++                    /*
++                     * XXX: If there is something else to rollback in the enclosing
++                     * function, this won't be done.
++                     */
++                    return -ENOMEM;
++                }
++
++                ${Log::info("adapter_init_tx: tx descriptors allocated")};
++
++                /* 2. Save the emplacement and the size of the ring in TDBA/TDLEN */
++                rtx_e1000_register_write32(hw_ctx, E1000_TDBAL, hw_ctx->tx_ring.dma_base & 0xffffffff);
++                rtx_e1000_register_write32(hw_ctx, E1000_TDBAH, hw_ctx->tx_ring.dma_base >> 32);
++                rtx_e1000_register_write32(hw_ctx, E1000_TDLEN, hw_ctx->tx_ring.size);
++
++                /* 3. Setup TDH/TDT to zero: the queue is empty */
++                rtx_e1000_register_write32(hw_ctx, E1000_TDH, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_TDT, 0);
++                hw_ctx->tx_ring.head = 0;
++                hw_ctx->tx_ring.tail = 0;
++
++                /* 4. Set TCTL.PSP and enable the transmitter */
++                rtx_e1000_register_set32(hw_ctx, E1000_TCTL, E1000_TCTL_PSP|E1000_TCTL_EN);
++
++                ${Log::info("adapter_init_tx: transmit registers configured and transmitter enabled")};
++            }
++        }
++
++        method  clean()
+         {
+             rtx_e1000_tx_ring_clean(${self});
+         }
+@@ -247,9 +457,8 @@
+         {
+             int                         bars;
+             unsigned char /* __iomem */ *ioaddr;
+-
+-            ${e1000::RxRing}    rx_ring;
+-            ${e1000::TxRing}    tx_ring;
++            ${e1000::RxRing.scalar}     rx_ring;
++            ${e1000::TxRing.scalar}     tx_ring;
+         }
+ 
+         chunk   Ethernet::HardwareContext()
+@@ -309,10 +518,53 @@
+             }
+         }
+ 
++        chunk   Ethernet::adapter_setup(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx;
++
++                /*
++                 * "General Configuration" (section 14.3):
++                 *
++                 * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection &
++                 *   negociation;
++                 * - CTRL.LRST/FRCSPD: Unset them to initiate the auto-negociation;
++                 * - CTRL.PHY_RST: Unset it;
++                 * - CTRL.ILOS: Unset it (ILOS is Invert Loss Of Signal);
++                 * - CTRL.VME: Make sure it's not set to disable VLAN support;
++                 * - Set the control flow registers to 0;
++                 * - Finally, initialize all the statistic registers from
++                 *   E1000_CRCERRS to E1000_TSCTFC.
++                 */
++                rtx_e1000_register_set32(hw_ctx, E1000_CTRL,
++                                         E1000_CMD_ASDE |
++                                         E1000_CMD_SLU);
++                rtx_e1000_register_unset32(hw_ctx, E1000_CTRL,
++                                           E1000_CMD_LRST    |
++                                           E1000_CMD_FRCSPD  |
++                                           E1000_CMD_PHY_RST |
++                                           E1000_CMD_ILOS    |
++                                           E1000_CMD_VME);
++                rtx_e1000_register_write32(hw_ctx, E1000_FCAH, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_FCAL, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_FCT, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_FCTTV, 0);
++                /* 
++                 * XXX: Using int i clashes with another int i from the
++                 * "parent" chunk:
++                 */
++                for (int j = 0; j != 64; ++j)
++                    rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + j * 4, 0);
++
++                ${Log::info("adapter_setup: general configuration done")};
++            }
++        }
++
+         map
+         {
++            rx_ring: ((${self})->rx_ring);
++            //tx_ring: ((${self})->tx_ring);
+         }
+-
+     }
+ 
+     template type   e1000::Register()
+@@ -615,269 +867,6 @@
+         }
+     }
+ 
+-    /* TODO: refactor
+-     *
+-     * Split into two method methods:
+-     * - e1000::RxRing::init_rx()
+-     * - e1000::TxRing::init_tx()
+-     *
+-     * Also it should use the new methods in Socket::SKbuff.
+-     */
+-    template sequence   set_up_device(Ethernet::Device rtx_ether_ctx)
+-    {
+-        chunk  ::CALL()
+-        {
+-            /*
+-             * This part is documented in the Intel Gigabit Ethernet Controller
+-             * Software Developper manual. (You can find it in the doc/hardware
+-             * directory).
+-             *
+-             * Since this part is actually completely device specific it should
+-             * not be written here. (but in the front-end).
+-             */
+-
+-            /*
+-             * shortcut hw_ctx... maybe we should directly take an
+-             * e1000::Context? (but we would need to make it point back to
+-             * the struct net_device)
+-             */
+-            ${e1000::Context.ref} hw_ctx;
+-            hw_ctx = &${rtx_ether_ctx}->hw_ctx;
+-
+-            /*
+-             * "General Configuration" (section 14.3):
+-             *
+-             * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection &
+-             *   negociation;
+-             * - CTRL.LRST/FRCSPD: Unset them to initiate the auto-negociation;
+-             * - CTRL.PHY_RST: Unset it;
+-             * - CTRL.ILOS: Unset it (ILOS is Invert Loss Of Signal);
+-             * - CTRL.VME: Make sure it's not set to disable VLAN support;
+-             * - Set the control flow registers to 0;
+-             * - Finally, initialize all the statistic registers from
+-             *   E1000_CRCERRS to E1000_TSCTFC.
+-             */
+-
+-            int i;
+-
+-            rtx_e1000_register_set32(hw_ctx, E1000_CTRL,
+-                                     E1000_CMD_ASDE |
+-                                     E1000_CMD_SLU);
+-            rtx_e1000_register_unset32(hw_ctx, E1000_CTRL,
+-                                       E1000_CMD_LRST    |
+-                                       E1000_CMD_FRCSPD  |
+-                                       E1000_CMD_PHY_RST |
+-                                       E1000_CMD_ILOS    |
+-                                       E1000_CMD_VME);
+-            rtx_e1000_register_write32(hw_ctx, E1000_FCAH, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_FCAL, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_FCT, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_FCTTV, 0);
+-            for (i = 0; i != 64; ++i)
+-                rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + i * 4, 0);
+-            
+-            {
+-                ${Log::info("setup_device: general configuration done")};
+-            }
+-
+-            /*
+-             * Receive initialization (section 14.4):
+-             *
+-             * 1. Program the receive address, in RAL/RAH;
+-             * 2. Initialize the Multicast Table Array;
+-             * 3. Program the interrupt mask register (done in
+-             *    e1000::activate_device_interruption);
+-             * 4. Allocate the receive descriptor ring and map it to make it
+-             *    accessible by the device;
+-             * 5. Write the start address of the ring in RDBAL/RDBAH and set
+-             *    RDLEN (Receive Descriptor Length) to the size of the ring;
+-             * 6. Set the RDH/RDT (Receive Descriptor Head/Tail) indexes to the
+-             *    beginning and end of the ring;
+-             * 7. Make sure that RCTL.BSIZE and .BSEX are at 0 to configure the
+-             *    receive buffer size to 2048 bytes (e1000::rx_buffer_len).
+-             * 8. Set RCTL.EN to enable the receiver.
+-             *
+-             * The ugly casts here are caused by the lack of CNorm unstrict.
+-             */
+-
+-            /* 1. Program the receive address */
+-
+-            /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */
+-            rtx_e1000_register_write32(hw_ctx, E1000_RAL,
+-                    *(unsigned int *)(${rtx_ether_ctx.dev_addr}));
+-            /*
+-             * The 16 upper bits of RAH also store the AS bits (which should be
+-             * 0) and the AV bit (should be 1 to set the address as valid).
+-             */
+-            rtx_e1000_register_write32(hw_ctx, E1000_RAH,
+-                    *(unsigned short *)(&${rtx_ether_ctx.dev_addr}[4]));
+-            rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV);
+-
+-            {
+-                ${Log::info("setup_device: receive address programmed")};
+-            }
+-
+-            /* 2. Initialize the MTA */
+-
+-            for (i = 0; i != 128; ++i)
+-                rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0);
+-
+-            {
+-                ${Log::info("setup_device: MTA init done")};
+-            }
+-
+-            /* 4. Setup the receive descriptor ring */
+-
+-            /* Allocate the descriptors */
+-            hw_ctx->rx_ring.size = ${config.rx_ring_size} * sizeof(*hw_ctx->rx_ring.base);
+-            hw_ctx->rx_ring.size = ALIGN(hw_ctx->rx_ring.size, 4096);
+-            hw_ctx->rx_ring.base = dma_alloc_coherent(
+-                    ${rtx_ether_ctx.device},
+-                    hw_ctx->rx_ring.size,
+-                    &hw_ctx->rx_ring.dma_base,
+-                    GFP_KERNEL);
+-            if (!hw_ctx->rx_ring.base)
+-            {
+-                ${Log::info("cannot allocate the descriptors for the rx ring")};
+-                goto err_rx_ring_alloc;
+-            }
+-
+-            {
+-                ${Log::info("setup_device: rx descriptors allocated")};
+-            }
+-
+-            /*
+-             * Allocate the skbuffs, map them for DMA, and write their address
+-             * in the corresponding descriptor.
+-             */
+-            for (i = 0; i != ${config.rx_ring_size}; ++i)
+-            {
+-                hw_ctx->rx_ring.skbuffs[i].skbuff = (${Socket::AbstractSKBuff}*)netdev_alloc_skb(
 -                        ${rtx_ether_ctx.net_device.k_net_dev}, /* XXX: .k_net_dev isn't expanded here */
-+                        ${rtx_ether_ctx.net_device.k_net_dev},
-                         ${config.rx_buffer_len});
-                 if (!hw_ctx->rx_ring.skbuffs[i].skbuff)
-                 {
+-                        ${config.rx_buffer_len});
+-                if (!hw_ctx->rx_ring.skbuffs[i].skbuff)
+-                {
+-                    ${Log::info("cannot allocate a skbuff for the rx ring")};
+-                    goto err_skbuffs_alloc;
+-                }
+-                hw_ctx->rx_ring.skbuffs[i].dma_handle = dma_map_single(
+-                        ${rtx_ether_ctx.device},
+-                        (struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff, /* XXX leaking cast */
+-                        ${config.rx_buffer_len},
+-                        DMA_FROM_DEVICE);
+-                int dma_error = dma_mapping_error(${rtx_ether_ctx.device},
+-                        hw_ctx->rx_ring.skbuffs[i].dma_handle);
+-                if (dma_error)
+-                {
+-                    ${Log::info("cannot dma-map a skbuff for the rx ring")};
+-                    goto err_skbuffs_map;
+-                }
+-                hw_ctx->rx_ring.base[i].buff_addr = cpu_to_le64(
+-                        hw_ctx->rx_ring.skbuffs[i].skbuff);
+-            }
+-
+-            ${Log::info("setup_device: skbuffs allocated")};
+-
+-            /* 5. Save the emplacement and the size of the ring in RDBA/RDLEN */
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDBAL, hw_ctx->rx_ring.dma_base & 0xffffffff);
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDBAH, hw_ctx->rx_ring.dma_base >> 32);
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDLEN, hw_ctx->rx_ring.size);
+-
+-            /* 6. Setup RDH/RDT */
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDH, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDT, ${config.rx_ring_size} - 1);
+-
+-            /* 7. Configure the buffer size, */
+-            rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_BSIZE_${config.rx_buffer_len});
+-
+-            /* 8. Enable the receiver */
+-            rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_EN);
+-
+-            ${Log::info("setup_device: receive registers configured and receiver enabled")};
+-
+-            /*
+-             * Transmission initialization (section 14.5):
+-             *
+-             * 1. Allocate the transmit descriptors ring and map it to make it
+-             *    accessible by the device;
+-             * 2. Write the start address of the ring in TDBAL/TDBAH and set
+-             *    TDLEN to the size of the ring;
+-             * 3. Set the TDH/TDT indexes to the beginning and end of the ring;
+-             * 4. Set TCTL.PSP to pad short packets and TCTL.EN to enable the
+-             *    transmitter.
+-             */
+-
+-            /*
+-             * XXX: at this point we must be careful to not fuck up with i, or
+-             * we are going go have surprises in `err_skbuffs_alloc`. Maybe it's
+-             * time to separate the rx and tx initialization in two functions.
+-             */
+-
+-            /* 1. Allocate the tx ring */
+-            hw_ctx->tx_ring.size = ${config.tx_ring_size} * sizeof(*hw_ctx->tx_ring.base);
+-            hw_ctx->tx_ring.size = ALIGN(hw_ctx->tx_ring.size, 4096);
+-            hw_ctx->tx_ring.base = dma_alloc_coherent(
+-                    ${rtx_ether_ctx.device},
+-                    hw_ctx->tx_ring.size,
+-                    &hw_ctx->tx_ring.dma_base,
+-                    GFP_KERNEL);
+-            if (!hw_ctx->rx_ring.base)
+-            {
+-                ${Log::info("cannot allocate the descriptors for the tx ring")};
+-                goto err_tx_ring_alloc;
+-            }
+-
+-            ${Log::info("setup_device: tx descriptors allocated")};
+-
+-            /* 2. Save the emplacement and the size of the ring in TDBA/TDLEN */
+-            rtx_e1000_register_write32(hw_ctx, E1000_TDBAL, hw_ctx->tx_ring.dma_base & 0xffffffff);
+-            rtx_e1000_register_write32(hw_ctx, E1000_TDBAH, hw_ctx->tx_ring.dma_base >> 32);
+-            rtx_e1000_register_write32(hw_ctx, E1000_TDLEN, hw_ctx->tx_ring.size);
+-
+-            /* 3. Setup TDH/TDT to zero: the queue is empty */
+-            rtx_e1000_register_write32(hw_ctx, E1000_TDH, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_TDT, 0);
+-            hw_ctx->tx_ring.head = 0;
+-            hw_ctx->tx_ring.tail = 0;
+-
+-            /* 4. Set TCTL.PSP and enable the transmitter */
+-            rtx_e1000_register_set32(hw_ctx, E1000_TCTL, E1000_TCTL_PSP|E1000_TCTL_EN);
+-
+-            ${Log::info("transmit registers configured and transmitter enabled")};
+-
+-            /*
+-             * XXX: We can't return here since we are not in a function but in
+-             * a chunk of code (injected in a function).
+-             */
+-            goto ok;
+-
+-        err_tx_ring_alloc:
+-            /*
+-             * Likewise, always the same problem with error handling, we don't
+-             * know where we are at in the "parent context":
+-             */
+-        err_skbuffs_alloc:
+-            while (i--)
+-            {
+-                dma_unmap_single(
+-                        ${rtx_ether_ctx.device},
+-                        hw_ctx->rx_ring.skbuffs[i].dma_handle,
+-                        ${config.rx_buffer_len},
+-                        DMA_FROM_DEVICE);
+-        err_skbuffs_map:
+-                /* XXX leaking cast: */
+-                dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff);
+-            }
+-
+-            dma_free_coherent(${rtx_ether_ctx.device}, hw_ctx->rx_ring.size,
+-                    hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base);
+-        err_rx_ring_alloc:
+-            return -ENOMEM;
+-
+-        ok:
+-        }
+-    }
+-
+     /* TODO:
+      *
+      * Refactor into two methods (one in RxRing and one in TxRing) and make use
+diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti
+--- a/rathaxes/samples/e1000/e1000.rti
++++ b/rathaxes/samples/e1000/e1000.rti
+@@ -1,23 +1,10 @@
+-interface e1000 : Socket, Ethernet, PCI, LKM, Builtin
++interface e1000 : Socket, Ethernet, DMA, PCI, LKM, Builtin
+ {
+     required variable   Builtin::number rx_ring_size;
+     required variable   Builtin::number tx_ring_size;
+     required variable   Builtin::number rx_buffer_len;
+     required variable   Builtin::number tx_max_data_per_desc;
+ 
+-    provided type   Context
+-    {
+-        chunk       Ethernet::HardwareContext();
+-        decl        data_types();
+-
+-        /* Callbacks/Hooks which should probably be in the front-end: */
+-        chunk       Ethernet::adapter_init_context(Ethernet::Device,
+-                                                   Builtin::number,
+-                                                   Builtin::symbol);
+-        chunk       Ethernet::adapter_reset(Ethernet::Device);
+-        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
+-    }
+-
+     provided type   RxDescriptor
+     {
+         chunk       LKM::includes();
+@@ -35,6 +22,32 @@
+     {
+         decl        data_types();
+         method      init();
++
++        /* XXX: Callback that should be in the front-end: */
++        chunk       Ethernet::adapter_init_rx(Ethernet::Device);
++
++        attribute   DMA::DMAHandle.scalar   dma_base;
++        attribute   Builtin::number.scalar  size;
++    }
++
++    provided type   Context
++    {
++        chunk       Ethernet::HardwareContext();
++        decl        data_types();
++
++        /* XXX:
++         * These callbacks/Hooks which should probably be in the front-end.
++         * Also, I'm not too happy about the names, it's difficult to make
++         * the difference between the probe and open parts.
++         */
++        chunk       Ethernet::adapter_init_context(Ethernet::Device,
++                                                   Builtin::number,
++                                                   Builtin::symbol);
++        chunk       Ethernet::adapter_reset(Ethernet::Device);
++        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
++        chunk       Ethernet::adapter_setup(Ethernet::Device);
++
++        attribute   RxRing.scalar   rx_ring;
+     }
+ 
+     provided type   TxRing
+@@ -44,6 +57,9 @@
+         decl        data_types();
+         method      init();
+ 
++        /* XXX: Callback that should be in the front-end: */
++        chunk       Ethernet::adapter_init_tx(Ethernet::Device);
++
+         /* Clean the ring (i.e: move the head closer to the tail): */
+         method      clean();
+         /* Return the number of clean descriptors left in the ring: */
+diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt
+--- a/rathaxes/samples/e1000/ethernet.blt
++++ b/rathaxes/samples/e1000/ethernet.blt
+@@ -170,6 +170,9 @@
+                     ${Log::info("Cannot register the interrupt handler")};
+                     return error;
+                 }
++                ${pointcut Ethernet::adapter_setup(local.rtx_ether_ctx)};
++                ${pointcut Ethernet::adapter_init_rx(local.rtx_ether_ctx)};
++                ${pointcut Ethernet::adapter_init_tx(local.rtx_ether_ctx)};
+                 ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)};
+ 
+                 return 0;
+diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti
+--- a/rathaxes/samples/e1000/ethernet.rti
++++ b/rathaxes/samples/e1000/ethernet.rti
+@@ -52,6 +52,15 @@
+         provided chunk  LKM::includes();
+         provided chunk  LKM::prototypes();
+         provided chunk  LKM::code();
++
++        /*
++         * For e1000, this part is documented in the Intel Gigabit Ethernet
++         * Controller Software Developper manual. (You can find it in the
++         * doc/hardware directory).
++         */
++        provided pointcut   Ethernet::adapter_setup(Ethernet::Device);
++        provided pointcut   Ethernet::adapter_init_rx(Ethernet::Device);
++        provided pointcut   Ethernet::adapter_init_tx(Ethernet::Device);
+     }
+ 
+     required sequence   send(Ethernet::Device, Socket::AbstractSKBuff)
+diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx
+--- a/rathaxes/samples/e1000/lkm.rtx
++++ b/rathaxes/samples/e1000/lkm.rtx
+@@ -4,10 +4,6 @@
+     {
+         Log::info("opening the device");
+ 
+-
+-        e1000::set_up_device(dev);
+-        Log::info("device activated");
+-
+         e1000::activate_device_interruption(dev);
+         Log::info("interruption enabled");
+ 
+diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti
+--- a/rathaxes/samples/e1000/socket.rti
++++ b/rathaxes/samples/e1000/socket.rti
+@@ -15,6 +15,10 @@
+         decl    data_types();
+         method  init(Socket::AbstractSKBuff);
+         method  dump_infos();
++        /*
++         * map_to and map_from return a non-zero value on failure (which
++         * doesn't correspond to an errno value):
++         */
+         method  map_to(Device::AbstractDevice);
+         method  map_from(Device::AbstractDevice);
+         method  unmap_to_and_free(Device::AbstractDevice);