e1000: adding final extensions for the I350 support.
authorReto Achermann <acreto@student.ethz.ch>
Mon, 25 Aug 2014 12:44:41 +0000 (14:44 +0200)
committerReto Achermann <acreto@student.ethz.ch>
Mon, 25 Aug 2014 12:44:41 +0000 (14:44 +0200)
devices/e1000.dev
usr/drivers/e1000/e1000n.c
usr/drivers/e1000/e1000n.h
usr/drivers/e1000/e1000n_hwinit.c

index 2c5b4f0..b9b6fc1 100644 (file)
@@ -114,12 +114,31 @@ device e1000 lsbfirst ( addr base ) "Intel e1000 Gigabit Ethernet" {
     bus64      1 "PCI Bus Width indication";
     pcix_mode   1 "PCI-X Mode indication";
     pcixspd     2 "PCI-X Bus Speed Indication";
-    _          3 mbz;
+    _          3 mbz;   
     gio_mes     1 "GIO master enable status";
     dev_rst_set 1 "Device reset set";
     pf_rst_done 1 "Software Rest or device reset completed";
     _          10 mbz;
   };
+  
+  register status_I350 rw also addr(base, 0x0008) "Device status" {
+    fd          1 "Link full duplex configuration";
+    lu          1 "Link up";
+    lan_id      2 "Function ID";
+    txoff       1 "Transmission paused";
+    _           1 mbz;
+    speed       2 type(linkspeed) "Link speed setting";
+    asdv        2 type(linkspeed) "Auto speed detection value";
+    phyra       1 "PHY reset asserted"; 
+    _           3  mbz;
+    nvf         4 "Num VFs in the IOV capability s";
+    vfe         1 "VF enable (VFE) bit in the IOV capability";
+    gio_mes     1 "GIO master enable status";
+    dev_rst_set 1 "Device reset set";
+    pf_rst_done 1 "Software Rest or device reset completed";
+    _           9 mbz;
+    mac_gate    1 "MAC clock gating Enable";
+  };
 
   // 13.3.3
   constants flashenable "Flash write enable control" {
@@ -756,6 +775,18 @@ device e1000 lsbfirst ( addr base ) "Intel e1000 Gigabit Ethernet" {
     exsten     1 "Extended status enable";
     _          16 mbz;
   };
+  
+  regarray srrctl rw addr(base, 0xC00C)[8; 0x40] "Split and Replication Receive Control" {
+    bsizepacket  7 "Receive Buffer Size for Packet Buffer, The value is in 1 KB resolution.";
+    dmacq_dis    1 "DMA Coalescing disable";
+    bsizeheader  6 "Receive Buffer Size for Header Buffer";
+    _            6 mbz;
+    rdmts        5 "Receive Descriptor Minimum Threshold Size";
+    desctype     3 "Defines the descriptor in Rx";
+    _            2 mbz;
+    timestamp    1 "Timestamp Received packet";
+    drop_en      1 "Drop Enabled";
+  };
 
   /************************************
    * Transmit registers
@@ -766,6 +797,7 @@ device e1000 lsbfirst ( addr base ) "Intel e1000 Gigabit Ethernet" {
     cd_half    = 0x200 "512 byte-times";
     cd_full    = 0x3f  "64 byte-times";
     cd_esb     = 0x40  "64 byte-times (for 631xESB/632xESB)";
+    cd_internal =  0x42 "i350 internal phy mode";
   };
   register tctl rw addr(base, 0x400) "Transmit control" {
     _          1 mbz;
@@ -1482,5 +1514,15 @@ device e1000 lsbfirst ( addr base ) "Intel e1000 Gigabit Ethernet" {
       ipv6     = 0x5 "IPv6 hash";
   };
 
+ /************************************
+  * Virtualization Registers
+  ***********************************/
+  register txswc rw addr(base, 0x5ACC) {
+    macas       8 "Enable anti spoofing filter on MAC addresses";
+    vlanas      8 "Enable anti spoofing filter on VLAN tags";
+    lle         8 "Local loopback enable";
+    _           7 mbz;
+    loopback_en 1 "Enable VMDQ loopback.";
+   };
 
 };
