When configuring the rx part of the interface, the e1000_main.c module enables receive on the adapter before it has initialised the buffer addresses. The resulting race with the arrival of the first packet can lead to the adapter and the driver having different ideas about where the next packet is meant to go, resulting in the failure of the network to function.

In practice, the window is narrow, and this may rarely if ever cause problems with real hardware. However VirtualBox is capable of delivering a packet from the virtual adapter is soon as receive is enabled, and this does indeed cause the network to fail to work. The situation arises if there are broadcast packets in the host network near the time when receive is enabled.

I propose the following patch to address the condition. It moves the task of initialising the buffers (done in two places) to the e1000_configure_rx function where it can be done before received is enabled. I have confirmed that this corrects the problem with VirtualBox, but I do not have the required hardware to test it in a non-virtualised environment.

--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -389,7 +389,6 @@ static void e1000_release_manageability(struct e1000_adapter *adapter)
 static void e1000_configure(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
-       int i;

        e1000_set_rx_mode(netdev);

@@ -399,15 +398,6 @@ static void e1000_configure(struct e1000_adapter *adapter)
        e1000_configure_tx(adapter);
        e1000_setup_rctl(adapter);
        e1000_configure_rx(adapter);
-       /* call E1000_DESC_UNUSED which always leaves
-        * at least 1 descriptor unused to make sure
-        * next_to_use != next_to_clean
-        */
-       for (i = 0; i < adapter->num_rx_queues; i++) {
-               struct e1000_rx_ring *ring = &adapter->rx_ring[i];
-               adapter->alloc_rx_buf(adapter, ring,
-                                     E1000_DESC_UNUSED(ring));
-       }
 }

 int e1000_up(struct e1000_adapter *adapter)
@@ -1860,6 +1850,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
        u64 rdba;
        struct e1000_hw *hw = &adapter->hw;
        u32 rdlen, rctl, rxcsum;
+       int i;

        if (adapter->netdev->mtu > ETH_DATA_LEN) {
                rdlen = adapter->rx_ring[0].count *
@@ -1916,6 +1907,16 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
                ew32(RXCSUM, rxcsum);
        }

+       /* call E1000_DESC_UNUSED which always leaves
+        * at least 1 descriptor unused to make sure
+        * next_to_use != next_to_clean
+        */
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct e1000_rx_ring *ring = &adapter->rx_ring[i];
+               adapter->alloc_rx_buf(adapter, ring,
+                                     E1000_DESC_UNUSED(ring));
+       }
+
        /* Enable Receives */
        ew32(RCTL, rctl | E1000_RCTL_EN);
 }
@@ -2187,10 +2188,7 @@ static void e1000_leave_82542_rst(struct e1000_adapter *adapter)
                e1000_pci_set_mwi(hw);

        if (netif_running(netdev)) {
-               /* No need to loop, because 82542 supports only 1 queue */
-               struct e1000_rx_ring *ring = &adapter->rx_ring[0];
                e1000_configure_rx(adapter);
-               adapter->alloc_rx_buf(adapter, ring, E1000_DESC_UNUSED(ring));
        }
 }

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit 
http://communities.intel.com/community/wired

Reply via email to