view rathaxes_samples_e1000_split_set_up_device.patch @ 129:518d9c8ac70c

Clean-up the patch queue
author Louis Opter <louis@lse.epita.fr>
date Mon, 02 Sep 2013 22:59:30 -0700
parents 52402232483f
children 6359457dce75
line wrap: on
line source

# HG changeset patch
# Parent 2bb3ee06ef16e410c364238ccdccf43a6a2acceb
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
@@ -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,164 @@
         {
         }
 
+        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;
+                    *(dma_addr_t *)&(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},
+                            /* XXX Leaking cast because of the array: */
+                            *((dma_addr_t *)&(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);
         }
     }
 
@@ -195,7 +351,7 @@
                         E1000_TXD_CMD_RS   |
                         skb_headlen(${local.k_skb.k_sk_buff}));
                 tx_desc->upper.data = 0;
-                tx_desc->buff_addr = cpu_to_le64(skb->dma_handle);
+                tx_desc->buff_addr = cpu_to_le64(${local.skb.dma_handle.k_dma_handle});
                 memcpy(&self->skbuffs[self->tail], ${local.k_skb.k_sk_buff}, sizeof(*${local.k_skb.k_sk_buff}));
                 self->tail = (self->tail + 1) % ${config.tx_ring_size};
             }
@@ -208,7 +364,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 +458,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 +519,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 +868,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 */
-                        ${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
@@ -901,15 +891,18 @@
              */
             for (int i = 0; i != ${config.rx_ring_size}; ++i)
             {
+                /*
+                 * XXX Leaking casts:
+                 *
+                 * We should go through the rtx types (Socket::SKBuff,
+                 * AbstractSKBuff), but we can't because of the array here,
+                 * which is not supported by the compiler.
+                 */
                 dma_unmap_single(
                         ${rtx_ether_ctx.device},
-                        (dma_addr_t)hw_ctx_->rx_ring.skbuffs[i].dma_handle,
+                        *((dma_addr_t *)&(hw_ctx_->rx_ring.skbuffs[i].dma_handle)),
                         ${config.rx_buffer_len},
                         DMA_FROM_DEVICE);
-                /* XXX Leaking cast
-                 * (We should go through the rtx types (Socket::SKBuff,
-                 * AbstractSKBuff)
-                 */
                 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,
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);