changeset 77:892b3bc7e43b

Wip on the RX init in the e1000 sample
author Louis Opter <louis@lse.epitech.net>
date Sun, 04 Mar 2012 18:35:43 +0100
parents 51bea596df7f
children 501bf9cf65dc
files e1000_initialize_reception.patch
diffstat 1 files changed, 256 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/e1000_initialize_reception.patch	Sun Mar 04 15:27:34 2012 +0100
+++ b/e1000_initialize_reception.patch	Sun Mar 04 18:35:43 2012 +0100
@@ -17,18 +17,87 @@
 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
-@@ -36,6 +36,25 @@
+@@ -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,78 @@
          }
      }
  
-+    template type   e1000::RingRx()
++    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;
++                rtx_e1000_rx_descriptor_p   base;
++                void                        *dma_base;
++
++                struct sk_buff              *skbuffs[256 /* ${config.rx_ring_size} */];
++                void                        *dma_skbuffs[256 /* ${config.rx_ring_size} */];
++            };
 +        }
 +
 +        chunk   ::init()
@@ -43,7 +112,7 @@
      template type   e1000::Register()
      {
          chunk   LKM::includes()
-@@ -64,6 +83,9 @@
+@@ -64,6 +139,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) */
@@ -53,7 +122,7 @@
              };
          }
  
-@@ -132,7 +154,8 @@
+@@ -132,7 +210,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) */
@@ -63,14 +132,61 @@
              };
          }
  
-@@ -491,9 +514,32 @@
-             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);
+@@ -458,14 +537,23 @@
+         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)
++             */
++            ${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 +566,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(&${ctx}->hw_ctx, E1000_CRCERRS + i * 4, 0);
++                rtx_e1000_register_write32(hw_ctx, E1000_CRCERRS + i * 4, 0);
 +
 +            /*
 +             * Receive initialization
@@ -79,33 +195,156 @@
 +             * - Initialize the Multicast Table Array;
 +             * - Program the interrupt mask register (done in
 +             *   e1000::activate_device_interruption);
-+             *
-+             * (We should use uint{32,16}_t but CNorm doesn't know them yet)
++             * - Allocate the receive descriptor ring and map it to make it
++             *   accessible by the device.
 +             */
-+            rtx_e1000_register_write32(&${ctx}->hw_ctx, E1000_RAL,
++
++             /* (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(&${ctx}->hw_ctx, E1000_RAH,
++            rtx_e1000_register_write32(hw_ctx, E1000_RAH,
 +                    *(unsigned short *)(&${ctx}->net_dev->dev_addr[4]));
-+            rtx_e1000_register_set32(&${ctx}->hw_ctx, E1000_RAH, E1000_RAH_AV);
++            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(&${ctx}->hw_ctx, E1000_MTA + i * 4, 0);
++                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,8 @@
+@@ -1,6 +1,9 @@
  interface e1000 : Socket, Ethernet, PCI, LKM
  {
      provided type   e1000::Context;
-+    provided type   e1000::RingRx;
++    provided type   e1000::RxDescriptor;
++    provided type   e1000::RxRing;
 +
      /*
       * These two types should actually be registers definitions in the frontend:
       */
+@@ -57,6 +60,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
+@@ -102,7 +102,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;
+ 
+                 ${pointcut ::IMPLEMENTATION(local.rtx_ether_dev)};
+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;
+ }