changeset 133:dbb4a3b383cb

Wip on build
author Louis Opter <kalessin@kalessin.fr>
date Wed, 08 Jan 2014 09:42:33 -0800
parents f2e4dd91dc6f
children 79226bb06e6a
files rathaxes_sample_e1000_rewrite_device_dependent_code.patch
diffstat 1 files changed, 1190 insertions(+), 889 deletions(-) [+]
line wrap: on
line diff
--- a/rathaxes_sample_e1000_rewrite_device_dependent_code.patch	Sun Jan 05 18:21:41 2014 +0100
+++ b/rathaxes_sample_e1000_rewrite_device_dependent_code.patch	Wed Jan 08 09:42:33 2014 -0800
@@ -1,12 +1,12 @@
 # HG changeset patch
-# Parent 7d00455945ec97c5851ac0d735da7c3cfbd8e39c
+# Parent 53d3ca9da9c4cd680cf5982b9e972903fb4d3231
 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,26 @@
+@@ -0,0 +1,40 @@
 +Remarks for David & Lionel:
 +
 +- Too much changes to not start over;
@@ -23,7 +23,14 @@
 +- Lack of support for circular dependencies make some code annoying or
 +  incorrect (circular dependencies between abstract and concrete types via the
 +  attribute or circular dependencies between the rings and the hardware
-+  context).
++  context);
++- It would be really cool to passthrough the comments;
++- Not being able to use a Rathaxes type in the attributes is really annoying
++  and forces me to hardcode a lot of stuff;
++- Pointcuts are scoped by subsystems which is kinda weird because different
++  subsystems are going to share the same pointcuts (i.e: the PCI and USB
++  susystem are going to expose the same pointcuts that can be used by the
++  Ethernet subsystem).
 +
 +Todo/Totry:
 +
@@ -31,11 +38,42 @@
 +  objects in ethernet.bl;
 +- Worry about the code being executed concurrently, e.g: what happens if the
 +  interrupt handler is called right before we disable it in the close path?
++- Why the DMA sequences are taking an AbstractDMAHandle instead of a DMAHandle?
 +
 +Questions:
++
++Compiler bugs:
++
++- Trying to expand a type that doesn't exists crashes the compiler instead of
++  displaying something more useful (took me 15 minutes to figure out that I
++  typed 3 colons instead of 2 in a placeholder).
+diff --git a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
+--- a/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
++++ b/rathaxes/compiler/passes/back/rtxIntrospect.inc.cws
+@@ -890,6 +890,8 @@
+     local to_remove;
+     foreach placeHolder in local_node.body.compile
+     {
++        if (!placeHolder.node.body.type)
++            traceLine(RED + "BUG: placeHolder.node.body.type is missing in rtxIntrospect_walk<\"__rtx_chunk__\">" + DEFAULT_COLOR);
+         if (rtxIntrospect_InferPlaceHolderTypes<placeHolder.node.body.type>(placeHolder.node.body, local_node) == false)
+         {
+             pushItem to_remove;
+diff --git a/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws b/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws
+--- a/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws
++++ b/rathaxes/compiler/passes/back/rtxPlaceHolders.inc.cws
+@@ -394,7 +394,10 @@
+                 { rtxPH_mapPlaceHolder(local_node.expr.id, compile, node_idx, "target_pointcut"); }
+             }
+             else
++            {
++                traceLine(CYAN + "LOUIS: local_node.expr: " + toString(local_node.expr) + DEFAULT_COLOR);
+                 rtxPH_compile<local_node.expr.type>(local_node.expr, compile, node_idx);
++            }
+         }
+         // Label
+         if (existVariable(local_node.label) && rtxPH_havePlaceHolder(local_node.label))
 diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/CMakeLists.txt
 +++ b/rathaxes/samples/e1000/CMakeLists.txt
 @@ -17,9 +17,9 @@
@@ -53,215 +91,40 @@
 +#IF (LINUX_KBUILD_DIR)
 +#    ADD_RATHAXES_LKM(e1000 e1000_src)
 +#ENDIF (LINUX_KBUILD_DIR)
-diff --git a/rathaxes/samples/e1000/dma.blt b/rathaxes/samples/e1000/dma.blt
-old mode 100755
-new mode 100644
-diff --git a/rathaxes/samples/e1000/dma.rti b/rathaxes/samples/e1000/dma.rti
-old mode 100755
-new mode 100644
 diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/e1000.blt
 +++ b/rathaxes/samples/e1000/e1000.blt
-@@ -1,8 +1,148 @@
- with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin
+@@ -1,564 +1,8 @@
+-with e1000, Ethernet, Socket, DMA, PCI, LKM, Log, Builtin
++with e1000, Ethernet, Socket, Device, DMA, PCI, LKM, Log, Builtin
  {
 -    template type   e1000::RxDescriptor()
 +    template type e1000::Register()
      {
 -        decl    data_types()
-+        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;
-@@ -12,13 +152,39 @@
-             __le16          special;
-         }
- 
+-        {
+-            __le64          buff_addr;
+-            __le16          length;
+-            __le16          csum;
+-            unsigned char   status;
+-            unsigned char   errors;
+-            __le16          special;
+-        }
+-
 -        chunk   LKM::includes()
-+        map
-         {
+-        {
 -            #include <linux/types.h>
-         }
-+    }
- 
+-        }
+-
 -        method  init()
-+    // 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
-@@ -26,44 +192,131 @@
-         }
-     }
- 
+-        {
+-        }
+-
+-        map
+-        {
+-        }
+-    }
+-
 -    /*
 -     * This is a generic tx descriptor for the e1000. When you use TCP
 -     * Segmentation Offload (TSO) the hardware actually uses two types of
@@ -272,11 +135,9 @@
 -     * - data descriptors: this descriptor points to data from the skbuffs.
 -     */
 -    template type   e1000::TxDescriptor()
-+    template type e1000::Buffer()
-     {
+-    {
 -        decl    data_types()
-+        decl data_types()
-         {
+-        {
 -            __le64                  buff_addr;
 -            union
 -            {
@@ -298,135 +159,17 @@
 -                    __le16          special;
 -                }                   fields;
 -            }                       upper;
-+            ${Socket::SKBuff}   sk_buff;
-+            ${DMA::DMAHandle}   dma;
-         }
- 
+-        }
+-
 -        method init()
-+        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});
-         }
- 
-         map
-@@ -71,32 +324,27 @@
-         }
-     }
- 
+-        {
+-        }
+-
+-        map
+-        {
+-        }
+-    }
+-
 -    /*
 -     * Ring of e1000::RxDescriptors and their corresponding skbuffs.
 -     *
@@ -439,79 +182,163 @@
 -     *   associated with each descriptor.
 -     */
 -    template type   e1000::RxRing()
-+    template type e1000::RxRing()
-     {
+-    {
 -        decl    data_types()
-+        decl data_types()
-         {
+-        {
 -            unsigned int                    size;
 -            ${e1000::RxDescriptor.ref}      base;
 -            dma_addr_t                      dma_base;
 -            ${Socket::SKBuff}               skbuffs[${config.rx_ring_size}];
-+            ${e1000::Ring}  ring;
-         }
- 
+-        }
+-
 -        method init()
-+        chunk LKM::prototypes()
-         {
-+            static int  rtx_e1000_alloc_rx_ressources(${e1000::RxRing.ref});
-         }
- 
+-        {
+-        }
+-
 -        chunk   Ethernet::adapter_init_rx(Ethernet::Device rtx_ether_ctx)
-+        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;
-@@ -167,18 +415,16 @@
-                  * Allocate the skbuffs, map them for DMA, and write their address
-                  * in the corresponding descriptor.
-                  */
+-        {
+-            {
+-                ${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)
 -                {
-+                for (i = 0; i != ${config.rx_ring_size}; ++i) {
-                     ${Socket::SKBuff.ref} skbuff = &hw_ctx->rx_ring.skbuffs[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;
-                     }
+-                        ${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;
-                     }
-@@ -212,8 +458,7 @@
-                 goto init_rx_ok;
- 
-             err_skbuffs_alloc:
+-                        ${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--)
 -                {
-+                while (i--) {
-                     dma_unmap_single(
-                             ${rtx_ether_ctx.device},
-                             /* XXX Leaking cast because of the array: */
-@@ -238,487 +483,87 @@
-             }
-         }
- 
+-                    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
-+        method init(e1000::MMIO io, Builtin::number desc_count)
-         {
+-        {
 -            size: ((${self}).size);
 -            dma_base: ((${self}).dma_base);
 -        }
@@ -545,12 +372,10 @@
 -            ${Socket::SKBuff}               skbuffs[${config.tx_ring_size}];
 -            unsigned short                  head;
 -            unsigned short                  tail;
-+            ${self.ring.init(local.io, local.desc_count, self.desc_size)};
-         }
- 
+-        }
+-
 -        chunk   LKM::prototypes()
-+        method alloc()
-         {
+-        {
 -            static void         rtx_e1000_tx_ring_clean(${e1000::TxRing.ref});
 -            static unsigned int rtx_e1000_tx_ring_descriptors_remaining(${e1000::TxRing.ref});
 -            static int          rtx_e1000_tx_ring_tso_cksum_offload(${e1000::TxRing.ref}, ${Socket::SKBuff.ref});
@@ -707,70 +532,56 @@
 -
 -        method init()
 -        {
-+            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);
-         }
-     }
- 
+-        }
+-
+-        map
+-        {
+-        }
+-    }
+-
 -    template type   e1000::Context()
-+    template type e1000::TxRing()
-     {
+-    {
 -        decl    data_types()
-+        decl data_types()
-         {
+-        {
 -            int                         bars;
 -            unsigned char /* __iomem */ *ioaddr;
 -            ${e1000::RxRing.scalar}     rx_ring;
 -            ${e1000::TxRing.scalar}     tx_ring;
-+            ${e1000::Ring}  ring;
-         }
- 
+-        }
+-
 -        chunk   Ethernet::HardwareContext()
-+        chunk LKM::prototypes()
-         {
+-        {
 -            /*
 -             * Force the generation of the structure in the "headers" part, we
 -             * have to do this since we do not use the structure in this blt
 -             * (we hacked a bit and used it in ethernet.blt directly).
 -             */
 -            ${e1000::Context}   hw_ctx;
-+            static int  rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref});
-         }
- 
+-        }
+-
 -        chunk   Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx,
 -                                               Builtin::number bars,
 -                                               Builtin::symbol ioaddr)
-+        chunk LKM::code()
-         {
-+            static int  rtx_e1000_alloc_tx_ressources(${e1000::TxRing.ref} self)
-             {
+-        {
+-            {
 -                ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx;
 -                hw_ctx->bars = ${bars};
 -                hw_ctx->ioaddr = ${ioaddr};
-+                return 0;
-             }
-         }
- 
+-            }
+-        }
+-
 -        chunk   Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx)
-+        method init(e1000::MMIO io, Builtin::number desc_count)
-         {
+-        {
 -            {
 -                /* XXX Naming this variable 'hw_ctx' kicks the decl out of the generated code */
 -                ${e1000::Context.ref} tmp_hw_ctx = &${rtx_ether_ctx}->hw_ctx;
 -                rtx_e1000_register_write32(tmp_hw_ctx, E1000_CTRL, E1000_CMD_RST);
 -                udelay(10);
 -            }
-+            ${self.ring.init(local.io, local.desc_count, self.desc_size)};
-         }
- 
+-        }
+-
 -        chunk   Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx)
-+        method alloc()
-         {
+-        {
 -            {
 -                ${e1000::Context.ref} hw_ctx = &${rtx_ether_ctx}->hw_ctx;
 -                /* Shamelessly borrowed from Minix */
@@ -835,183 +646,169 @@
 -
 -                ${Log::info("adapter_setup: general configuration done")};
 -            }
-+            rtx_e1000_alloc_tx_ressources(${self});
+-        }
+-
+-        map
+-        {
+-            rx_ring: ((${self})->rx_ring);
+-            //tx_ring: ((${self})->tx_ring); XXX Circular dep with Context
+-        }
+-    }
+-
+-    template type   e1000::Register()
+-    {
+-        decl    data_types()
++        decl data_types()
+         {
+             E1000_CTRL          = 0x00000, /* Device Control - RW */
+             E1000_CTRL_DUP      = 0x00004, /* Device Control Duplicate (Shadow) - RW */
+@@ -593,19 +37,14 @@
+             E1000_TDT           = 0x03818, /* Transmit Descriptor Tail */
          }
  
+-        method init(Builtin::number value)
+-        {
+-            ${self} = ${value};
+-        }
+-
          map
          {
--            rx_ring: ((${self})->rx_ring);
--            //tx_ring: ((${self})->tx_ring); XXX Circular dep with Context
-+            descs: ((${self})->descs); // TODO: fix cast pour directement avoir les descs
-+            desc_size: sizeof(/* XXX ${e1000::TxDescriptor} */int);
          }
      }
  
--    template type   e1000::Register()
-+    template type e1000::Context()
+-    template type   e1000::Commands()
++    template type e1000::Command()
      {
 -        decl    data_types()
 +        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 */
-+            ${e1000::MMIO}      io;
-+            ${e1000::TxRing}    tx_ring;
-+            ${e1000::RxRing}    rx_ring;
+             E1000_CMD_FD                    = 0x00000001, /* Full duplex.0=half; 1=full */
+             E1000_CMD_BEM                   = 0x00000002, /* Endian Mode.0=little,1=big */
+@@ -670,9 +109,9 @@
          }
- 
--        method init(Builtin::number value)
-+        chunk LKM::includes()
-         {
--            ${self} = ${value};
-+            #include <linux/types.h>
-         }
+     }
  
--        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::TxDescriptorFlags()
--    {
++    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
--        {
--        }
--    }
--
++        decl data_types()
+         {
+             E1000_TXD_DTYP_D        = 0x00100000, /* Data Descriptor */
+             E1000_TXD_DTYP_C        = 0x00000000, /* Context Descriptor */
+@@ -701,326 +140,656 @@
+         }
+     }
+ 
 -    /* TODO: make that a method of e1000::Context */
 -    template sequence   e1000::print_status(Ethernet::Device rtx_ether_ctx)
