view e1000_initialize_transmission.patch @ 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
line wrap: on
line source

# HG changeset patch
# Parent e2e48ad161482555c5e87550e76cf15ef7fdbd3e
rathaxes: initialize transmission on the e1000 sample:

- This is documented in details in the sections 14.5 and 3.3 of the
  Intel Gigabit Controller Software Developer manual.

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,59 @@
     }
 
     /*
+     * 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()
+        {
+            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.
      *
      * - 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;
+                struct rtx_e1000_tx_ring    tx_ring;
             } *rtx_e1000_ctx_p;
         }
 
@@ -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 @@
             }
 
             /*
+             * Transmission initialization (section 14.5):
+             *
+             * 1. Allocate the transmit descriptors ring and map it to make it
+             *    accessible by the device;
+             * 2. Write the start address of the ring in TDBAL/TDBAH and set
+             *    TDLEN to the size of the ring;
+             * 3. Set the TDH/TDT indexes to the beginning and end of the ring;
+             * 4. Set TCTL.PSP to pad short packets and TCTL.EN to enable the
+             *    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: