# HG changeset patch
# Parent 0d14f4eef173e65c3430393966e5f7e3bef7a8b2
rathaxes: initialize reception on the e1000 sample:

- This is documented in details in the sections 14.4 and 3.2 of the
  Intel Gigabit Controller Software Developer manual;
- "Address filtering" is set up, address filters just tell the hardware
  which packets they should accept (unicast/multicast/vlan/promisc), we
  simply configure the hardware to accept packet for its own mac
  address (receive address);
- It involves setting up a ring of receive descriptors (their format is
  documented in section 3.2.3) and an internal data structure to keep
  track of the ring;
- Each descriptor of the ring correspond to an skbuff (skbuff are
  allocated individually).

diff --git a/rathaxes/samples/e1000/e1000.blt b/rathaxes/samples/e1000/e1000.blt
--- a/rathaxes/samples/e1000/e1000.blt
+++ b/rathaxes/samples/e1000/e1000.blt
@@ -21,9 +21,12 @@
              */
             typedef struct rtx_e1000_ctx
             {
-                int                             bars;
-                unsigned char /* __iomem */     *ioaddr;
-                int                             irq;
+                int                         bars;
+                unsigned char /* __iomem */ *ioaddr;
+                int                         irq;
+
+                /* we can't use the Rathaxes type here (#8) */
+                struct rtx_e1000_rx_ring    rx_ring;
             } *rtx_e1000_ctx_p;
         }
 
@@ -36,6 +39,82 @@
         }
     }
 
+    template type   e1000::RxDescriptor()
+    {
+        chunk   LKM::includes()
+        {
+            typedef int ${e1000::RxDescriptor};
+
+            #include <linux/types.h>
+        }
+
+        chunk   ::decl()
+        {
+            typedef struct rtx_e1000_rx_descriptor
+            {
+                /* actual types are in comments */
+                unsigned long int   /* __le64 */    buff_addr;
+                unsigned short      /* __le16 */    length;
+                unsigned short      /* __le16 */    csum;
+                unsigned char                       status;
+                unsigned char                       errors;
+                unsigned short      /* __le16 */    special;
+            } *rtx_e1000_rx_descriptor_p;
+        }
+
+        chunk   ::init()
+        {
+        }
+
+        map
+        {
+        }
+    }
+
+    template type   e1000::RxRing()
+    {
+        chunk   LKM::includes()
+        {
+            typedef int ${e1000::RxRing};
+        }
+
+        chunk   ::decl()
+        {
+            /*
+             * - size: total size of the ring in bytes.
+             * - base: address of the ring;
+             * - dma_base: (physical) address of the ring where the device
+             *   can access it;
+             * - skbuffs: array of the skbuffs associated with
+             *   each descriptor;
+             * - dma_skbuffs: (physical) address of each skbuff
+             *   where the device can write the received
+             *   packets;
+             */
+            struct rtx_e1000_rx_ring
+            {
+                unsigned int                	size;
+                /*
+                 * we can't use the typedef here because will not understand it
+                 * in __std__ mode
+                 */
+                struct rtx_e1000_rx_descriptor	*base;
+                void                        	*dma_base;
+
+                struct sk_buff              *skbuffs[256 /* ${config.rx_ring_size} */];
+                void                        *dma_skbuffs[256 /* ${config.rx_ring_size} */];
+            };
+        }
+
+        chunk   ::init()
+        {
+        }
+
+        map
+        {
+        }
+    }
+
     template type   e1000::Register()
     {
         chunk   LKM::includes()
@@ -64,6 +143,9 @@
                 E1000_FCT           = 0x00030, /* Flow Control Type */
                 E1000_FCTTV         = 0x00170, /* Flow Control Transmit Timer Value */
                 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 */
             };
         }
 
@@ -132,7 +214,8 @@
                 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_INTR_MDAC                 = 0x00000200, /* MDIO access complete */
+                E1000_RAH_AV                    = (1 << 31),  /* Set the MAC Address as Valid */
             };
         }
 
@@ -458,14 +541,24 @@
         chunk  ::CALL()
         {
             /*
-             * This is documented in the Intel Gigabit Ethernet Controller
-             * Software Developper manual.
+             * This part is documented in the Intel Gigabit Ethernet Controller
+             * Software Developper manual. (You can find it in the doc/hardware
+             * directory).
              *
              * Since this part is actually completely device specific it should
              * not be written here. (but in the front-end).
              */
 
             /*
+             * shortcut hw_ctx... maybe we should directly take an
+             * e1000::Context? (but we would need to make it point back to
+             * the struct net_device)
+             */
+            typedef int       ${e1000::Context};
+            ${e1000::Context} hw_ctx;
+            hw_ctx = &${ctx}->hw_ctx;
+
+            /*
              * "General Configuration" (section 14.3):
              *
              * - CTRL.ASDE/CTRL.SLU: Let the PHY handle the speed detection &
@@ -478,22 +571,111 @@
              * - Finally, initialize all the statistic registers from
              *   E1000_CRCERRS to E1000_TSCTFC.
              */
-            rtx_e1000_register_set32(&${ctx}->hw_ctx, E1000_CTRL,
+
+            rtx_e1000_register_set32(hw_ctx, E1000_CTRL,
                                      E1000_CMD_ASDE |
                                      E1000_CMD_SLU);
-            rtx_e1000_register_unset32(&${ctx}->hw_ctx, E1000_CTRL,
+            rtx_e1000_register_unset32(hw_ctx, E1000_CTRL,
                                        E1000_CMD_LRST    |
                                        E1000_CMD_FRCSPD  |
                                        E1000_CMD_PHY_RST |
                                        E1000_CMD_ILOS    |
                                        E1000_CMD_VME);
-            rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCAH, 0);
-            rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCAL, 0);
-            rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCT, 0);
-            rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_FCTTV, 0);
-            int i = 0;
+            rtx_e1000_register_write32(hw_ctx, E1000_FCAH, 0);
+            rtx_e1000_register_write32(hw_ctx, E1000_FCAL, 0);
+            rtx_e1000_register_write32(hw_ctx, E1000_FCT, 0);
+            rtx_e1000_register_write32(hw_ctx, E1000_FCTTV, 0);
+            int i = 0; /* CNorm workaround, the init part of for isn't generated */
             for (i = 0; i != 64; ++i)
-                rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_CRCERRS + i * 4, 0);
+                rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + i * 4, 0);
+
+            /*
+             * Receive initialization
+             *
+             * - Program the receive address, in RAL/RAH;
+             * - Initialize the Multicast Table Array;
+             * - Program the interrupt mask register (done in
+             *   e1000::activate_device_interruption);
+             * - Allocate the receive descriptor ring and map it to make it
+             *   accessible by the device.
+             */
+
+             /* (We should use uint{32,16}_t but CNorm doesn't know them yet) */
+            rtx_e1000_register_write32(hw_ctx, E1000_RAL,
+                    *(unsigned int *)(${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_register_write32(hw_ctx, E1000_RAH,
+                    *(unsigned short *)(&${ctx}->net_dev->dev_addr[4]));
+            rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV);
+
+            i = 0; /* CNorm workaround, the init part of for isn't generated */
+            for (i = 0; i != 128; ++i)
+                rtx_e1000_register_write32(hw_ctx, E1000_MTA + i * 4, 0);
+
+            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(&${ctx}->pci_dev->dev,
+                    hw_ctx->rx_ring.size, &hw_ctx->rx_ring.dma_base, GFP_KERNEL);
+            if (!hw->ctx->rx_ring.base)
+            {
+                ${Log::info("cannot allocate the descriptors for the Rx ring")};
+                goto err_rx_ring_alloc;
+            }
+
+            i = 0;
+            for (i = 0; i != ${config.rx_ring_size}; ++i)
+            {
+                hw_ctx->rx_ring.skbuffs[i] = netdev_allock_skb(${ctx}->net_device,
+                        ${config.rx_buffer_len});
+                if (!hw_ctx->rx_ring.skbuffs[i])
+                {
+                    ${Log::info("cannot allocate a skbuff for the Rx ring")};
+                    goto err_skbuffs_alloc;
+                }
+                hw_ctx->rx_ring.dma_skbuffs[i] = dma_map_single(&${ctx}->pci_dev->dev,
+                        hw_ctx->rx_ring.skbuffs[i]->data,
+                        ${config.rx_buffer_len},
+                        DMA_FROM_DEVICE);
+                if (dma_mapping_error(&${ctx}->pci_dev->dev,
+                            hw_ctx->rx_ring.dma_skbuffs[i]))
+                {
+                    ${Log::info("cannot dma-map a skbuff for the Rx ring")};
+                    goto err_skbuffs_map;
+                }
+                hw_ctx->rx_ring.base[i].buff_addr = cpu_to_le64(hw_ctx->rx_ring.dma_skbuffs[i]);
+            }
+
+            /*
+             * Always the same problem with error handling, we don't know where
+             * we are at in the "parent context":
+             */
+
+        err_skbuffs_alloc:
+            while (i--)
+            {
+                dma_unmap_single(&${ctx}->pci_dev->dev,
+                        hw_ctx->rx_ring.dma_skbuffs[i],
+                        ${config.rx_buffer_len},
+                        DMA_FROM_DEVICE);
+        err_skbuffs_map:
+                dev_kfree_skb(hw_ctx->rx_ring.skbuffs[i]);
+            }
+
+            dma_free_coherent(&${ctx}->pci_dev->dev, hw_ctx->rx_ring.size,
+                    hw_ctx->rx_ring.base, hw_ctx->rx_ring.dma_base);
+        err_rx_ring_alloc:
+            return -ENOMEM;
+        }
+    }
+
+    template sequence   e1000::free_rx_tx(Ethernet::Device ctx)
+    {
+        chunk   ::CALL()
+        {
+
         }
     }
 
