Commit a8ea92e8 authored by Scott Feldman's avatar Scott Feldman Committed by Jeff Garzik

e1000 net driver updates 2/4:

* Bug fix: detect-for-hang mechanism was getting fooled by
false-positives: fixed.
* Removed unnecessary tx_lock from driver, decreasing CPU utilization
under heavy UDP load.
parent 8a76ddc0
...@@ -155,6 +155,7 @@ struct e1000_buffer { ...@@ -155,6 +155,7 @@ struct e1000_buffer {
struct sk_buff *skb; struct sk_buff *skb;
uint64_t dma; uint64_t dma;
unsigned long length; unsigned long length;
unsigned long time_stamp;
}; };
struct e1000_desc_ring { struct e1000_desc_ring {
...@@ -210,8 +211,6 @@ struct e1000_adapter { ...@@ -210,8 +211,6 @@ struct e1000_adapter {
/* TX */ /* TX */
struct e1000_desc_ring tx_ring; struct e1000_desc_ring tx_ring;
unsigned long trans_finish;
spinlock_t tx_lock;
uint32_t txd_cmd; uint32_t txd_cmd;
int max_data_per_txd; int max_data_per_txd;
......
...@@ -592,7 +592,6 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -592,7 +592,6 @@ e1000_sw_init(struct e1000_adapter *adapter)
hw->adaptive_ifs = TRUE; hw->adaptive_ifs = TRUE;
atomic_set(&adapter->irq_sem, 1); atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->tx_lock);
spin_lock_init(&adapter->stats_lock); spin_lock_init(&adapter->stats_lock);
} }
...@@ -717,7 +716,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) ...@@ -717,7 +716,7 @@ e1000_configure_tx(struct e1000_adapter *adapter)
uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
uint32_t tctl, tipg; uint32_t tctl, tipg;
E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000FFFFFFFF)); E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32)); E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen); E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
...@@ -754,7 +753,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) ...@@ -754,7 +753,7 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tctl = E1000_READ_REG(&adapter->hw, TCTL); tctl = E1000_READ_REG(&adapter->hw, TCTL);
tctl &= ~E1000_TCTL_CT; tctl &= ~E1000_TCTL_CT;
tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
...@@ -877,7 +876,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) ...@@ -877,7 +876,7 @@ e1000_configure_rx(struct e1000_adapter *adapter)
/* set the Receive Delay Timer Register */ /* set the Receive Delay Timer Register */
if(adapter->hw.mac_type == e1000_82540) { if(adapter->hw.mac_type >= e1000_82540) {
E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay); E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay);
E1000_WRITE_REG(&adapter->hw, RDTR, 64); E1000_WRITE_REG(&adapter->hw, RDTR, 64);
...@@ -893,7 +892,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) ...@@ -893,7 +892,7 @@ e1000_configure_rx(struct e1000_adapter *adapter)
/* Setup the Base and Length of the Rx Descriptor Ring */ /* Setup the Base and Length of the Rx Descriptor Ring */
E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000FFFFFFFF)); E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32)); E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen); E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
...@@ -1214,6 +1213,8 @@ e1000_watchdog(unsigned long data) ...@@ -1214,6 +1213,8 @@ e1000_watchdog(unsigned long data)
{ {
struct e1000_adapter *adapter = (struct e1000_adapter *) data; struct e1000_adapter *adapter = (struct e1000_adapter *) data;
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct e1000_desc_ring *txdr = &adapter->tx_ring;
int i;
e1000_check_for_link(&adapter->hw); e1000_check_for_link(&adapter->hw);
...@@ -1230,7 +1231,6 @@ e1000_watchdog(unsigned long data) ...@@ -1230,7 +1231,6 @@ e1000_watchdog(unsigned long data)
"Full Duplex" : "Half Duplex"); "Full Duplex" : "Half Duplex");
netif_carrier_on(netdev); netif_carrier_on(netdev);
adapter->trans_finish = jiffies;
netif_wake_queue(netdev); netif_wake_queue(netdev);
mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
} }
...@@ -1250,6 +1250,13 @@ e1000_watchdog(unsigned long data) ...@@ -1250,6 +1250,13 @@ e1000_watchdog(unsigned long data)
e1000_update_stats(adapter); e1000_update_stats(adapter);
e1000_update_adaptive(&adapter->hw); e1000_update_adaptive(&adapter->hw);
/* Early detection of hung controller */
i = txdr->next_to_clean;
if(txdr->buffer_info[i].dma &&
time_after(jiffies, txdr->buffer_info[i].time_stamp + HZ) &&
!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
netif_stop_queue(netdev);
/* Reset the timer */ /* Reset the timer */
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
} }
...@@ -1312,6 +1319,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) ...@@ -1312,6 +1319,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
skb->data + offset, skb->data + offset,
size, size,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
tx_ring->buffer_info[i].time_stamp = jiffies;
len -= size; len -= size;
offset += size; offset += size;
...@@ -1390,20 +1398,11 @@ static int ...@@ -1390,20 +1398,11 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{ {
struct e1000_adapter *adapter = netdev->priv; struct e1000_adapter *adapter = netdev->priv;
unsigned long flags;
int tx_flags = 0, count; int tx_flags = 0, count;
int f; int f;
if(time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) {
adapter->trans_finish = jiffies;
netif_stop_queue(netdev);
return 1;
}
count = TXD_USE_COUNT(skb->len - skb->data_len, count = TXD_USE_COUNT(skb->len - skb->data_len,
adapter->max_data_per_txd); adapter->max_data_per_txd);
for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
...@@ -1412,14 +1411,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ...@@ -1412,14 +1411,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(skb->ip_summed == CHECKSUM_HW) if(skb->ip_summed == CHECKSUM_HW)
count++; count++;
spin_lock_irqsave(&adapter->tx_lock, flags);
e1000_clean_tx_irq(adapter);
if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) { if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
netif_stop_queue(netdev); netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->tx_lock, flags);
return 1; return 1;
} }
spin_unlock_irqrestore(&adapter->tx_lock, flags);
if(e1000_tx_csum(adapter, skb)) if(e1000_tx_csum(adapter, skb))
tx_flags |= E1000_TX_FLAGS_CSUM; tx_flags |= E1000_TX_FLAGS_CSUM;
...@@ -1430,7 +1425,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ...@@ -1430,7 +1425,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
} }
#endif #endif
count = e1000_tx_map(adapter, skb); count = e1000_tx_map(adapter, skb);
e1000_tx_queue(adapter, count, tx_flags); e1000_tx_queue(adapter, count, tx_flags);
...@@ -1703,12 +1698,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) ...@@ -1703,12 +1698,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
} }
e1000_clean_rx_irq(adapter); e1000_clean_rx_irq(adapter);
e1000_clean_tx_irq(adapter);
if((icr & E1000_ICR_TXDW) && spin_trylock(&adapter->tx_lock)) {
e1000_clean_tx_irq(adapter);
spin_unlock(&adapter->tx_lock);
}
i--; i--;
} }
...@@ -1755,8 +1745,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) ...@@ -1755,8 +1745,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
i = (i + 1) % tx_ring->count; i = (i + 1) % tx_ring->count;
tx_desc = E1000_TX_DESC(*tx_ring, i); tx_desc = E1000_TX_DESC(*tx_ring, i);
adapter->trans_finish = jiffies;
} }
tx_ring->next_to_clean = i; tx_ring->next_to_clean = i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment