changeset 83:27f0e70df342

Wip on the transmission, tx init done, and tx hooked from Ethernet send
author Louis Opter <louis@lse.epitech.net>
date Sun, 08 Jul 2012 10:00:25 +0200
parents 71f76c0f235f
children 6432998a8245
files e1000_fix_rdt_set.patch e1000_implement_the_frame_transmission_chunk.patch e1000_initialize_transmission.patch series
diffstat 4 files changed, 322 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/e1000_fix_rdt_set.patch	Sun Jul 08 10:00:25 2012 +0200
@@ -0,0 +1,42 @@
+# HG changeset patch
+# Parent bcab8e474b3aca4c4b326869a05d3ee69e1c82a5
+rathaxes: fix a stupid bug in e1000: the tail index for the rx descriptors ring was improperly set + couple of cosmetics
+
+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
+@@ -49,7 +49,6 @@
+     {
+         chunk   LKM::includes()
+         {
+-
+             static const ${e1000::RxRing}   force_rtx_e1000_rx_ring_decl;
+         }
+ 
+@@ -638,7 +637,7 @@
+             rtx_e1000_register_set32(hw_ctx, E1000_RAH, E1000_RAH_AV);
+ 
+             {
+-                ${Log::info("setup_device: program receieve address done")};
++                ${Log::info("setup_device: receive address programmed")};
+             }
+ 
+             /* 2. Initialize the MTA */
+@@ -668,7 +667,7 @@
+             }
+ 
+             {
+-                ${Log::info("setup_device: descriptors allocated")};
++                ${Log::info("setup_device: rx descriptors allocated")};
+             }
+ 
+             /*
+@@ -716,7 +715,7 @@
+ 
+             /* 6. Setup RDH/RDT */
+             rtx_e1000_register_write32(hw_ctx, E1000_RDH, 0);
+-            rtx_e1000_register_write32(hw_ctx, E1000_RDT, hw_ctx->rx_ring.size - 1);
++            rtx_e1000_register_write32(hw_ctx, E1000_RDT, ${config.rx_ring_size} - 1);
+ 
+             /* 7. Configure the buffer size, XXX: * E1000_RCTL_BSIZE_${config.rx_buffer_len} */
+             rtx_e1000_register_set32(hw_ctx, E1000_RCTL, E1000_RCTL_BSIZE_2048);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/e1000_implement_the_frame_transmission_chunk.patch	Sun Jul 08 10:00:25 2012 +0200
@@ -0,0 +1,74 @@
+# HG changeset patch
+# Parent 1a5a83776de5ecff15e42930c7741f5b4f2ada13
+rathaxes: start to queue up packets in the TX ring on the e1000 sample
+
+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
+@@ -597,7 +597,7 @@
+ 
+         chunk   ::CALL()
+         {
+-            // this is an hack for the scope
++            // See #10
+             (void)1;
+             {
+                 int error;
+@@ -970,4 +970,31 @@
+             }
+         }
+     }
++
++    template sequence   e1000::xmit(Ethernet::Device ctx, Socket::SKBuff skb)
++    {
++        chunk   ::CALL()
++        {
++            /*
++             * Put packets on the TX ring, must return NETDEV_TX_OK or
++             * NETDEV_TX_BUSY.
++             */
++            (void)1; // See #10
++            {
++                ${Log::info("xmit: skbuff details:")};
++            }
++            pr_info(
++                    "\t     len = %-5u data_len = %-5u head_len = %-5u\n"
++                    "\tnr_frags = %u\n"
++                    "\tgso_size = %-5u gso_segs = %-5u gso_type = %-5u\n",
++                    ${skb}->len,
++                    ${skb}->data_len,
++                    skb_headlen(${skb}),
++                    skb_shinfo(${skb})->nr_frags,
++                    skb_shinfo(${skb})->gso_size,
++                    skb_shinfo(${skb})->gso_segs,
++                    skb_shinfo(${skb})->gso_type
++            );
++        }
++    }
+ }
+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
+@@ -70,6 +70,11 @@
+         provided chunk  ::CALL();
+     }
+ 
++    provided sequence   e1000::xmit(Ethernet::Device, Socket::SKBuff)
++    {
++        provided chunk  ::CALL();
++    }
++
+     provided sequence   e1000::register_read32(e1000::Context, e1000::Register)
+     {
+         provided chunk  LKM::prototypes();
+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
+@@ -46,6 +46,7 @@
+     Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb)
+     {
+         Log::info("we have one packet to transmit!");
++        e1000::xmit(dev, skb);
+     }
+ 
+     LKM::init()
--- a/e1000_initialize_transmission.patch	Mon May 21 04:09:23 2012 +0200
+++ b/e1000_initialize_transmission.patch	Sun Jul 08 10:00:25 2012 +0200
@@ -1,5 +1,5 @@
 # HG changeset patch
-# Parent 1328cb41b1bb4d39588c1934c841b3e4362f7413
+# Parent e2e48ad161482555c5e87550e76cf15ef7fdbd3e
 rathaxes: initialize transmission on the e1000 sample:
 
 - This is documented in details in the sections 14.5 and 3.3 of the
@@ -8,32 +8,111 @@
 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
-@@ -34,6 +34,24 @@
-         }
+@@ -34,6 +34,59 @@
      }
  
-+    template type   e1000:TxDescriptor()
+     /*
++     * 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()
 +    {
-+        chunk   LKM:includes()
++        chunk   LKM::includes()
 +        {
-+            typedef int ${e1000:TxDescriptor};
-+
-+            static const ${e1000:TxDescriptor} force_rtx_e1000_tx_descriptor_decl;
++            static const ${e1000::TxDescriptor} force_rtx_e1000_tx_descriptor_decl;
 +        }
 +
 +        chunk   ::decl()
 +        {
 +            typedef struct rtx_e1000_tx_descriptor
 +            {
++                unsigned long int   /* __le64 */    buff_addr;
++                union
++                {
++                    unsigned int    /* __le32 */    data;
++                    struct
++                    {
++                        unsigned short /* __le16 */ length;
++                        unsigned char               csum_offset; /* CSO */
++                        unsigned char               cmd;
++                    }                               fields;
++                }                                   lower;
++                union
++                {
++                    unsigned int    /* __le32 */    data;
++                    struct
++                    {
++                        unsigned char               status;
++                        unsigned char               csum_start; /* CSS */
++                        unsigned short /* __le16 */ special;
++                    }                               fields;
++                }                                   upper;
++            } *rtx_e1000_tx_descriptor_p;
++        }
 +
-+            }
++        chunk   ::init()
++        {
++        }
++
++        map
++        {
 +        }
 +    }
 +
-     /*
++    /*
       * Ring of e1000::RxDescriptors and their corresponding skbuffs.
       *
-@@ -103,6 +121,7 @@
+      * - size: total size of the ring in bytes.
+@@ -73,6 +126,43 @@
+         }
+     }
+ 
++    /*
++     * Ring of e1000::TxDescriptors, this is a bit similar to the Rx ring except
++     * that we don't really have to manage the skbuffs themselves (they are
++     * given to use by the kernel).
++     *
++     * - size: total size of the ring in bytes.
++     * - base: address of the ring (we can't use the typedef here until we get
++     *   CNorm unstrict);
++     * - dma_base: (physical) address of the ring where the device can access
++     *   the different descriptors.
++     */
++    template type   e1000::TxRing()
++    {
++        chunk   LKM::includes()
++        {
++            static const ${e1000::TxRing}   force_rtx_e1000_tx_ring_decl;
++        }
++
++        chunk   ::decl()
++        {
++            struct rtx_e1000_tx_ring
++            {
++                unsigned int                    size;
++                struct rtx_e1000_tx_descriptor  *base;
++                void*   /* dma_addr_t */        dma_base;
++            };
++        }
++
++        chunk   ::init()
++        {
++        }
++
++        map
++        {
++        }
++    }
++
+     template type   e1000::Context()
+     {
+         chunk   LKM::includes()
+@@ -99,6 +189,7 @@
  
                  /* we can't use the Rathaxes type here (#8) */
                  struct rtx_e1000_rx_ring    rx_ring;
@@ -41,7 +120,36 @@
              } *rtx_e1000_ctx_p;
          }
  
-@@ -736,6 +755,20 @@
+@@ -139,6 +230,7 @@
+                 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 */
+@@ -148,6 +240,11 @@
+                 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 */
+             };
+         }
+ 
+@@ -226,6 +323,8 @@
+                 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 */
+             };
+         }
+ 
+@@ -728,11 +827,64 @@
              }
  
              /*
@@ -56,9 +164,93 @@
 +             *    transmitter.
 +             */
 +
