diff rathaxes_sample_e1000_rewrite_device_dependent_code.patch @ 131:c209851a82de

Wip, start a rewrite of the e1000 device dependent code
author Louis Opter <kalessin@kalessin.fr>
date Fri, 03 Jan 2014 15:01:47 +0100
parents
children f2e4dd91dc6f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rathaxes_sample_e1000_rewrite_device_dependent_code.patch	Fri Jan 03 15:01:47 2014 +0100
@@ -0,0 +1,1252 @@
+# HG changeset patch
+# Parent 7d00455945ec97c5851ac0d735da7c3cfbd8e39c
+rathaxes: rewrite/refactor all the e1000 device dependent code
+
+diff --git a/notes.txt b/notes.txt
+new file mode 100644
+--- /dev/null
++++ b/notes.txt
+@@ -0,0 +1,9 @@
++- Too much changes to not start over;
++- Lack of methods is extremely annoying and requires a lot of workarounds (e.g:
++  see the register read/write/set/unset methods on e1000::Context);
++- I'm using a pointcut inside the ethernet context "decl data_types" to inject
++  my hardware context; it's impossible to get it back without hardcoding stuff,
++  because the ethernet subsystem isn't aware of the type of the field (so I
++  can't write an attribute). Being able to just inject a type (instead of a
++  whole structure field) might not be the best solution but would solve this
++  issue/use case.
+diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt
+--- a/rathaxes/samples/e1000/CMakeLists.txt
++++ b/rathaxes/samples/e1000/CMakeLists.txt
+@@ -9,7 +9,6 @@
+                      pci.rti
+                      socket.rti
+                      ethernet.rti
+-                     e1000.rti
+                      BLT
+                      log.blt
+                      lkm.blt
+@@ -17,9 +16,8 @@
+                      dma.blt
+                      pci.blt
+                      socket.blt
+-                     e1000.blt
+                      ethernet.blt)
+ 
+-IF (LINUX_KBUILD_DIR)
+-    ADD_RATHAXES_LKM(e1000 e1000_src)
+-ENDIF (LINUX_KBUILD_DIR)
++#IF (LINUX_KBUILD_DIR)
++#    ADD_RATHAXES_LKM(e1000 e1000_src)
++#ENDIF (LINUX_KBUILD_DIR)
+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
+@@ -170,14 +170,15 @@
+                 for (i = 0; i != ${config.rx_ring_size}; ++i)
+                 {
+                     ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i];
+-                    // XXX #46: ${rtx_ether_ctx.init_rx_skbuff(local.skbuff, config.rx_buffer_len)};
+-                    if (rtx_ethernet_init_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len}))
++                    // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)};
++                    if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len}))
+                     {
+                         ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")};
+                         goto err_skbuffs_alloc;
+                     }
+-                    // 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))
++                    /* XXX: recuperer le dma handle et le placer correctement dans le descripteur. */
++                    ${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)}
++                    if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)})
+                     {
+                         ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")};
+                         goto err_skbuffs_map;
+diff --git a/rathaxes/samples/e1000/e1000ng.blt b/rathaxes/samples/e1000/e1000ng.blt
+new file mode 100755
+--- /dev/null
++++ b/rathaxes/samples/e1000/e1000ng.blt
+@@ -0,0 +1,717 @@
++with e1000ng, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin
++{
++    template type e1000::Register()
++    {
++        decl data_types()
++        {
++            E1000_CTRL          = 0x00000, /* Device Control - RW */
++            E1000_CTRL_DUP      = 0x00004, /* Device Control Duplicate (Shadow) - RW */
++            E1000_STATUS        = 0x00008, /* Device Status - RO */
++            E1000_EEPROM_FLASH  = 0x00010, /* EEPROM/Flash Control - RW */
++            E1000_EEPROM_READ   = 0x00014, /* EEPROM Read - RW */
++            E1000_CTRL_EXT      = 0x00018, /* Extended Device Control - RW */
++            E1000_FLA           = 0x0001C, /* Flash Access - RW */
++            E1000_MDIC          = 0x00020, /* MDI Control - RW */
++            E1000_IMS           = 0x000D0, /* Interrupt Mask Set */
++            E1000_IMC           = 0x000D8, /* Interrupt Mask Clear */
++            E1000_ICR           = 0x000C0, /* Interrupt Cause Read - R/clr */
++            E1000_FCAL          = 0x00028, /* Flow Control Address Low */
++            E1000_FCAH          = 0x0002c, /* Flow Control Address High */
++            E1000_FCT           = 0x00030, /* Flow Control Type */
++            E1000_RCTL          = 0x00100, /* Receive Control */
++            E1000_FCTTV         = 0x00170, /* Flow Control Transmit Timer Value */
++            E1000_TCTL          = 0x00400, /* Transmit Control */
++            E1000_CRCERRS       = 0x04000, /* CRC Error Count (base address of the statistic register spaces) */
++            E1000_RAL           = 0x05400, /* Receive Address Low */
++            E1000_RAH           = 0x05404, /* Receive Address High */
++            E1000_MTA           = 0x05200, /* Multicast Table Array */
++            E1000_RDBAL         = 0x02800, /* Receive Descriptor Base Address (Low 32 bits) */
++            E1000_RDBAH         = 0x02804, /* Receive Descriptor Base Address (High 32 bits) */
++            E1000_RDLEN         = 0x02808, /* Receive Descriptor Length */
++            E1000_RDH           = 0x02810, /* Receive Descriptor Head */
++            E1000_RDT           = 0x02818, /* Receive Descriptor Tail */
++            E1000_TDBAL         = 0x03800, /* Transmit Descriptor Base Address (Low 32 bits) */
++            E1000_TDBAH         = 0x03804, /* Transmit Descriptor Base Address (High 33 bits) */
++            E1000_TDLEN         = 0x03808, /* Transmit Descriptor Length */
++            E1000_TDH           = 0x03810, /* Transmit Descriptor Head */
++            E1000_TDT           = 0x03818, /* Transmit Descriptor Tail */
++        }
++
++        map
++        {
++        }
++    }
++
++    template type e1000::Commands()
++    {
++        decl data_types()
++        {
++            E1000_CMD_FD                    = 0x00000001, /* Full duplex.0=half; 1=full */
++            E1000_CMD_BEM                   = 0x00000002, /* Endian Mode.0=little,1=big */
++            E1000_CMD_PRIOR                 = 0x00000004, /* Priority on PCI. 0=rx,1=fair */
++            E1000_CMD_GIO_MASTER_DISABLE    = 0x00000004, /* Blocks new Master requests */
++            E1000_CMD_LRST                  = 0x00000008, /* Link reset. 0=normal,1=reset */
++            E1000_CMD_TME                   = 0x00000010, /* Test mode. 0=normal,1=test */
++            E1000_CMD_SLE                   = 0x00000020, /* Serial Link on 0=dis,1=en */
++            E1000_CMD_ASDE                  = 0x00000020, /* Auto-speed detect enable */
++            E1000_CMD_SLU                   = 0x00000040, /* Set link up (Force Link) */
++            E1000_CMD_ILOS                  = 0x00000080, /* Invert Loss-Of Signal */
++            E1000_CMD_SPD_SEL               = 0x00000300, /* Speed Select Mask */
++            E1000_CMD_SPD_10                = 0x00000000, /* Force 10Mb */
++            E1000_CMD_SPD_100               = 0x00000100, /* Force 100Mb */
++            E1000_CMD_SPD_1000              = 0x00000200, /* Force 1Gb */
++            E1000_CMD_BEM32                 = 0x00000400, /* Big Endian 32 mode */
++            E1000_CMD_FRCSPD                = 0x00000800, /* Force Speed */
++            E1000_CMD_FRCDPX                = 0x00001000, /* Force Duplex */
++            E1000_CMD_D_UD_EN               = 0x00002000, /* Dock/Undock enable */
++            E1000_CMD_D_UD_POLARITY         = 0x00004000, /* Defined polarity of Dock/Undock indication in SDP[0] */
++            E1000_CMD_FORCE_PHY_RESET       = 0x00008000, /* Reset both PHY ports, through PHYRST_N pin */
++            E1000_CMD_EXT_LINK_EN           = 0x00010000, /* enable link status from external LINK_0 and LINK_1 pins */
++            E1000_CMD_SWDPIN0               = 0x00040000, /* SWDPIN 0 value */
++            E1000_CMD_SWDPIN1               = 0x00080000, /* SWDPIN 1 value */
++            E1000_CMD_SWDPIN2               = 0x00100000, /* SWDPIN 2 value */
++            E1000_CMD_SWDPIN3               = 0x00200000, /* SWDPIN 3 value */
++            E1000_CMD_SWDPIO0               = 0x00400000, /* SWDPIN 0 Input or output */
++            E1000_CMD_SWDPIO1               = 0x00800000, /* SWDPIN 1 input or output */
++            E1000_CMD_SWDPIO2               = 0x01000000, /* SWDPIN 2 input or output */
++            E1000_CMD_SWDPIO3               = 0x02000000, /* SWDPIN 3 input or output */
++            E1000_CMD_RST                   = 0x04000000, /* Global reset */
++            E1000_CMD_RFCE                  = 0x08000000, /* Receive Flow Control enable */
++            E1000_CMD_TFCE                  = 0x10000000, /* Transmit flow control enable */
++            E1000_CMD_RTE                   = 0x20000000, /* Routing tag enable */
++            E1000_CMD_VME                   = 0x40000000, /* IEEE VLAN mode enable */
++            E1000_CMD_PHY_RST               = 0x80000000, /* PHY Reset */
++            E1000_CMD_SW2FW_INT             = 0x02000000, /* Initiate an interrupt to manageability engine */
++            E1000_INTR_TXDW                 = 0x00000001, /* Transmit desc written back */
++            E1000_INTR_TXQE                 = 0x00000002, /* Transmit Queue empty */
++            E1000_INTR_LSC                  = 0x00000004, /* Link Status Change */
++            E1000_INTR_RXSEQ                = 0x00000008, /* rx sequence error */
++            E1000_INTR_RXDMT0               = 0x00000010, /* rx desc min. threshold (0) */
++            E1000_INTR_RXO                  = 0x00000040, /* rx overrun */
++            E1000_INTR_RXT0                 = 0x00000080, /* rx timer intr (ring 0) */
++            E1000_INTR_MDAC                 = 0x00000200, /* MDIO access complete */
++            E1000_RAH_AV                    = (1 << 31),  /* Set the MAC Address as Valid */
++            E1000_RCTL_EN                   = (1 << 1),   /* Receiver Enable */
++            E1000_RCTL_BSEX                 = (1 << 25),  /* Buffer Size Extension */
++            E1000_RCTL_BSIZE_256            = ((1 << 16) | (1 << 17)),
++            E1000_RCTL_BSIZE_512            = (1 << 17),
++            E1000_RCTL_BSIZE_1024           = (1 << 16),
++            E1000_RCTL_BSIZE_2048           = 0,
++            E1000_RCTL_BSIZE_4096           = (E1000_RCTL_BSEX | (1 << 16) | (1 << 17)),
++            E1000_RCTL_BSIZE_8192           = (E1000_RCTL_BSEX | (1 << 17)),
++            E1000_RCTL_BSIZE_16384          = (E1000_RCTL_BSEX | (1 << 16)),
++            E1000_TCTL_EN                   = (1 << 1),   /* Transmitter Enable */
++            E1000_TCTL_PSP                  = (1 << 3),   /* Pad Short Packet */
++        }
++
++        map
++        {
++        }
++    }
++
++    template type e1000::TxDescriptorFlag()
++    {
++        decl data_types()
++        {
++            E1000_TXD_DTYP_D        = 0x00100000, /* Data Descriptor */
++            E1000_TXD_DTYP_C        = 0x00000000, /* Context Descriptor */
++            E1000_TXD_POPTS_IXSM    = 0x01,       /* Insert IP checksum */
++            E1000_TXD_POPTS_TXSM    = 0x02,       /* Insert TCP/UDP checksum */
++            E1000_TXD_CMD_EOP       = 0x01000000, /* End of Packet */
++            E1000_TXD_CMD_IFCS      = 0x02000000, /* Insert FCS (Ethernet CRC) */
++            E1000_TXD_CMD_IC        = 0x04000000, /* Insert Checksum */
++            E1000_TXD_CMD_RS        = 0x08000000, /* Report Status */
++            E1000_TXD_CMD_RPS       = 0x10000000, /* Report Packet Sent */
++            E1000_TXD_CMD_DEXT      = 0x20000000, /* Descriptor extension (0 = legacy) */
++            E1000_TXD_CMD_VLE       = 0x40000000, /* Add VLAN tag */
++            E1000_TXD_CMD_IDE       = 0x80000000, /* Enable Tidv register */
++            E1000_TXD_STAT_DD       = 0x00000001, /* Descriptor Done */
++            E1000_TXD_STAT_EC       = 0x00000002, /* Excess Collisions */
++            E1000_TXD_STAT_LC       = 0x00000004, /* Late Collisions */
++            E1000_TXD_STAT_TU       = 0x00000008, /* Transmit underrun */
++            E1000_TXD_CMD_TCP       = 0x01000000, /* TCP packet */
++            E1000_TXD_CMD_IP        = 0x02000000, /* IP packet */
++            E1000_TXD_CMD_TSE       = 0x04000000, /* TCP Seg enable */
++            E1000_TXD_STAT_TC       = 0x00000004, /* Tx Underrun */
++        }
++
++        map
++        {
++        }
++    }
++
++    template type e1000::RxDescriptor()
++    {
++        decl data_types()
++        {
++            __le64          buff_addr;
++            __le16          length;
++            __le16          csum;
++            unsigned char   status;
++            unsigned char   errors;
++            __le16          special;
++        }
++
++        map
++        {
++        }
++    }
++
++    // This is a generic tx descriptor for the e1000. When you use TCP
++    // Segmentation Offload (TSO) the hardware actually uses two types of
++    // tx descriptors in its tx ring:
++    // - context descriptors: this descriptor doesn't actually point to data to
++    //   send but initialize the offloading engine for the data descriptor that
++    //   follow;
++    // - data descriptors: this descriptor points to data from the skbuffs.
++    template type e1000::TxDescriptor()
++    {
++        decl data_types()
++        {
++            __le64                  buff_addr;
++            union {
++                __le32              data;
++                struct {
++                    __le16          length;
++                    unsigned char   csum_offset; /* CSO */
++                    unsigned char   cmd;
++                }                   fields;
++            }                       lower;
++            union {
++                __le32              data;
++                struct {
++                    unsigned char   status;
++                    unsigned char   csum_start; /* CSS */
++                    __le16          special;
++                }                   fields;
++            }                       upper;
++        }
++
++        map
++        {
++        }
++    }
++
++    template type e1000::Buffer()
++    {
++        decl data_types()
++        {
++            ${Socket::SKBuff}   sk_buff;
++            ${DMA::DMAHandle}   dma;
++        }
++
++        method init(Socket::SKBuff sk_buff, DMA::DMAHandle dma)
++        {
++            ${self.sk_buff} = ${sk_buff};
++            ${self.dma} = ${dma};
++        }
++
++        map
++        {
++            sk_buff: ${self}->sk_buff;
++            dma: ${self}->dma;
++        }
++    }
++
++    template type e1000::MMIO
++    {
++        decl data_types()
++        {
++            unsigned char   *io;
++        }
++
++        // XXX: we'll need those functions until we get working methods (#46):
++
++        chunk LKM::prototypes()
++        {
++            static unsigned int rtx_e1000_reg_read32(${e1000::MMIO}, ${e1000::Register});
++            static void         rtx_e1000_reg_write32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number});
++            static void         rtx_e1000_reg_set32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number});
++            static void         rtx_e1000_reg_unset32(${e1000:::MMIO}, ${e1000::Register}, ${Builtin::number});
++        }
++
++        chunk LKM::code()
++        {
++            static unsigned int rtx_e1000_reg_read32(${e1000::MMIO} io, ${e1000::Register} reg)
++            {
++                return ioread32(${local.io.io} + reg);
++            }
++
++            static void         rtx_e1000_reg_write32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value)
++            {
++                return iowrite32(value, ${local.io.io} + reg);
++            }
++
++            static void         rtx_e1000_reg_set32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value)
++            {
++                return iowrite32(rtx_e1000_reg_read32(io, reg) | value, ${local.io.io} + reg);
++            }
++
++            static void         rtx_e1000_reg_unset32(${e1000:::MMIO} io, ${e1000::Register} reg, ${Builtin::number} value)
++            {
++                return iowrite32(rtx_e1000_reg_read32(io, reg) & ~value, ${local.io.io} + reg);
++            }
++        }
++
++        method init(Builtin::symbol io)
++        {
++            ${self.io} = ${io};
++        }
++
++        method read32(${e1000::Register} reg)
++        {
++            ioread32(${self.io} + ${local.reg});
++        }
++
++        method write32(${e1000::Register} reg, ${Builtin::number} value)
++        {
++            iowrite32(${local.value}, ${self.io} + ${local.reg});
++        }
++
++        method set32(${e1000::Register} reg, ${Builtin::number} value)
++        {
++            iowrite32(ioread32(${self.io} + ${local.reg}) | value, ${self.io} + ${local.reg});
++        }
++
++        method unset32(${e1000::Register} reg, ${Builtin::number} value)
++        {
++            iowrite32(ioread32(${self.io} + ${local.reg}) & ~value, ${self.io} + ${local.reg});
++        }
++
++        map
++        {
++            io: ((unsigned char *)(${self}));
++        }
++    }
++
++    template type e1000::Ring()
++    {
++        decl data_types()
++        {
++            ${e1000::MMIO}          io;
++            ${DMA::DMAHandle}       dma;
++            ${Builtin::symbol.ref}  descs;
++            ${Builtin::number}      size;
++            ${e1000::Buffer.ref}    buffs;
++        }
++
++        chunk LKM::prototypes()
++        {
++            static void rtx_e1000_ring_init(${e1000::Ring.ref}, ${e1000::MMIO},
++                                            ${Builtin::number}, ${Builtin::number});
++        }
++
++        chunk LKM::code()
++        {
++            static void rtx_e1000_ring_init(${e1000::Ring.ref} self,
++                                            ${e1000::MMIO} io,
++                                            ${Builtin::number} desc_count,
++                                            ${Builtin::number} desc_size)
++            {
++                memset(self, 0, sizeof(*self));
++                self->size = ALIGN(desc_count * desc_size, 4096);
++                self->io = io;
++            }
++        }
++
++        method init(e1000::MMIO io, Builtin::number desc_count, Builtin::number desc_size)
++        {
++            rtx_e1000_ring_init(&${self}, ${io}, ${desc_count}, ${desc_size});
++        }
++    }
++
++    template type e1000::RxRing()
++    {
++        decl data_types()
++        {
++            ${e1000::Ring}  ring;
++        }
++
++        chunk LKM::prototypes()
++        {
++            static int  rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref});
++        }
++
++        chunk LKM::code()
++        {
++            static int  rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref} self)
++            {
++                return 0;
++            }
++        }
++
++        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,
++                    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)
++                {
++                    ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[i];
++                    // XXX #46: ${rtx_ether_ctx.alloc_rx_skbuff(local.skbuff, config.rx_buffer_len)};
++                    if (rtx_ethernet_alloc_rx_skbuff(${local.skbuff}, ${config.rx_buffer_len}))
++                    {
++                        ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")};
++                        goto err_skbuffs_alloc;
++                    }
++                    /* XXX: recuperer le dma handle et le placer correctement dans le descripteur. */
++                    ${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, RTX_DMA_FROM_DEVICE)}
++                    if (${DMA::map(local.rtx_ether_ctx.device, local.skbuff.data, local.skbuff.len, 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};
++                pr_info("rtx_e1k: adapter_init_rx: skbuffs allocated, headlen=%d", skb_headlen((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i - 1].skbuff));
++
++                /* 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. */
++            }
++        }
++
++        method init(e1000::MMIO io, Builtin::number desc_count)
++        {
++            ${self.ring.init(local.io, local.desc_count, self.desc_size)};
++        }
++
++        method alloc()
++        {
++            rtx_e1000_alloc_rx_ressources(${self});
++        }
++
++        map
++        {
++            descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs
++            desc_size: sizeof(/* XXX ${e1000::RxDescriptor} */int);
++        }
++    }
++
++    template type e1000::TxRing()
++    {
++        decl data_types()
++        {
++            ${e1000::Ring}  ring;
++        }
++
++        chunk LKM::prototypes()
++        {
++            static int  rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref});
++        }
++
++        chunk LKM::code()
++        {
++            static int  rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref} self)
++            {
++                return 0;
++            }
++        }
++
++        method init(e1000::MMIO io, Builtin::number desc_count)
++        {
++            ${self.ring.init(local.io, local.desc_count, self.desc_size)};
++        }
++
++        method alloc()
++        {
++            rtx_e1000_alloc_tx_ressources(${self});
++        }
++
++        map
++        {
++            descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs
++            desc_size: sizeof(/* XXX ${e1000::TxDescriptor} */int);
++        }
++    }
++
++    template type e1000::Context()
++    {
++        decl data_types()
++        {
++            ${e1000::MMIO}      io;
++            ${e1000::TxRing}    tx_ring;
++            ${e1000::RxRing}    rx_ring;
++        }
++
++        chunk LKM::includes()
++        {
++            #include <linux/types.h>
++        }
++
++        chunk LKM::prototypes()
++        {
++            static void rtx_e1000_print_status(${e1000::Context.ref});
++        }
++
++        chunk LKM::code()
++        {
++            static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx)
++            {
++                unsigned int status = rtx_e1000_reg_read32(hw_ctx, E1000_STATUS);
++                ${Log::info("card status:")};
++                // XXX We can't use Log::info below because it just accept a
++                // string (as opposed to a format string with its parameters):
++                pr_info("\tRegister value: 0x%x\n", status);
++                pr_info("\tMode: %s\n", (status & 1) ? "Full": "Half");
++                pr_info("\tLink: %s\n", (status & 2) ? "Up" : "Down");
++                pr_info("\tTransmission: %s\n", (status & 4) ? "Paused" : "Ok");
++                pr_info("\tInterface: %s\n", (status & 3) == 3 ? "Up" : "Down");
++            }
++        }
++
++        chunk Ethernet::HardwareContext()
++        {
++            ${e1000::Context}   hw_ctx;
++        }
++
++        chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol ioaddr)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                ${local.hw_ctx.io.init(local.ioaddr)};
++                ${local.hw_ctx.rx_ring.init(local.hw_ctx.io, config.rx_ring_size)};
++                ${local.hw_ctx.tx_ring.init(local.hw_ctx.io, config.tx_ring_size)};
++            }
++        }
++
++        chunk Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                // XXX #46: ${local.hw_ctx.io.write32(E1000_CTRL, E1000_CMD_RST)};
++                rtx_e1000_reg_write32(hw_ctx, E1000_CTRL, E1000_CMD_RST);
++                udelay(10); // TODO: abstract this too...
++                ${Log::info("adapter has been reset")};
++            }
++        }
++
++        chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                // Shamelessly borrowed from Minix
++                for (int i = 0; i < 3; ++i) {
++                    rtx_e1000_reg_write32(hw_ctx, E1000_EEPROM_READ, (i << 8) | 1);
++                    int value;
++                    do {
++                        value = rtx_e1000_reg_read32(hw_ctx, E1000_EEPROM_READ);
++                    } while ((value & (1 << 4)) == 0);
++                    value >>= 16;
++                    // NOTE: I'm not sure if Ethernet::Device should be
++                    // accessed directly here. But since we need to take it in
++                    // parameter (so we can get back our e1000::Context) it
++                    // seems inadequate to set this in another way:
++                    ${local.rtx_ether_ctx.dev_addr}[i * 2] = value & 0xff;
++                    ${local.rtx_ether_ctx.dev_addr}[i * 2 + 1] = (value >> 8) & 0xff;
++                }
++
++                ${Log::info("mac address loaded from the EEPROM")};
++            }
++        }
++
++        chunk Ethernet::adapter_setup_rx_tx(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.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.
++                //
++                // XXX #46: Use the read/write/set/unset methods on Context
++                rtx_e1000_reg_set32(hw_ctx, E1000_CTRL, E1000_CMD_ASDE|E1000_CMD_SLU);
++                rtx_e1000_reg_unset32(
++                    hw_ctx,
++                    E1000_CTRL,
++                    E1000_CMD_LRST|E1000_CMD_FRCSPD|E1000_CMD_PHY_RST|
++                    E1000_CMD_ILOS|E1000_CMD_VME
++                );
++                rtx_e1000_reg_write32(hw_ctx, E1000_FCAH, 0);
++                rtx_e1000_reg_write32(hw_ctx, E1000_FCAL, 0);
++                rtx_e1000_reg_write32(hw_ctx, E1000_FCT, 0);
++                rtx_e1000_reg_write32(hw_ctx, E1000_FCTTV, 0);
++                for (int i = 0; i != 64; ++i)
++                    rtx_e1000_reg_write32(hw_ctx, E1000_CRCERRS + i * 4, 0);
++
++                ${Log::info("adapter_setup: general configuration done")};
++            }
++        }
++
++        chunk Ethernet::adapter_enable_interrupts(Ethernet::Device)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                rtx_e1000_reg_write32(
++                    hw_ctx,
++                    E1000_IMS,
++                    E1000_INTR_TXDW|E1000_INTR_TXQE|E1000_INTR_LSC|
++                    E1000_INTR_RXO|E1000_INTR_RXT0
++                );
++
++                // XXX We should probably move that elsewhere (it just used to
++                // be done right after we enabled interrupts when this was
++                // still in lkm.rtx):
++                ${local.hw_ctx.print_status()};
++            }
++        }
++
++        chunk Ethernet::handle_interrupt(Ethernet::Device rtx_ether_ctx)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                unsigned int icr = rtx_e1000_reg_read32(hw_ctx, E1000_ICR);
++                pr_info("%s: interrupt received, ICR: 0x%x", ${config.name}, icr);
++                if (icr) {
++                    if (icr & E1000_INTR_LSC) {
++                        ${Log::info("handle_interrupt: cable link status changed, dumping card status:")};
++                        ${local.hw_ctx.print_status()};
++                    }
++                    if (icr & (E1000_INTR_TXQE|E1000_INTR_TXDW)) {
++                        ${Log::info("handle_interrupt: TxRing: packet(s) sent")};
++                    }
++                    if (icr & E1000_INTR_RXT0) {
++                        ${Log::info("handle_interrupt: RxRing: packet(s) received")};
++                    }
++                    if (icr & E1000_INTR_RXO) {
++                        ${Log::info("handle_interrupt: RxRing: overrun")};
++                    }
++
++                    // XXX: This sucks since we don't know the pointcut context:
++                    return IRQ_HANDLED;
++                }
++            }
++        }
++
++        method print_status()
++        {
++            rtx_e1000_print_status(${self});
++        }
++
++        map
++        {
++            io: ${self}->io;
++            rx_ring: ${self}->rx_ring;
++            tx_ring: ${self}->tx_ring;
++        }
++    }
++}
+diff --git a/rathaxes/samples/e1000/e1000ng.rti b/rathaxes/samples/e1000/e1000ng.rti
+new file mode 100755
+--- /dev/null
++++ b/rathaxes/samples/e1000/e1000ng.rti
+@@ -0,0 +1,122 @@
++interface e1000ng : 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;
++
++    // Hardware values/data structures, should probably be in the front-end:
++    provided type   Register            { decl data_types(); }
++    provided type   Command             { decl data_types(); }
++    provided type   TxDescriptorFlag    { decl data_types(); }
++    provided type   RxDescriptor        { decl data_types(); }
++    provided type   TxDescriptor        { decl data_types(); }
++
++    provided type   Buffer
++    {
++        decl        data_types();
++
++        method      init(Socket::SKBuff, DMA::DMAHandle);
++
++        attribute   Socket::SKBuff.ref  sk_buff;
++        attribute   DMA::DMAHandle.ref  dma;
++    }
++
++    // I wish we could just leave those methods in the Context type but we also
++    // need them from the rings and that would mean a circular dependency
++    // between the context and the rings and Rathaxes can't handle it.
++    provided type   MMIO
++    {
++        decl        data_types();
++
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
++        method      init(Builtin::symbol);
++        method      read32(Register);
++        method      write32(Register, Builtin::number);
++        method      set32(Register, Builtin::number);
++        method      unset32(Register, Builtin::number);
++
++        attribute   Builtin::symbol io;
++    }
++
++    provided type   Ring
++    {
++        decl        data_types();
++
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
++        method      init(MMIO, Builtin::number, Builtin::number);
++
++        attribute   MMIO                io;
++        attribute   DMA:DMAHandle       dma;
++        attribute   Builtin::number     size;   // Total size in bytes
++        attribute   Builtin::symbol.ref descs;
++        attribute   Buffer.ref          buffs;
++    }
++
++    provided type   RxRing
++    {
++        decl        data_types();
++
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
++        method      init(MMIO, Builtin::number);
++        method      alloc(); // Returns != 0 on failure
++
++        attribute   RxDescriptor    descs;
++    }
++
++    provided type   TxRing
++    {
++        decl        data_types();
++
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
++        method      init(MMIO, Builtin::number);
++        method      alloc(); // Returns != 0 on failure
++
++        attribute   TxDescriptor    descs;
++    }
++
++    provided type   Context
++    {
++        decl        data_types();
++
++        chunk       LKM::includes();
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++        chunk       Ethernet::HardwareContext();
++
++        // NOTE: Those callbacks/hooks should probably be in the front-end:
++
++        // Init the hardware context structure, doesn't allocate anything.
++        chunk       Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol);
++
++        // Reset the adapter
++        chunk       Ethernet::adapter_reset(Ethernet::Device);
++
++        // Load the MAC address from the EEPROM and save it into the
++        // dev_addr field/attribute of Ethernet::Device.
++        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
++
++        // Prepare the device and the resources for rx/tx.
++        chunk       Ethernet::adapter_setup_rx_tx(Ethernet::Device);
++
++        // Enable interrupts.
++        chunk       Ethernet::adapter_enable_interrupts(Ethernet::Device);
++
++        // Interrupt handler.
++        chunk       Ethernet::handle_interrupt(Ethernet::Device);
++
++        method      print_status();
++
++        attribute   MMIO            io;
++        attribute   RxRing.scalar   rx_ring;
++        attribute   TxRing.scalar   tx_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
+@@ -106,7 +106,7 @@
+             {
+                 ${Socket::AbstractSKBuff} k_sk_buff = netdev_alloc_skb(${local.self.net_device.k_net_dev}, ${local.size});
+                 if (${local.k_sk_buff) {
+-                    ${local.sk_buff.init(local.k_sk_buff, local.size)};
++                    ${local.sk_buff.init(local.k_sk_buff)};
+                     return 0;
+                 }
+                 return 1;
+@@ -164,34 +164,30 @@
+         {
+             static int  rtx_ethernet_open(struct net_device *dev)
+             {
+-                /*
+-                 * XXX The casts are here because the compiler doesn't resolve
+-                 * "enclosed" type (e.g: local.var.enclosed) correctly.
+-                 */
+                 ${Ethernet::AbstractDevice.ref} rtx_net_dev;
+                 { /* XXX: I end up with a placeholder if I don't open a scope */
+                     ${local.rtx_net_dev.init(local.dev)};
+                 }
+                 ${Ethernet::Device.ref} rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx};
+ 
+-                int error;
++                ${pointcut Ethernet::adapter_setup_rx_tx(local.rtx_ether_ctx)};
++
+                 {
+-                    ${Log::info("installing the interrupt handler")};
++                    ${Log::info("Installing the interrupt handler")};
+                 }
+-                error = request_irq(${local.rtx_ether_ctx.irq},
+-                                    rtx_ethernet_interrupt_handler,
+-                                    IRQF_SHARED,
+-                                    ${config.name},
+-                                    dev);
+-                if (error)
+-                {
++                int error = request_irq(
++                    ${local.rtx_ether_ctx.irq},
++                    rtx_ethernet_interrupt_handler,
++                    IRQF_SHARED,
++                    ${config.name},
++                    dev
++                );
++                if (error) {
+                     ${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)};
++
++                ${pointcut Ethernet::adapter_enable_interrupts(local.rtx_ether_ctx)};
+ 
+                 return 0;
+             }
+@@ -269,7 +265,7 @@
+                 ${Ethernet::Device.ref} rtx_ether_ctx;
+                 rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx};
+ 
+-                ${pointcut ::IMPLEMENTATION(local.rtx_ether_ctx)};
++                ${pointcut Ethernet::handle_interrupt(local.rtx_ether_ctx)};
+ 
+                 return IRQ_NONE;
+             }
+@@ -342,12 +338,8 @@
+              * XXX: the asssignments/casts are here to circumvent
+              * typing issues in the compiler (see previous XXX).
+              */
+-            int bars = ${rtx_pci_dev.bars};
+             unsigned char /* __iomem */ *ioaddr = ${rtx_pci_dev.ioaddr};
+-            ${cast local.bars as Builtin::number};
+-            ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx,
+-                                                      local.bars,
+-                                                      local.ioaddr)};
++            ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, local.ioaddr)};
+             ${pointcut Ethernet::adapter_reset(local.rtx_ether_ctx)};
+             ${pointcut Ethernet::adapter_load_mac_address(local.rtx_ether_ctx)};
+             memcpy(${local.rtx_ether_ctx.perm_addr},
+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
+@@ -28,8 +28,12 @@
+ 
+     provided type   Device
+     {
++        decl        data_types();
++
+         chunk       LKM::includes();
+-        decl        data_types();
++        chunk       LKM::prototypes();
++        chunk       LKM::code();
++
+         pointcut    Ethernet::HardwareContext();
+ 
+         method      init(Ethernet::AbstractDevice, PCI::AbstractDevice);
+@@ -51,7 +55,7 @@
+         attribute   Builtin::symbol.scalar  irq;
+     }
+ 
+-    required sequence   open(Ethernet::Device)
++    provided sequence   open(Ethernet::Device)
+     {
+         provided chunk  LKM::includes();
+         provided chunk  LKM::prototypes();
+@@ -62,9 +66,8 @@
+          * 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);
++        provided pointcut   Ethernet::adapter_setup_rx_tx(Ethernet::Device);
++        provided pointcut   Ethernet::adapter_enable_interrupts(Ethernet::Device);
+     }
+ 
+     required sequence   send(Ethernet::Device, Socket::AbstractSKBuff)
+@@ -79,10 +82,12 @@
+         provided chunk  LKM::code();
+     }
+ 
+-    required sequence   interrupt_handler(Ethernet::Device)
++    provided sequence   interrupt_handler(Ethernet::Device)
+     {
+         provided chunk  LKM::prototypes();
+         provided chunk  LKM::code();
++
++        provided pointcut   Ethernet::handle_interrupt(Ethernet::Device);
+     }
+ 
+     provided sequence   init()
+@@ -90,9 +95,7 @@
+         provided chunk  LKM::data();
+         provided chunk  PCI::pci_probe_hook(PCI::Device);
+ 
+-        provided pointcut   Ethernet::adapter_init_context(Ethernet::Device,
+-                                                           Builtin::number,
+-                                                           Builtin::symbol);
++        provided pointcut   Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol);
+         provided pointcut   Ethernet::adapter_reset(Ethernet::Device);
+         provided pointcut   Ethernet::adapter_load_mac_address(Ethernet::Device);
+     }
+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
+@@ -1,34 +1,5 @@
+ device LKM use LKM, PCI, Ethernet, Log, Socket
+ {
+-    Ethernet::open(Ethernet::Device dev)
+-    {
+-        Log::info("opening the device");
+-
+-        e1000::activate_device_interruption(dev);
+-        Log::info("interruption enabled");
+-
+-        e1000::print_status(dev);
+-    }
+-
+-    Ethernet::close(Ethernet::Device dev)
+-    {
+-        Log::info("closing the device");
+-
+-        /*
+-         * Note: some calls to release resources must be done when IRQs are
+-         * enabled (dma_free_coherent() for example). So we have to cleanup our
+-         * stuff before free_interrupt_handler().
+-         */
+-        e1000::free_rx_tx(dev);
+-        Log::info("free'ed up rx/tx resources");
+-    }
+-
+-    Ethernet::interrupt_handler(Ethernet::Device dev)
+-    {
+-        Log::info("got an interruption");
+-        e1000::handle_interrupt(dev);
+-    }
+-
+     Ethernet::send(Ethernet::Device dev, Socket::AbstractSKBuff skb)
+     {
+         Log::info("we have one packet to transmit!");
+diff --git a/rathaxes/samples/e1000/socket.blt b/rathaxes/samples/e1000/socket.blt
+--- a/rathaxes/samples/e1000/socket.blt
++++ b/rathaxes/samples/e1000/socket.blt
+@@ -22,16 +22,12 @@
+     {
+         decl  data_types()
+         {
+-            ${Socket::AbstractSKBuff.ref}       skbuff;
+-            ${DMA::AbstractDMAHandle.scalar}    dma_handle;
+-            unsigned int                        size;
++            ${Socket::AbstractSKBuff.ref}   skbuff;
+         }
+ 
+         chunk   LKM::prototypes()
+         {
+             static void rtx_socket_skbuff_dump_infos(${Socket::SKBuff.ref});
+-            static int  rtx_socket_skbuff_map(${Socket::SKBuff.ref}, ${Device::AbstractDevice.ref}, ${DMA::DMADirection.scalar});
+-            static void rtx_socket_skbuff_unmap_and_free(${Socket::SKBuff.ref}, ${Device::AbstractDevice.ref}, ${DMA::DMADirection.scalar});
+         }
+ 
+         chunk   LKM::code()
+@@ -63,85 +59,6 @@
+                         shinfo->nr_frags, shinfo->gso_size, shinfo->gso_segs, shinfo->gso_type
+                 );
+             }
+-
+-            static int rtx_socket_skbuff_map(${Socket::SKBuff.ref} self,
+-                                             ${Device::AbstractDevice.ref} dev,
+-                                             ${DMA::DMADirection.scalar} direction)
+-            {
+-                WARN_ON(!${local.self.sk_buff});
+-                WARN_ON(${local.self.dma_handle});
+-                /*
+-                 * TODO: we don't support skbuffs with paged data yet (see also
+-                 * http://vger.kernel.org/~davem/skb_data.html).
+-                 */
+-                WARN_ON(skb_is_nonlinear(${local.self.sk_buff.k_sk_buff}));
+-
+-                unsigned int len = ${local.self.size};
+-                ${cast local.len as Builtin::number};
+-                ${local.self.dma_handle} = ${DMA::map(local.dev, local.self.sk_buff.k_sk_buff, local.len, local.direction)};
+-                int err = ${DMA::mapping_error(local.dev, local.self.dma_handle)};
+-                if (err)
+-                {
+-                    ${local.self.dma_handle} = 0;
+-                    return err;
+-                }
+-                return 0;
+-            }
+-
+-            static void rtx_socket_skbuff_unmap_and_free(${Socket::SKBuff.ref} self,
+-                                                         ${Device::AbstractDevice.ref} dev,
+-                                                         ${DMA::DMADirection} direction)
+-            {
+-                WARN_ON(!${local.self.sk_buff});
+-                WARN_ON(skb_is_nonlinear(${local.self.sk_buff.k_sk_buff});
+-
+-                if (${local.self.dma_handle})
+-                {
+-                    unsigned int len = ${local.self.size};
+-                    ${cast local.len as Builtin::number};
+-                    ${DMA::unmap(local.dev, local.self.dma_handle, local.len, local.direction)};
+-                    ${local.self.dma_handle} = 0;
+-                }
+-                dev_kfree_skb_any(${local.self.sk_buff.k_sk_buff});
+-                ${local.self.sk_buff} = NULL;
+-            }
+-        }
+-
+-        /*
+-         * XXX: the rathaxes argument kernel_skb is not actually bound to the
+-         * correct C variable from Ethernet::send() (so I named it as the C
+-         * variable I needed)
+-         */
+-        method  init(Socket::AbstractSKBuff kernel_skb, Builtin::number size)
+-        {
+-            ${self.sk_buff} = ${kernel_skb};
+-            ${self.size} = ${size};
+-            ${self.dma_handle} = 0;
+-        }
+-
+-        method  dump_infos()
+-        {
+-            rtx_socket_skbuff_dump_infos(${self});
+-        }
+-
+-        method   map_to(Device::AbstractDevice dev)
+-        {
+-            rtx_socket_skbuff_map(${self}, ${dev}, RTX_DMA_TO_DEVICE);
+-        }
+-
+-        method   map_from(Device::AbstractDevice dev)
+-        {
+-            rtx_socket_skbuff_map(${self}, ${dev}, RTX_DMA_FROM_DEVICE);
+-        }
+-
+-        method   unmap_to_and_free(Device::AbstractDevice dev)
+-        {
+-            rtx_socket_skbuff_unmap_and_free(${self}, ${dev}, RTX_DMA_TO_DEVICE);
+-        }
+-
+-        method   unmap_from_and_free(Device::AbstractDevice dev)
+-        {
+-            rtx_socket_skbuff_unmap_and_free(${self}, ${dev}, RTX_DMA_FROM_DEVICE);
+         }
+ 
+         map
+@@ -151,13 +68,9 @@
+             // management can be abstracted from the user. But this is at least
+             // useful for internal use:
+             sk_buff: (${self})->skbuff;
+-            // XXX: We need to cast here so we can do things like
+-            // var.dma_handle = 0; but the type shouldn't be hardcoded (at the
+-            // same time ${DMA:AbstractDMAHandle} couldn't be used because that
+-            // would yield to a struct type which you can't assign directly;
+-            // but maybe doing the ->data in that case would be acceptable).
+-            dma_handle: (*((dma_addr_t *)&(${self})->dma_handle));
+-            size: (${self})->size;
++
++            data: ((struct sk_buff *)((${self})->sk_buff))->data;
++            len: ((struct sk_buff *)((${self})->sk_buff))->len;
+         }
+     }
+ }
+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
+@@ -12,20 +12,14 @@
+     {
+         chunk   LKM::prototypes();
+         chunk   LKM::code();
++
+         decl    data_types();
+-        method  init(Socket::AbstractSKBuff, Builtin::number);
++
++        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);
+-        method  unmap_from_and_free(Device::AbstractDevice);
+ 
+-        attribute   Socket::AbstractSKBuff.ref      sk_buff;
+-        attribute   DMA::AbstractDMAHandle.scalar   dma_handle;
+-        attribute   Builtin::number.scalar          size;
++        attribute   Socket::AbstractSKBuff.ref  sk_buff;
++        attribute   Builtin::symbol.ref         data;
++        attribute   Builtin::number.scalar      len;
+     }
+ }