diff --git a/rathaxes/samples/e1000/e1000.rti b/rathaxes/samples/e1000/e1000.rti
--- a/rathaxes/samples/e1000/e1000.rti
+++ b/rathaxes/samples/e1000/e1000.rti
@@ -1,6 +1,9 @@
 interface e1000 : Socket, Ethernet, PCI, LKM
 {
     provided type   e1000::Context;
+    provided type   e1000::RxDescriptor;
+    provided type   e1000::RxRing;
+
     /*
      * These two types should actually be registers definitions in the frontend:
      */
@@ -55,6 +58,11 @@
         provided chunk  ::CALL();
     }
 
+    provided sequence   e1000::free_rx_tx(Ethernet::Device dev)
+    {
+        provided chunk  ::CALL();
+    }
+
     provided sequence   e1000::handle_interrupt(Ethernet::Device)
     {
         provided chunk  ::CALL();
diff --git a/rathaxes/samples/e1000/ethernet.blt b/rathaxes/samples/e1000/ethernet.blt
--- a/rathaxes/samples/e1000/ethernet.blt
+++ b/rathaxes/samples/e1000/ethernet.blt
@@ -105,7 +105,7 @@
         {
             static int  rtx_ethernet_close(struct net_device *dev)
             {
-                struct rtx_ethernet_dev* rtx_ether_dev =  netdev_priv(dev);
+                struct rtx_ethernet_dev* rtx_ether_dev = netdev_priv(dev);
                 struct rtx_e1000_ctx* ctx = &rtx_ether_dev->hw_ctx;
 
                 ${cast local.rtx_ether_dev as Ethernet::Device};
diff --git a/rathaxes/samples/e1000/lkm.rtx b/rathaxes/samples/e1000/lkm.rtx
--- a/rathaxes/samples/e1000/lkm.rtx
+++ b/rathaxes/samples/e1000/lkm.rtx
@@ -24,7 +24,17 @@
     Ethernet::close(Ethernet::Device dev)
     {
         Log::info("closing the device");
+
+        /*
+         * Note: some calls to release resources must be done when IRQs are
+         * enabled (dma_free_coherent() for example). So we have to cleanup our
+         * stuff before free_interrupt_handler().
+         */
+        e1000::free_rx_tx(dev);
+        Log::info("free'ed up skbuffs");
+
         e1000::free_interrupt_handler(dev);
+        Log::info("interrupt handler free'ed");
     }
 
     Ethernet::interrupt_handler(Ethernet::Device dev)
@@ -61,4 +71,11 @@
     PCI::set_master = true;
 
     Ethernet::ifname = "rtx%d";
+
+    e1000::rx_ring_size = 256; /* Number of incoming packets we can buffer */
+    /*
+     * The e1000 supports seven receive buffer sizes: 256, 512, 1024, 2048,
+     * 4096, 8192 and 16384 bytes:
+     */
+    e1000::rx_buffer_len = 2048;
 }