++            /*
++             * XXX: at this point we must be careful to not fuck up with i, or
++             * we are going go have surprises in `err_skbuffs_alloc`. Maybe it's
++             * time to separate the rx and tx initialization in two functions.
++             */
++
 +            /* 1. Allocate the tx ring */
++            hw_ctx->tx_ring.size = ${config.tx_ring_size} * sizeof(*hw_ctx->tx_ring.base);
++            hw_ctx->tx_ring.size = ALIGN(hw_ctx->tx_ring.size, 4096);
++            hw_ctx->tx_ring.base = dma_alloc_coherent(
++                    &${ctx}->pci_dev->dev,
++                    hw_ctx->tx_ring.size,
++                    (dma_addr_t *)&hw_ctx->tx_ring.dma_base,
++                    GFP_KERNEL);
++            if (!hw_ctx->rx_ring.base)
++            {
++                ${Log::info("cannot allocate the descriptors for the tx ring")};
++                goto err_tx_ring_alloc;
++            }
++
++            {
++                ${Log::info("setup_device: tx descriptors allocated")};
++            }
++
++            /* 2. Save the emplacement and the size of the ring in TDBA/TDLEN */
++            rtx_e1000_register_write32(hw_ctx, E1000_TDBAL, (dma_addr_t)hw_ctx->tx_ring.dma_base & 0xffffffff);
++            rtx_e1000_register_write32(hw_ctx, E1000_TDBAH, (dma_addr_t)hw_ctx->tx_ring.dma_base >> 32);
++            rtx_e1000_register_write32(hw_ctx, E1000_TDLEN, hw_ctx->tx_ring.size);
++
++            /* 3. Setup TDH/TDT to zero: the queue is empty */
++            rtx_e1000_register_write32(hw_ctx, E1000_TDH, 0);
++            rtx_e1000_register_write32(hw_ctx, E1000_TDT, 0);
++
++            /* 4. Set TCTL.PSP and enable the transmitter */
++            rtx_e1000_register_set32(hw_ctx, E1000_TCTL, E1000_TCTL_PSP|E1000_TCTL_PSP);
++
++            {
++                ${Log::info("transmit registers configured and transmitter enabled")};
++            }
 +
 +            /*
               * XXX: We can't return here since we are not in a function but in
               * a chunk of code (injected in a function).
               */
+             goto ok;
+ 
++        err_tx_ring_alloc:
+             /*
+              * Likewise, always the same problem with error handling, we don't
+              * know where we are at in the "parent context":
+@@ -788,6 +940,15 @@
+                 ${Log::info("free_rx_tx: rx ring free'ed")};
+             }
+ 
++            /*
++             * Free the tx ring:
++             * - Free the descriptors array.
++             */
++            dma_free_coherent(&${ctx}->pci_dev->dev, hw_ctx->tx_ring.size,
++                    hw_ctx->tx_ring.base, (dma_addr_t)hw_ctx->tx_ring.dma_base);
++            {
++                ${Log::info("free_rx_tx: tx ring free'ed")};
++            }
+         }
+     }
+ 
+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
+@@ -2,7 +2,9 @@
+ {
+     provided type   e1000::Context;
+     provided type   e1000::RxDescriptor;
++    provided type   e1000::TxDescriptor;
+     provided type   e1000::RxRing;
++    provided type   e1000::TxRing;
+ 
+     /*
+      * These two types should actually be registers definitions in the frontend:
+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
+@@ -73,6 +73,7 @@
+     Ethernet::ifname = "rtx%d";
+ 
+     e1000::rx_ring_size = 256; /* Number of incoming packets we can buffer */
++    e1000::tx_ring_size = 256; /* Mumber of buffers we can have in the tx queue */
+     /*
+      * The e1000 supports seven receive buffer sizes: 256, 512, 1024, 2048,
+      * 4096, 8192 and 16384 bytes:
--- a/series	Mon May 21 04:09:23 2012 +0200
+++ b/series	Sun Jul 08 10:00:25 2012 +0200
@@ -1,1 +1,3 @@
+e1000_fix_rdt_set.patch
 e1000_initialize_transmission.patch
+e1000_implement_the_frame_transmission_chunk.patch