--    {
++    template type e1000::RxDescriptor()
+     {
 -        chunk   LKM::prototypes()
++        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::Context()
++    {
++        decl data_types()
++        {
++            unsigned char   *io_addr; // XXX should be annoted with __iomem
++            // XXX Forced to hardcode the type because there is a circular
++            // dependency between the rings and the context.
++            // TODO: get the right generated types:
++            int    tx_ring;
++            int    rx_ring;
++        }
++
++        chunk LKM::includes()
++        {
++            #include <linux/types.h>
++        }
++
 +        chunk LKM::prototypes()
          {
              static void rtx_e1000_print_status(${e1000::Context.ref});
++
++            // XXX Needed until we can call methods (issue #46):
++            static unsigned int rtx_e1000_reg_read32(${e1000::Context}, ${e1000::Register});
++            static void rtx_e1000_reg_write32(${e1000::Context}, ${e1000::Register}, unsigned int);
++            static void rtx_e1000_reg_set32(${e1000::Context}, ${e1000::Register}, unsigned int);
++            static void rtx_e1000_reg_unset32(${e1000::Context}, ${e1000::Register}, unsigned int);
          }
  
 -        chunk   LKM::code()
 +        chunk LKM::code()
          {
-             static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx)
+-            static void rtx_e1000_print_status(${e1000::Context.ref} hw_ctx)
++            static void rtx_e1000_print_status(${e1000::Context.ref} self)
              {
 -                unsigned int status = rtx_e1000_register_read32(hw_ctx, E1000_STATUS);
 -                    ${Log::info("card status:")};
@@ -1019,24 +816,270 @@
 -                 * we can't use Log::info below because it just accept a string
 -                 * (as opposed to a format string with its parameters).
 -                 */
-+                unsigned int status = rtx_e1000_reg_read32(hw_ctx, E1000_STATUS);
++                unsigned int status = rtx_e1000_reg_read32(${local.self}, 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):
++                // XXX We can't use Log::info below because it just accepts a
++                // string (as opposed to a format string with its arguments):
                  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");
-@@ -727,300 +572,178 @@
+                 pr_info("\tTransmission: %s\n", (status & 4) ? "Paused" : "Ok");
+                 pr_info("\tInterface: %s\n", (status & 3) == 3 ? "Up" : "Down");
              }
++
++            static unsigned int rtx_e1000_reg_read32(${e1000::Context} self, ${e1000::Register} reg)
++            {
++                return ioread32(${local.self.io_addr} + reg);
++            }
++
++            static void rtx_e1000_reg_write32(${e1000::Context} self,
++                                              ${e1000::Register} reg,
++                                              unsigned int value)
++            {
++                return iowrite32(value, ${local.self.io_addr.io} + reg);
++            }
++
++            static void rtx_e1000_reg_set32(${e1000::Context} self,
++                                            ${e1000::Register} reg,
++                                            unsigned int value)
++            {
++                return iowrite32(
++                    rtx_e1000_reg_read32(${local.self}, reg) | value,
++                    ${local.self.io_addr.io} + reg
++                );
++            }
++
++            static void rtx_e1000_reg_unset32(${e1000::Context} self,
++                                              ${e1000::Register} reg,
++                                              unsigned int value)
++            {
++                return iowrite32(rtx_e1000_reg_read32(
++                    ${local.self}, reg) & ~value,
++                    ${local.self.io_addr.io} + reg
++                );
++            }
          }
  
 -        chunk   ::CALL()
-+        chunk Ethernet::HardwareContext()
++        method init(Builtin::symbol io_addr)
          {
 -            rtx_e1000_print_status(&${rtx_ether_ctx}->hw_ctx);
--        }
--    }
--
++            ${self.io_addr} = ${io_addr};
++        }
++
++        method reg_read32(e1000::Register reg)
++        {
++            ioread32(${self.io_addr} + ${local.reg});
++        }
++
++        method reg_write32(e1000::Register reg, Builtin::number value)
++        {
++            iowrite32(${value}, ${self.io_addr} + ${reg});
++        }
++
++        method reg_set32(e1000::Register reg, Builtin::number value)
++        {
++            iowrite32(ioread32(${self.io_addr} + ${reg}) | ${value}, ${self.io_addr} + ${reg});
++        }
++
++        method reg_unset32(e1000::Register reg, Builtin::number value)
++        {
++            iowrite32(ioread32(${self.io_addr} + ${reg}) & ~${value}, ${self.io_addr} + ${reg});
++        }
++
++        chunk Ethernet::HardwareContext()
++        {
++            ${e1000::Context} hw_ctx;
++        }
++
++        chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol io_addr)
++        {
++            {
++                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
++                ${local.hw_ctx.init(local.io_addr)};
++                ${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 udelay 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")};
++            }
++        }
++
++        // For e1000, this part is documented in the Intel Gigabit Ethernet
++        // Controller Software Developper manual. (You can find it in the
++        // doc/hardware directory).
++        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_rx_tx: general configuration done")};
++
++                int err;
++
++                err = rtx_e1000_rx_ring_alloc_resources(&hw_ctx->rx_ring);
++                if (err)
++                    goto err_alloc_rx_ring;
++                rtx_e1000_rx_ring_configure(&hw_ctx->rx_ring);
++
++                err = rtx_e1000_tx_ring_alloc_resources(&hw_ctx->tx_ring);
++                if (err)
++                    goto err_alloc_tx_ring;
++                rtx_e1000_tx_ring_configure(&hw_ctx->tx_ring);
++
++                err_alloc_tx_ring:
++                    rtx_e1000_rx_ring_free_resources(&hw_ctx->rx_ring);
++                err_alloc_rx_ring:
++                    // XXX Can't return here since we don't know the context.
++                    // TODO: hardcode a goto
++                    (void)1;
++            }
++        }
++
++        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):
++                // XXX #46: ${local.hw_ctx.print_status()};
++                rtx_e1000_print_status(hw_ctx);
++            }
++        }
++
++        chunk Ethernet::disable_interrupts(Ethernet::Device rtx_ether_ctx)
++        {
++            { ${Log::info("adapter_disable_interrupts: TBD...")}; }
++        }
++
++        chunk Ethernet::adapter_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:")};
++                        // XXX #46: ${local.hw_ctx.print_status()};
++                        rtx_e1000_print_status(hw_ctx);
++                    }
++                    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;
++                }
++            }
++        }
++
++        chunk Ethernet::adapter_xmit(Ethernet::Device rtx_ether_ctx, Socket::SKBuff rtx_skb)
++        {
++            { ${Log::info("adapter_xmit: TBD...")}; }
++        }
++
++        chunk Ethernet::adapter_disable_rx(Ethernet::Device rtx_ether_ctx)
++        {
++            { ${Log::info("adapter_disable_rx: TBD..")}; }
++        }
++
++        chunk Ethernet::adpater_disable_tx(Ethernet::Device rtx_ether_ctx)
++        {
++            { ${Log::info("adapter_disable_tx: TBD..")}; }
++        }
++
++        chunk Ethernet::adapter_free_rx_tx(Ethernet::Device rtx_ether_ctx)
++        {
++            { ${Log::info("adapter_free_rx_tx: TBD..")}; }
++        }
++
++        method print_status()
++        {
++            rtx_e1000_print_status(${self});
++        }
++
++        map
++        {
++            io_addr: ${self}->io;
++            rx_ring: ${self}->rx_ring;
++            tx_ring: ${self}->tx_ring;
+         }
+     }
+ 
 -    /*
 -     * We should have been able to do something along those lines, but
 -     * it didn't work so we made the call manually.
@@ -1056,174 +1099,332 @@
 -     * TODO: make them methods of e1000::Context
 -     */
 -    template sequence   e1000::register_read32(e1000::Context ctx, e1000::Register reg_offset)
--    {
++    template type e1000::Ring()
+     {
 -        chunk   LKM::prototypes()
--        {
++        decl data_types()
+         {
 -            /* FIXME: See issue #54 */
 -            static unsigned int    rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref}, unsigned int);
-+            ${e1000::Context}   hw_ctx;
++            ${e1000::Context}       hw_ctx;
++            ${DMA::DMAHandle}       dma;
++            unsigned int            size;
++            ${Builtin::symbol.ref}  descs;
++            ${e1000::Buffer.ref}    buffs;
          }
  
 -        chunk   LKM::code()
-+        chunk Ethernet::adapter_init_context(Ethernet::Device rtx_ether_ctx, Builtin::symbol ioaddr)
++        chunk LKM::prototypes()
          {
 -            /* FIXME: See issue #54 */
 -            static unsigned int    rtx_e1000_register_read32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset)
++            static void rtx_e1000_ring_init(${e1000::Ring.ref}, ${e1000::Context}, int, int);
++        }
++
++        chunk LKM::code()
++        {
++            static void rtx_e1000_ring_init(${e1000::Ring.ref} self, ${e1000::Context} hw_ctx,
++                                            int desc_count, int desc_size)
              {
 -                return ioread32(ctx->ioaddr + reg_offset);
-+                ${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   ::CALL()
-+        chunk Ethernet::adapter_reset(Ethernet::Device rtx_ether_ctx)
-         {
--            rtx_e1000_register_read32(${ctx}, ${reg_offset});
--        }
--    }
--
--    template sequence   e1000::register_write32(e1000::Context ctx, e1000::Register reg_offset, ::number value)
--    {
--        chunk   LKM::prototypes()
--        {
--            /* FIXME: See issue #54 */
--            static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int);
--        }
--
--        chunk   LKM::code()
--        {
--            /* FIXME: See issue #54 */
--            static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value)
-             {
--                iowrite32(value, ctx->ioaddr + reg_offset);
-+                ${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")};
++                BUG_ON(desc_count <= 0 || desc_size <= 0);
++                memset(self, 0, sizeof(*self));
++                self->size = ALIGN(desc_count * desc_size, 4096);
++                self->hw_ctx = hw_ctx;
              }
          }
  
 -        chunk   ::CALL()
-+        chunk Ethernet::adapter_load_mac_address(Ethernet::Device rtx_ether_ctx)
++        method init(e1000::Context hw_ctx, Builtin::number desc_count, Builtin::number desc_size)
+         {
+-            rtx_e1000_register_read32(${ctx}, ${reg_offset});
++            rtx_e1000_ring_init(&${self}, ${hw_ctx}, ${desc_count}, ${desc_size});
++        }
++
++        map
++        {
++            hw_ctx: ${self}->hw_ctx;
++            dma: ${self}->dma;
++            size: ${self}->size;
++            descs: ${self}->descs;
++            buffs: ${self}->buffs;
+         }
+     }
+ 
+-    template sequence   e1000::register_write32(e1000::Context ctx, e1000::Register reg_offset, ::number value)
++    template type e1000::RxRing()
+     {
+-        chunk   LKM::prototypes()
++        decl data_types()
+         {
+-            /* FIXME: See issue #54 */
+-            static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int);
++            ${e1000::Ring}  ring;
+         }
+ 
+-        chunk   LKM::code()
++        chunk LKM::prototypes()
          {
--            rtx_e1000_register_write32(${ctx}, ${reg_offset}, ${value});
--        }
--    }
+-            /* FIXME: See issue #54 */
+-            static void rtx_e1000_register_write32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value)
++            static int rtx_e1000_rx_ring_alloc_resources(${e1000::RxRing.ref});
++            static void rtx_e1000_rx_ring_configure(${e1000::RxRing.ref});
++        }
++
++        chunk LKM::code()
++        {
++            static int rtx_e1000_rx_ring_alloc_resources(${e1000::RxRing.ref} self)
+             {
+-                iowrite32(value, ctx->ioaddr + reg_offset);
++                // XXX Reread & Fix everything down there (data structure changes and so on)
++
++                // 4. Setup the receive descriptor ring
++
++                int i;
++
++                // Allocate the descriptors
++                hw_ctx->rx_ring.base = ${DMA::alloc_coherent(
++                    local.self.hw_ctx.net_dev.device, local.self.size,
++                    local.self.dma.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(ocal.skbuff, ${config.rx_buffer_len})) {
++//                      ${Log::info("adapter_init_rx: cannot allocate a skbuff for the rx ring")};
++//                      goto err_skbuffs_alloc;
++//                  }
++//                  /* TODO: 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));
++
++            err_skbuffs_alloc:
++                while (i--) {
++                    ${DMA::unmap(
++                        local.self.hw_ctx.net_dev.device,
++                        // XXX Leaking cast because of the array: (TODO: the data structure changed)
++                        *((dma_addr_t *)&(self->buffs[i].dma_handle)),
++                        ${config.rx_buffer_len},
++                        RTX_DMA_FROM_DEVICE
++                    )};
++            err_skbuffs_map:
++                    // XXX leaking cast: (TODO: the data structure changed)
++                    dev_kfree_skb((struct sk_buff *)hw_ctx->rx_ring.skbuffs[i].skbuff);
++                }
++
++                ${DMA::free_coherent(
++                    local.self.hw_ctx.net_dev.device, local.self.size,
++                    local.self.descs, local.self.dma.dma_handle
++                )};
++            err_rx_ring_alloc:
++                return -ENOMEM;
++            }
++
++            static void rtx_e1000_rx_ring_configure(${e1000::RxRing.ref} self)
 +            {
-+                ${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;
-+                }
- 
--    template sequence   e1000::register_set32(e1000::Context ctx, e1000::Register reg_offset, ::number value)
--    {
--        chunk   LKM::prototypes()
--        {
--            /* FIXME: See issue #54 */
--            static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int);
--        }
--
--        chunk   LKM::code()
--        {
--            /* FIXME: See issue #54 */
--            static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value)
--            {
--                iowrite32(rtx_e1000_register_read32(ctx, reg_offset) | value, ctx->ioaddr + reg_offset);
-+                ${Log::info("mac address loaded from the EEPROM")};
++                // XXX Reread & Fix everything down there (data structure changes and so on)
++
++                // 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_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RAL,
++                    *(unsigned int *)(${local.self.hw_ctx.net_dev.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_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RAH,
++                    *(unsigned short *)(&${local.self.hw_ctx.net_dev.dev_addr}[4])
++                );
++                rtx_e1000_reg_set32(${local.self.hw_ctx}, E1000_RAH, E1000_RAH_AV);
++
++                ${Log::info("rx_ring_configure: receive address programmed")};
++
++                // 2. Initialize the MTA
++
++                for (i = 0; i != 128; ++i) // TODO Remove that hardcoded 128
++                    rtx_e1000_reg_write32(${local.self.hw_ctx}, E1000_MTA + i * 4, 0);
++
++                ${Log::info("rx_ring_configure: MTA init done")};
++
++                // 5. Save the emplacement and the size of the ring in RDBA/RDLEN
++                rtx_e1000_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RDBAL,
++                    ${local.self.hw_ctx}->rx_ring.dma_base & 0xffffffff
++                );
++                rtx_e1000_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RDBAH,
++                    ${local.self.hw_ctx}->rx_ring.dma_base >> 32
++                );
++                rtx_e1000_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RDLEN,
++                    ${local.self.hw_ctx}->rx_ring.size
++                );
++
++                // 6. Setup RDH/RDT
++                rtx_e1000_reg_write32(${local.self.hw_ctx}, E1000_RDH, 0);
++                rtx_e1000_reg_write32(
++                    ${local.self.hw_ctx}, E1000_RDT,
++                    ${config.rx_ring_size} - 1
++                );
++
++                // 7. Configure the buffer size
++                rtx_e1000_reg_set32(
++                    ${local.self.hw_ctx}, E1000_RCTL,
++                    E1000_RCTL_BSIZE_${config.rx_buffer_len}
++                );
++
++                // 8. Enable the receiver
++                rtx_e1000_reg_set32(${local.self.hw_ctx}, E1000_RCTL, E1000_RCTL_EN);
++
++                ${Log::info("rx_ring_configure: receive registers configured and receiver enabled")};
++
++                return 0;
              }
          }
  
 -        chunk   ::CALL()
-+        // For e1000, this part is documented in the Intel Gigabit Ethernet
-+        // Controller Software Developper manual. (You can find it in the
-+        // doc/hardware directory).
-+        chunk Ethernet::adapter_setup_rx_tx(Ethernet::Device rtx_ether_ctx)
++        method init(e1000::Context hw_ctx, Builtin::number desc_count)
+         {
+-            rtx_e1000_register_write32(${ctx}, ${reg_offset}, ${value});
++            ${self.ring.init(hw_ctx, desc_count, self.desc_size)};
++        }
++
++        method alloc()
++        {
++            rtx_e1000_rx_ring_alloc_resources(${self});
++        }
++
++        method configure()
++        {
++            rtx_e1000_rx_ring_configure(${self});
++        }
++
++        map
++        {
++            // TODO: fix cast to directly get the attributes from the Ring:
++            hw_ctx: ((int)(${self})->hw_ctx);
++            dma: ((int)(${self})->dma);
++            size: ((int)(${self})->size);
++            descs: ((int)(${self})->descs);
++            buffs: ((int)(${self})->buffs);
++            desc_size: sizeof(/* TODO: get the generated type... ${e1000::RxDescriptor} */int);
+         }
+     }
+ 
+-    template sequence   e1000::register_set32(e1000::Context ctx, e1000::Register reg_offset, ::number value)
++    template type e1000::TxRing()
+     {
+-        chunk   LKM::prototypes()
++        decl data_types()
+         {
+-            /* FIXME: See issue #54 */
+-            static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int);
++            ${e1000::Ring}  ring;
+         }
+ 
+-        chunk   LKM::code()
++        chunk LKM::prototypes()
+         {
+-            /* FIXME: See issue #54 */
+-            static void rtx_e1000_register_set32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value)
++            static int rtx_e1000_tx_ring_alloc_resources(${e1000::TxRing.ref});
++            static void rtx_e1000_tx_ring_configure(${e1000::TxRing.ref});
++        }
++
++        chunk LKM::code()
++        {
++            static int rtx_e1000_tx_ring_alloc_resources(${e1000::TxRing.ref} self)
+             {
+-                iowrite32(rtx_e1000_register_read32(ctx, reg_offset) | value, ctx->ioaddr + reg_offset);
++                return 0;
++            }
++
++            static void rtx_e1000_tx_ring_configure(${e1000::TxRing.ref} self)
++            {
++                // return ; XXX wtf fails with:
++                // function 'rtxPH_compile(local_node : node, compile : node, node_idx : value)' hasn't been implemented
+             }
+         }
+ 
+-        chunk   ::CALL()
++        method init(e1000::Context hw_ctx, Builtin::number desc_count)
          {
 -            rtx_e1000_register_set32(${ctx}, ${reg_offset}, ${value});
 -        }
 -    }
-+            {
-+                ${e1000::Context.ref} hw_ctx = &${local.rtx_ether_ctx}->hw_ctx;
- 
+-
 -    template sequence   e1000::register_unset32(e1000::Context ctx, e1000::Register reg_offset, ::number value)
 -    {
 -        chunk   LKM::prototypes()
 -        {
 -            /* FIXME: See issue #54 */
 -            static void rtx_e1000_register_unset32(/*const*/ ${e1000::Context.ref}, unsigned int, unsigned int);
--        }
-+                // "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);
++            ${self.ring.init(hw_ctx, desc_count, self.desc_size)};
+         }
  
 -        chunk   LKM::code()
--        {
++        method alloc()
+         {
 -            /* FIXME: See issue #54 */
 -            static void rtx_e1000_register_unset32(/*const*/ ${e1000::Context.ref} ctx, unsigned int reg_offset, unsigned int value)
 -            {
 -                iowrite32(rtx_e1000_register_read32(ctx, reg_offset) & ~value, ctx->ioaddr + reg_offset);
-+                ${Log::info("adapter_setup: general configuration done")};
-             }
+-            }
++            rtx_e1000_tx_ring_alloc_resources(${self});
          }
  
 -        chunk   ::CALL()
-+        chunk Ethernet::adapter_enable_interrupts(Ethernet::Device)
++        method configure()
          {
 -            rtx_e1000_register_unset32(${ctx}, ${reg_offset}, ${value});
--        }
++            rtx_e1000_tx_ring_configure(${self});
+         }
 -    }
-+            {
-+                ${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
-+                );
  
 -    template sequence   activate_device_interruption(Ethernet::Device rtx_ether_ctx)
 -    {
 -        chunk  ::CALL()
--        {
++        map
+         {
 -            rtx_e1000_register_write32(&${rtx_ether_ctx}->hw_ctx, E1000_IMS,
 -                                       E1000_INTR_TXDW |
 -                                       E1000_INTR_TXQE |
@@ -1316,63 +1517,29 @@
 -                }
 -
 -                return IRQ_HANDLED;
-+                // 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):
-+                // XXX #46: ${local.hw_ctx.print_status()};
-+                rtx_e1000_print_status(hw_ctx);
-             }
-         }
+-            }
+-        }
 -    }
- 
+-
 -    template sequence   e1000::xmit(Ethernet::Device rtx_ether_ctx, Socket::AbstractSKBuff kernel_skb)
 -    {
 -        chunk   ::CALL()
-+        chunk Ethernet::disable_interrupts(Ethernet::Device rtx_ether_ctx)
-         {
+-        {
 -            /*
 -             * Put packets on the TX ring, must return NETDEV_TX_OK or
 -             * NETDEV_TX_BUSY.
 -             */
-+            { ${Log::info("adapter_disable_interrupts: TBD...")}; }
-+        }
- 
+-
 -            ${Socket::SKBuff} skb;
 -            ${e1000::Context.ref} hw_ctx;
 -            ${e1000::TxRing.ref} tx_ring;
 -            ${Device::AbstractDevice.ref} devp;
-+        chunk Ethernet::adapter_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:")};
-+                        // XXX #46: ${local.hw_ctx.print_status()};
-+                        rtx_e1000_print_status(hw_ctx);
-+                    }
-+                    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")};
-+                    }
- 
+-
 -            ${local.skb.init(kernel_skb)};
 -            hw_ctx = &${rtx_ether_ctx}->hw_ctx;
 -            tx_ring = &hw_ctx->tx_ring;
 -            devp = (${Device::AbstractDevice.ref})${rtx_ether_ctx.device};
-+                    // XXX: This sucks since we don't know the pointcut context:
-+                    return IRQ_HANDLED;
-+                }
-+            }
-+        }
- 
+-
 -            ${Log::info("xmit: skbuff details:")};
 -            /*
 -             * skb does not expand on the bound C variable (should be
@@ -1384,11 +1551,7 @@
 -             * ${local.skb.dump_infos()};
 -             */
 -            rtx_socket_skbuff_dump_infos(&skb);
-+        chunk Ethernet::adapter_xmit(Ethernet::Device rtx_ether_ctx, Socket::SKBuff rtx_skb)
-+        {
-+            { ${Log::info("adapter_xmit: TBD...")}; }
-+        }
- 
+-
 -            /*
 -             * The transmission is going to be several steps:
 -             * 1. TCP Segmentation Offload & Checksum Offloading: pick a
@@ -1398,38 +1561,22 @@
 -             * 2. DMA Map the skbuff data as slices of 4096;
 -             * 3. Signal the hardware that data is available via a tx desc.
 -             */
-+        chunk Ethernet::adapter_disable_rx(Ethernet::Device rtx_ether_ctx)
-+        {
-+            { ${Log::info("adapter_disable_rx: TBD..")}; }
-+        }
- 
+-
 -            /* XXX: same thing wanted to use: ${local.tx_ring.descriptors_remaining()} */
 -            if (!rtx_e1000_tx_ring_descriptors_remaining(tx_ring))
 -                return NETDEV_TX_BUSY;
-+        chunk Ethernet::adpater_disable_tx(Ethernet::Device rtx_ether_ctx)
-+        {
-+            { ${Log::info("adapter_disable_tx: TBD..")}; }
-+        }
- 
+-
 -            /* 1. Offloading */
-+        chunk Ethernet::adapter_free_rx_tx(Ethernet::Device rtx_ether_ctx)
-+        {
-+            { ${Log::info("adapter_free_rx_tx: TBD..")}; }
-+        }
- 
+-
 -            /* XXX: ${local.tx_ring.tso_cksum_offload(skb)}; */
 -            if (rtx_e1000_tx_ring_tso_cksum_offload(tx_ring, &skb))
 -            {
 -                ${Log::info("xmit: the packet needs to be fragmented and/or checksummed but this not implemented yet!")};
 -                goto err_offload;
 -            }
- 
+-
 -            /* 2. Map the data */
-+        method print_status()
-+        {
-+            rtx_e1000_print_status(${self});
-+        }
- 
+-
 -            /* XXX: ${local.skb.map_to(devp.k_device)}; */
 -            if (rtx_socket_skbuff_map(&skb, ${devp.k_device}, DMA_TO_DEVICE))
 -            {
@@ -1452,21 +1599,22 @@
 -            /* XXX: ${local.skb.unmap_to_and_free(local.dev)}; */
 -            rtx_socket_skbuff_unmap_and_free(&skb, ${devp.k_device}, DMA_TO_DEVICE);
 -            return NETDEV_TX_OK;
-+        map
-+        {
-+            io: ${self}->io;
-+            rx_ring: ${self}->rx_ring;
-+            tx_ring: ${self}->tx_ring;
++            // TODO: fix cast to directly get the attributes from the Ring:
++            hw_ctx: ((int)(${self})->hw_ctx);
++            dma: ((int)(${self})->dma);
++            size: ((int)(${self})->size);
++            descs: ((int)(${self})->descs);
++            buffs: ((int)(${self})->buffs);
++            desc_size: sizeof(/* TODO: get the generated type ${e1000::TxDescriptor} */int);
          }
      }
  }
 diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/e1000.rti
 +++ b/rathaxes/samples/e1000/e1000.rti
-@@ -1,157 +1,115 @@
- interface e1000 : Socket, Ethernet, DMA, PCI, LKM, Builtin
+@@ -1,157 +1,122 @@
+-interface e1000 : Socket, Ethernet, DMA, PCI, LKM, Builtin
++interface e1000 : Socket, Ethernet, Device, DMA, PCI, LKM, Builtin
  {
 -    required variable   Builtin::number rx_ring_size;
 -    required variable   Builtin::number tx_ring_size;
@@ -1498,24 +1646,44 @@
      }
  
 -    provided type   TxDescriptor
-+    // 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
++    provided type   Context
      {
          decl        data_types();
 -        method      init();
 +
++        chunk       LKM::includes();
 +        chunk       LKM::prototypes();
 +        chunk       LKM::code();
++        chunk       Ethernet::HardwareContext();
++
++        // NOTE: Those callbacks/hooks should probably be in the front-end:
++
++        chunk       Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol);
++        chunk       Ethernet::adapter_reset(Ethernet::Device);
++        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
++        chunk       Ethernet::adapter_setup_rx_tx(Ethernet::Device);
++        chunk       Ethernet::adapter_enable_interrupts(Ethernet::Device);
++        chunk       Ethernet::adapter_disable_interrupts(Ethernet::Device);
++        chunk       Ethernet::adapter_handle_interrupt(Ethernet::Device);
++        chunk       Ethernet::adapter_xmit(Ethernet::Device, Socket::SKBuff);
++        chunk       Ethernet::adapter_disable_rx(Ethernet::Device);
++        chunk       Ethernet::adapter_disable_tx(Ethernet::Device);
++        chunk       Ethernet::adapter_free_rx_tx(Ethernet::Device);
 +
 +        method      init(Builtin::symbol);
-+        method      read32(Register);
-+        method      write32(Register, Builtin::number);
-+        method      set32(Register, Builtin::number);
-+        method      unset32(Register, Builtin::number);
++        method      print_status();
++        method      reg_read32(Register);
++        method      reg_write32(Register, Builtin::number);
++        method      reg_set32(Register, Builtin::number);
++        method      reg_unset32(Register, Builtin::number);
 +
-+        attribute   Builtin::symbol.scalar  io;
++        // XXX: Circular dependency with the rings, this will prevent us to
++        // call methods even when issue $46 is resolved, and it also forces
++        // us to hardcode generated types in the definition of the type:
++        attribute   Builtin::symbol.scalar  rx_ring;
++        attribute   Builtin::symbol.scalar  tx_ring;
++
++        attribute   Ethernet::Device.ref    net_dev;
 +    }
 +
 +    provided type   Ring
@@ -1525,10 +1693,13 @@
 +        chunk       LKM::prototypes();
 +        chunk       LKM::code();
 +
-+        method      init(MMIO, Builtin::number, Builtin::number);
++        method      init(e1000::Context, Builtin::number);
 +
-+        attribute   MMIO.scalar             io;
-+        attribute   DMA::DMAHandle.scalar    dma;
++        // Keep a backref to The context since it's going to be needed for of
++        // operations involving the ethernet device, flags on the context, etc.
++        attribute   Context.ref             hw_ctx;
++
++        attribute   DMA::DMAHandle.scalar   dma;
 +        attribute   Builtin::number.scalar  size;   // Total size in bytes
 +        attribute   Builtin::symbol.ref     descs;
 +        attribute   Buffer.ref              buffs;
@@ -1545,31 +1716,22 @@
 +        chunk       LKM::code();
  
 -        attribute   DMA::DMAHandle.scalar   dma_base;
--        attribute   Builtin::number.scalar  size;
-+        method      init(MMIO, Builtin::number);
++        method      init(e1000::Context, Builtin::number);
 +        method      alloc(); // Returns != 0 on failure