index 098e472..85b3f89 100644 (file)
@@ -297,12 +297,26 @@ static bool handle_free_TX_slot_fn(void)
     e1000_dqval_t dqval = 0;
     struct tx_desc tdesc;
 
+    /*
+     * XXX: we should move on to non-legacy descriptors for the newer
+     *      devices at some point:
+     *
+     *      These descriptors should not be used when advanced features such as
+     *      virtualization are used. If legacy descriptors are used when
+     *      virtualization is enabled such as when TXSWC.Loopback enable or
+     *      STATUS.VFE or one of the TXSWC.MACAS bits or one of the TXSWC.VLANAS
+     *      bits are set, the packets are ignored and not sent.
+     */
     tdesc.buffer_address = buffer_address;
     tdesc.ctrl.raw = 0;
+#if E1000_USE_LEGACY_DESC
     tdesc.ctrl.legacy.data_len = packet_len;
     tdesc.ctrl.legacy.cmd.d.rs = 1;
     tdesc.ctrl.legacy.cmd.d.ifcs = 1;
     tdesc.ctrl.legacy.cmd.d.eop = (last ? 1 : 0);
+#else
+    assert(!"advanced descriptors not implemented yet.");
+#endif
 
     /* FIXME: the packet should be copied into separate location, so that
      * application can't temper with it. */
@@ -679,12 +693,8 @@ static void e1000_init_fn(struct device_mem *bar_info, int nr_allocated_bars)
 
 #ifndef LIBRARY
     ethersrv_init(global_service_name, assumed_queue_id, get_mac_address_fn,
-                 NULL,
-                  transmit_pbuf_list_fn,
-                  find_tx_free_slot_count_fn,
-                  handle_free_TX_slot_fn,
-                  receive_buffer_size,
-                  rx_register_buffer_fn,
+                  NULL, transmit_pbuf_list_fn, find_tx_free_slot_count_fn,
+                  handle_free_TX_slot_fn, receive_buffer_size,rx_register_buffer_fn,
                   rx_find_free_slot_count_fn);
 #else
     ethernetif_backend_init(global_service_name, assumed_queue_id, get_mac_address_fn,
index d754470..ef3eb05 100644 (file)
@@ -24,7 +24,7 @@
 #define E1000_PRINT(fmt, ...)        printf(DRIVER_STRING fmt, ##__VA_ARGS__)
 #define E1000_PRINT_ERROR(fmt, ...)  fprintf(stderr, DRIVER_STRING fmt, ##__VA_ARGS__)
 
-
+#define E1000_USE_LEGACY_DESC 1
 /*
  * Global constants
  */
index 19d096b..f083a73 100644 (file)
@@ -241,7 +241,7 @@ static int e1000_reset(e1000_device_t *dev)
         timeout = 1000;
         do {
             usec_delay(10);
-        } while (e1000_status_gio_mes_rdf(dev->device) && 0 < timeout--);
+        } while (e1000_status_I350_gio_mes_rdf(dev->device) && 0 < timeout--);
 
         if (timeout <= 0) {
             E1000_DEBUG("Error: Failed to disable GIO management.\n");
@@ -681,6 +681,21 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
     }
 
     e1000_initialize(dev->device, (void *) bar_info[0].vaddr);
+       
+       /*
+        * XXX: This is a check if we are using legacy descriptors and virtual functions
+        *      are enabled to display an error message and abort execution.
+        */
+    if (dev->mac_type == e1000_I350 && E1000_USE_LEGACY_DESC) {
+        if(e1000_txswc_loopback_en_rdf(dev->device)
+               || e1000_status_I350_vfe_rdf(dev->device)
+               || e1000_txswc_macas_rdf(dev->device)
+               || e1000_txswc_vlanas_rdf(dev->device)) {
+            debug_printf("ERROR: legacy descriptors used with Advanced Features!\n");
+            exit(1);
+        };
+
+    }
 
     E1000_DEBUG("Setting media type.\n");
     e1000_set_media_type(dev);