-+
-+        attribute   RxDescriptor.scalar descs;
-+    }
-+
-+    provided type   TxRing
-+    {
-+        decl        data_types();
++        method      free();
++        method      configure();
 +
-+        chunk       LKM::prototypes();
-+        chunk       LKM::code();
-+
-+        method      init(MMIO, Builtin::number);
-+        method      alloc(); // Returns != 0 on failure
-+
-+        attribute   TxDescriptor.scalar descs;
-     }
- 
-     provided type   Context
-     {
++        // Re-expose all the Ring attributes + the size of a single descriptor:
++        attribute   Context.ref             hw_ctx;
++        attribute   DMA::DMAHandle.scalar   dma;
+         attribute   Builtin::number.scalar  size;
+-    }
+-
+-    provided type   Context
+-    {
 -        chunk       Ethernet::HardwareContext();
-         decl        data_types();
- 
+-        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
@@ -1578,44 +1740,33 @@
 -        chunk       Ethernet::adapter_init_context(Ethernet::Device,
 -                                                   Builtin::number,
 -                                                   Builtin::symbol);
-+        chunk       LKM::includes();
-+        chunk       LKM::prototypes();
-+        chunk       LKM::code();
-+        chunk       Ethernet::HardwareContext();
-+
-+        // NOTE: Those callbacks/hooks should probably be in the front-end:
-+
-+        chunk       Ethernet::adapter_init_context(Ethernet::Device, Builtin::symbol);
-         chunk       Ethernet::adapter_reset(Ethernet::Device);
-         chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
+-        chunk       Ethernet::adapter_reset(Ethernet::Device);
+-        chunk       Ethernet::adapter_load_mac_address(Ethernet::Device);
 -        chunk       Ethernet::adapter_setup(Ethernet::Device);
-+        chunk       Ethernet::adapter_setup_rx_tx(Ethernet::Device);
-+        chunk       Ethernet::adapter_enable_interrupts(Ethernet::Device);
-+        chunk       Ethernet::adapter_disable_interrupts(Ethernet::Device);
-+        chunk       Ethernet::adapter_handle_interrupt(Ethernet::Device);
-+        chunk       Ethernet::adapter_xmit(Ethernet::Device, Socket::SKBuff);
-+        chunk       Ethernet::adapter_disable_rx(Ethernet::Device);
-+        chunk       Ethernet::adapter_disable_tx(Ethernet::Device);
-+        chunk       Ethernet::adapter_free_rx_tx(Ethernet::Device);
- 
-+        method      print_status();
-+
-+        attribute   MMIO.scalar     io;
-         attribute   RxRing.scalar   rx_ring;
+-
+-        attribute   RxRing.scalar   rx_ring;
 -        /* XXX: circular dependency with Contex: */
 -        //attribute   TxRing.scalar   tx_ring;
--    }
--
--    provided type   TxRing
--    {
--        chunk       LKM::prototypes();
--        chunk       LKM::code();
++        attribute   RxDescriptor.scalar     descs;
++        attribute   Builtin::number.scalar  desc_size;
+     }
+ 
+     provided type   TxRing
+     {
++        decl        data_types();
++
+         chunk       LKM::prototypes();
+         chunk       LKM::code();
 -        decl        data_types();
 -        method      init();
--
+ 
 -        /* XXX: Callback that should be in the front-end: */
 -        chunk       Ethernet::adapter_init_tx(Ethernet::Device);
--
++        method      init(e1000::Context, Builtin::number);
++        method      alloc(); // Returns != 0 on failure
++        method      free();
++        method      configure();
+ 
 -        /* Clean the ring (i.e: move the head closer to the tail): */
 -        method      clean();
 -        /* Return the number of clean descriptors left in the ring: */
@@ -1707,12 +1858,15 @@
 -        provided chunk  LKM::prototypes();
 -        provided chunk  LKM::code();
 -        provided chunk  ::CALL();
-+        attribute   TxRing.scalar   tx_ring;
++        // Re-expose all the Ring attributes + the size of a single descriptor:
++        attribute   Context.ref             hw_ctx;
++        attribute   DMA::DMAHandle.scalar   dma;
++        attribute   Builtin::number.scalar  size;
++        attribute   TxDescriptor.scalar     descs;
++        attribute   Builtin::number.scalar  desc_size;
      }
  }
 diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/ethernet.blt
 +++ b/rathaxes/samples/e1000/ethernet.blt
 @@ -1,4 +1,4 @@