@@ -816,7 +831,16 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
     }
 
     if (dev->mac_type == e1000_I350) {
+        /* If VLANs are not used, software should clear VFE. */
+        e1000_rctl_vfe_wrf(dev->device, 0);
+
+         /* Set up the MTA (Multicast Table Array) by software. This means
+          * zeroing all entries initially and adding in entries as requested. */
+        for (int i = 0; i < 128; ++i) {
+            e1000_mta_wr(dev->device, i, 0);
+        }
 
+        /*  Software should program RDLEN[n] register only when queue is disabled */
         e1000_rdbal_I350_wr(dev->device, 0, frameid.base & 0xffffffff);
         e1000_rdbah_I350_wr(dev->device, 0, (frameid.base >> 32) & 0xffffffff);
         e1000_rdlen_I350_len_wrf(dev->device, 0, (receive_buffers / 8));
@@ -825,12 +849,22 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
         e1000_rdh_I350_wr(dev->device, 0, 0);
         e1000_rdt_I350_wr(dev->device, 0, 0);
 
-        /*  Software should program RDLEN[n] register only when queue is disabled */
+        /* Program SRRCTL of the queue according to the size of the buffers,
+         * the required header handling and the drop policy. */
+        e1000_srrctl_t srrctl = 0;
+        srrctl = e1000_srrctl_bsizeheader_insert(srrctl, 0);
+        e1000_srrctl_wr(dev->device, 0, srrctl);
+
+        /* Enable the queue by setting RXDCTL.ENABLE. In the case of queue zero,
+         * the enable bit is set by default - so the ring parameters should be
+         * set before RCTL.RXEN is set. */
         e1000_rxdctl_I350_t rxdctl = 0;
         rxdctl = e1000_rxdctl_I350_enable_insert(rxdctl, 1);
         rxdctl = e1000_rxdctl_I350_wthresh_insert(rxdctl, 1);
         e1000_rxdctl_I350_wr(dev->device, 0, rxdctl);
 
+        /* Poll the RXDCTL register until the ENABLE bit is set. The tail should
+         * not be bumped before this bit was read as one. */
         uint16_t timeout = 1000;
         while(!e1000_rxdctl_I350_enable_rdf(dev->device, 0) && timeout--) {
             usec_delay(10);
@@ -838,6 +872,7 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
         if (timeout <= 0) {
             E1000_DEBUG("ERROR: failed to enable the RX queue\n");
         }
+
     } else {
         /* tell card where receive ring is */
         e1000_rdbal_wr(dev->device, 0, frameid.base & 0xffffffff);
@@ -870,9 +905,6 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
     *transmit_ring = alloc_map_frame(VREGION_FLAGS_READ_WRITE_NOCACHE,
                                      sizeof(struct tx_desc) * transmit_buffers, &frame);
 
-    *transmit_ring = alloc_map_frame(VREGION_FLAGS_READ_WRITE_NOCACHE,
-                                     sizeof(union rx_desc) * transmit_buffers, &frame);
-
     if (*transmit_ring == NULL) {
         E1000_PRINT_ERROR("Error: Failed to allocate map frame.\n");
         exit(1);
@@ -892,12 +924,24 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
         e1000_tdh_I350_wr(dev->device, 0, 0);
         e1000_tdt_I350_wr(dev->device, 0, 0);
 
+        /* Program the TXDCTL register with the desired TX descriptor write
+         * back policy. Suggested values are:
+                — WTHRESH = 1b
+                — All other fields 0b.
+         */
         e1000_txdctl_I350_t txdctl = 0;
-        txdctl = e1000_txdctl_I350_enable_insert(txdctl, 1);
         txdctl = e1000_txdctl_I350_priority_insert(txdctl, 1);
         txdctl = e1000_txdctl_I350_wthresh_insert(txdctl, 1);
         e1000_txdctl_I350_wr(dev->device, 0, txdctl);
 
+        /* If needed, set the TDWBAL/TWDBAH to enable head write back */
+        e1000_tdwbal_wr(dev->device, 0, 0);
+        e1000_tdwbah_wr(dev->device, 0, 0);
+
+        /* Enable the queue using TXDCTL.ENABLE (queue zero is enabled by default). */
+        e1000_txdctl_I350_enable_wrf(dev->device, 0, 1);
+
+        /* Poll the TXDCTL register until the ENABLE bit is set. */
         uint16_t timeout = 1000;
         while(!e1000_txdctl_I350_enable_rdf(dev->device, 0) && timeout--) {
             usec_delay(10);
@@ -906,8 +950,6 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
             E1000_DEBUG("ERROR: failed to enable the TX queue\n");
         }
 
-        e1000_tdwbal_wr(dev->device, 0, 0);
-
     } else {
         /* tell card about our transmit ring */
         e1000_tdbal_wr(dev->device, 0, frameid.base & 0xffffffff);
@@ -919,36 +961,39 @@ void e1000_hwinit(e1000_device_t *dev, struct device_mem *bar_info,
     e1000_configure_tx(dev);
 
     /* enable transmit */
-    {
-        e1000_tctl_t tctl = 0;
 
+    e1000_tctl_t tctl = 0;
+    if (dev->mac_type == e1000_I350) {
+        tctl = e1000_tctl_ct_insert(tctl, 0xf);
+    } else {
         tctl = e1000_tctl_ct_insert(tctl, 0x10);
-        tctl = e1000_tctl_en_insert(tctl, 1);
-        tctl = e1000_tctl_psp_insert(tctl, 1);
-        tctl = e1000_tctl_bst_insert(tctl, 0x40);
-        e1000_tctl_wr(dev->device, tctl);
-    }
-
-    /* Enable interrupt throttling rate.
-     *
-     * The optimal performance setting for this register is very system and
-     * configuration specific. A initial suggested range is 651-5580 (28Bh - 15CCh).
-     * The value 0 will disable interrupt throttling
-     */
-    if (dev->mac_type == e1000_82575
-        || dev->mac_type == e1000_82576
-        || dev->mac_type == e1000_I210
-        || dev->mac_type == e1000_I350) {
-        e1000_eitr_interval_wrf(dev->device, 0, 5580);
-        //e1000_eitr_interval_wrf(dev->device, 0, 10);
-    }
-    else {
-        e1000_itr_interval_wrf(dev->device, 5580);
-        //e1000_itr_interval_wrf(dev->device, 10);
     }
+    tctl = e1000_tctl_en_insert(tctl, 1);
+    tctl = e1000_tctl_psp_insert(tctl, 1);
+    tctl = e1000_tctl_bst_insert(tctl, 0x40);
+    e1000_tctl_wr(dev->device, tctl);
 
     /* Enable interrupts */
     if (use_interrupt) {
+
+        /* Enable interrupt throttling rate.
+         *
+         * The optimal performance setting for this register is very system and
+         * configuration specific. A initial suggested range is 651-5580 (28Bh - 15CCh).
+         * The value 0 will disable interrupt throttling
+         */
+        if (dev->mac_type == e1000_82575
+            || dev->mac_type == e1000_82576
+            || dev->mac_type == e1000_I210
+            || dev->mac_type == e1000_I350) {
+            e1000_eitr_interval_wrf(dev->device, 0, 5580);
+            //e1000_eitr_interval_wrf(dev->device, 0, 10);
+        }
+        else {
+            e1000_itr_interval_wrf(dev->device, 5580);
+            //e1000_itr_interval_wrf(dev->device, 10);
+        }
+
         e1000_intreg_t intreg = 0;
 
         intreg = e1000_intreg_lsc_insert(intreg, 1);