@@ -1721,6 +1875,24 @@
  {
      template type   Ethernet::ProtocolId()
      {
+@@ -9,7 +9,7 @@
+ 
+         chunk LKM::prototypes()
+         {
+-            static const char   *rtx_ethernet_protocol_id_to_str(unsigned short);
++            static const char *rtx_ethernet_protocol_id_to_str(unsigned short);
+         }
+ 
+         chunk LKM::data()
+@@ -28,7 +28,7 @@
+ 
+         chunk LKM::code()
+         {
+-            static const char   *rtx_ethernet_protocol_id_to_str(unsigned short proto_id)
++            static const char *rtx_ethernet_protocol_id_to_str(unsigned short proto_id)
+             {
+                 for (int i = 0;
+                      i != sizeof(rtx_ethernet_proto_table) / sizeof(rtx_ethernet_proto_table[0]);
 @@ -61,7 +61,7 @@
  
          method  init(Builtin::symbol dev)
@@ -1755,9 +1927,18 @@
      {
          chunk   LKM::includes()
          {
-@@ -164,60 +167,68 @@
+@@ -157,100 +160,114 @@
+ 
+         chunk LKM::prototypes()
          {
-             static int  rtx_ethernet_open(struct net_device *dev)
+-            static int  rtx_ethernet_open(struct net_device *);
++            static int rtx_ethernet_open(struct net_device *);
+         }
+ 
+         chunk LKM::code()
+         {
+-            static int  rtx_ethernet_open(struct net_device *dev)
++            static int rtx_ethernet_open(struct net_device *dev)
              {
 -                /*
 -                 * XXX The casts are here because the compiler doesn't resolve
@@ -1817,13 +1998,13 @@
          chunk LKM::prototypes()
          {
 -            static int  rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev);
-+            static int  rtx_ethernet_xmit(struct sk_buff *skb, struct net_device *dev);
++            static int rtx_ethernet_xmit(struct sk_buff *skb, struct net_device *dev);
          }
  
          chunk LKM::code()
          {
 -            static int  rtx_ethernet_xmit(struct sk_buff* kernel_skb, struct net_device *net_dev)
-+            static int  rtx_ethernet_xmit(struct sk_buff *k_skb, struct net_device *net_dev)
++            static int rtx_ethernet_xmit(struct sk_buff *k_skb, struct net_device *net_dev)
              {
                  ${Ethernet::Device.ref} rtx_ether_ctx = netdev_priv(net_dev);
 -                ${Socket::AbstractSKBuff.ref} rtx_skb = (${Socket::AbstractSKBuff.ref}) kernel_skb;
@@ -1849,12 +2030,14 @@
      {
          chunk LKM::prototypes()
          {
-@@ -226,31 +237,37 @@
+-            static int  rtx_ethernet_close(struct net_device *);
++            static int rtx_ethernet_close(struct net_device *);
+         }
  
          chunk LKM::code()
          {
 -            static int  rtx_ethernet_close(struct net_device *dev)
-+            static int  rtx_ethernet_close(struct net_device *net_dev)
++            static int rtx_ethernet_close(struct net_device *net_dev)
              {
 -                ${Ethernet::AbstractDevice.ref} rtx_net_dev;
 -                { /* XXX: I end up with a placeholder if I don't open a scope */
@@ -1901,7 +2084,20 @@
      {
          /*
           * We can't use the irqreturn_t type here because CNornm doesn't know
-@@ -269,11 +286,16 @@
+@@ -258,29 +275,34 @@
+          */
+         chunk LKM::prototypes()
+         {
+-            static enum irqreturn   rtx_ethernet_interrupt_handler(int, void *);
++            static enum irqreturn rtx_ethernet_interrupt_handler(int, void *);
+         }
+ 
+         chunk LKM::code()
+         {
+-            static enum irqreturn   rtx_ethernet_interrupt_handler(int irq, void *dev_id)
++            static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id)
+             {
+                 ${Ethernet::AbstractDevice.ref} rtx_net_dev = dev_id;
                  ${Ethernet::Device.ref} rtx_ether_ctx;
                  rtx_ether_ctx = ${local.rtx_net_dev.rtx_ether_ctx};
  
@@ -1919,22 +2115,124 @@
      }
  
      template sequence   Ethernet::init()
-@@ -342,12 +364,8 @@
-              * XXX: the asssignments/casts are here to circumvent
-              * typing issues in the compiler (see previous XXX).
-              */
+     {
+         chunk LKM::data()
+         {
+-            static const struct net_device_ops  rtx_ether_ops =
++            static const struct net_device_ops rtx_ether_ops =
+             {
+                 .ndo_open = rtx_ethernet_open,
+                 .ndo_stop = rtx_ethernet_close,
+@@ -298,64 +320,62 @@
+          */
+         chunk PCI::pci_probe_hook(PCI::Device rtx_pci_dev)
+         {
+-            ${Ethernet::AbstractDevice.ref} rtx_net_dev;
+-            ${Ethernet::Device.ref} rtx_ether_ctx;
++            {
++                ${Ethernet::AbstractDevice.ref} rtx_net_dev;
++                ${Ethernet::Device.ref} rtx_ether_ctx;
+ 
+-            rtx_net_dev = (${Ethernet::AbstractDevice.ref})alloc_etherdev(sizeof(*rtx_ether_ctx));
+-            if (!rtx_net_dev)
+-            {
+-                ${Log::info("cannot allocate the ethernet device context")};
+-                error = -ENOMEM;
+-                goto fail;
++                rtx_net_dev = (${Ethernet::AbstractDevice.ref})alloc_etherdev(sizeof(*rtx_ether_ctx));
++                if (!rtx_net_dev)
++                {
++                    ${Log::info("cannot allocate the ethernet device context")};
++                    error = -ENOMEM;
++                    goto fail;
++                }
++                SET_NETDEV_DEV(${local.rtx_net_dev.k_net_dev}, ${rtx_pci_dev.device});
++                strlcpy(${local.rtx_net_dev.k_net_dev}->name,
++                        ${config.ifname},
++                        sizeof(${local.rtx_net_dev.k_net_dev}->name));
++                ${local.rtx_net_dev.k_net_dev}->irq = ${rtx_pci_dev.irq};
++                ${local.rtx_net_dev.k_net_dev}->netdev_ops = &rtx_ether_ops;
++
++                error = register_netdev(${local.rtx_net_dev.k_net_dev});
++                if (error)
++                {
++                    ${Log::info("cannot register the driver in the net subsystem")};
++                    goto fail;
++                }
++
++                /* Initialize our context held by the net_device structure */
++                /*
++                 * XXX: the cast is here because the compiler resolve the
++                 * type of rtx_pci_dev.pci_device to the type of
++                 * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device.
++                 */
++                ${PCI::AbstractDevice.ref} workaround = ${rtx_pci_dev.pci_device};
++                ${cast local.workaround as PCI::AbstractDevice};
++                { /* XXX: I end up with a placeholder if I don't open a scope */
++                    ${local.rtx_ether_ctx.init(local.rtx_net_dev, local.workaround)};
++                }
++
++                /* Register ourselves in the parent context: */
++                /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */
++                ${rtx_pci_dev}->context = rtx_ether_ctx;
++
++                /*
++                 * XXX: the asssignments/casts are here to circumvent
++                 * typing issues in the compiler (see previous XXX).
++                 */
++                unsigned char /* __iomem */ *io_addr = ${rtx_pci_dev.ioaddr};
++                ${pointcut Ethernet::adapter_init_context(local.rtx_ether_ctx, local.io_addr)};
++                ${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},
++                       ${local.rtx_ether_ctx.dev_addr},
++                       ${local.rtx_net_dev.k_net_dev}->addr_len);
+             }
+-            SET_NETDEV_DEV(${local.rtx_net_dev.k_net_dev}, ${rtx_pci_dev.device});
+-            strlcpy(${local.rtx_net_dev.k_net_dev}->name,
+-                    ${config.ifname},
+-                    sizeof(${local.rtx_net_dev.k_net_dev}->name));
+-            ${local.rtx_net_dev.k_net_dev}->irq = ${rtx_pci_dev.irq};
+-            ${local.rtx_net_dev.k_net_dev}->netdev_ops = &rtx_ether_ops;
+-
+-            error = register_netdev(${local.rtx_net_dev.k_net_dev});
+-            if (error)
+-            {
+-                ${Log::info("cannot register the driver in the net subsystem")};
+-                goto fail;
+-            }
+-
+-            /* Initialize our context held by the net_device structure */
+-            /*
+-             * XXX: the cast is here because the compiler resolve the
+-             * type of rtx_pci_dev.pci_device to the type of
+-             * rtx_pci_dev instead of the type of rtx_pci_dev.pci_device.
+-             */
+-            ${PCI::AbstractDevice.ref} workaround = ${rtx_pci_dev.pci_device};
+-            ${cast local.workaround as PCI::AbstractDevice};
+-            { /* XXX: I end up with a placeholder if I don't open a scope */
+-                ${local.rtx_ether_ctx.init(local.rtx_net_dev, local.workaround)};
+-            }
+-
+-            /* Register ourselves in the parent context: */
+-            /* ${rtx_pci_dev.set_context(local.rtx_ether_ctx)}; */
+-            ${rtx_pci_dev}->context = rtx_ether_ctx;
+-
+-            /*
+-             * 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};
+-            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},
-@@ -355,7 +373,7 @@
-                    ${local.rtx_net_dev.k_net_dev}->addr_len);
+-            ${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},
+-                   ${local.rtx_ether_ctx.dev_addr},
+-                   ${local.rtx_net_dev.k_net_dev}->addr_len);
          }
  
 -        /* This chunk should be removed (see #26) */
@@ -1942,8 +2240,23 @@
          chunk   ::CALL()
          {
          }
-@@ -377,7 +395,7 @@
-             free_netdev(${local.rtx_net_dev.k_net_dev});
+@@ -369,15 +389,17 @@
+          */
+         chunk   PCI::pci_remove_hook(PCI::Device rtx_pci_dev)
+         {
+-            ${Ethernet::Device.ref} rtx_ether_ctx = ${rtx_pci_dev.rtx_drv_context};
+-            BUG_ON(!rtx_ether_ctx);
++            {
++                ${Ethernet::Device.ref} rtx_ether_ctx = ${rtx_pci_dev.rtx_drv_context};
++                BUG_ON(!rtx_ether_ctx);
+ 
+-            ${Ethernet::AbstractDevice.ref} rtx_net_dev = ${local.rtx_ether_ctx.net_device};
+-            unregister_netdev(${local.rtx_net_dev.k_net_dev});
+-            free_netdev(${local.rtx_net_dev.k_net_dev});
++                ${Ethernet::AbstractDevice.ref} rtx_net_dev = ${local.rtx_ether_ctx.net_device};
++                unregister_netdev(${local.rtx_net_dev.k_net_dev});
++                free_netdev(${local.rtx_net_dev.k_net_dev});
++            }
          }
  
 -        /* This chunk should be removed (see #26) */
@@ -1952,8 +2265,6 @@
          {
          }
 diff --git a/rathaxes/samples/e1000/ethernet.rti b/rathaxes/samples/e1000/ethernet.rti
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/ethernet.rti
 +++ b/rathaxes/samples/e1000/ethernet.rti
 @@ -2,16 +2,16 @@
@@ -2058,7 +2369,7 @@
      }
  
 -    required sequence   close(Ethernet::Device)
-+    provided sequence   close()
++    provided sequence       close()
      {
 -        provided chunk  LKM::prototypes();
 -        provided chunk  LKM::code();
@@ -2108,8 +2419,6 @@
      }
  
 diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/lkm.rtx
 +++ b/rathaxes/samples/e1000/lkm.rtx
 @@ -1,40 +1,5 @@
@@ -2163,8 +2472,6 @@
  
      /*
 diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/old_e1000.blt
-old mode 100755
-new mode 100644
 copy from rathaxes/samples/e1000/e1000.blt
 copy to rathaxes/samples/e1000/old_e1000.blt
 --- a/rathaxes/samples/e1000/e1000.blt
@@ -2190,13 +2497,9 @@
                          ${Log::info("adapter_init_rx: cannot dma-map a skbuff for the rx ring")};
                          goto err_skbuffs_map;
 diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/old_e1000.rti
-old mode 100755
-new mode 100644
 copy from rathaxes/samples/e1000/e1000.rti
 copy to rathaxes/samples/e1000/old_e1000.rti
 diff --git a/rathaxes/samples/e1000/socket.blt b/rathaxes/samples/e1000/socket.blt
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/socket.blt
 +++ b/rathaxes/samples/e1000/socket.blt
 @@ -22,16 +22,12 @@
@@ -2346,8 +2649,6 @@
      }
  }
 diff --git a/rathaxes/samples/e1000/socket.rti b/rathaxes/samples/e1000/socket.rti
-old mode 100755
-new mode 100644
 --- a/rathaxes/samples/e1000/socket.rti
 +++ b/rathaxes/samples/e1000/socket.rti
 @@ -12,20 +12,14 @@