Commit fd1a461e authored by Jeb J. Cramer's avatar Jeb J. Cramer Committed by Jeff Garzik

[E1000] Perform single PCI read per interrupt

* ISR cleanup; performing single PCI read
parent 35d75fa0
...@@ -1920,82 +1920,45 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) ...@@ -1920,82 +1920,45 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
{ {
struct net_device *netdev = data; struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev->priv; struct e1000_adapter *adapter = netdev->priv;
uint32_t icr = E1000_READ_REG(&adapter->hw, ICR);
#ifdef CONFIG_E1000_NAPI int i;
if (netif_rx_schedule_prep(netdev)) {
/* Disable interrupts and enable polling */
atomic_inc(&adapter->irq_sem);
E1000_WRITE_REG(&adapter->hw, IMC, ~0);
E1000_WRITE_FLUSH(&adapter->hw);
__netif_rx_schedule(netdev);
}
#else
uint32_t icr;
int i = E1000_MAX_INTR;
while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
adapter->hw.get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
}
e1000_clean_rx_irq(adapter); if(!icr)
e1000_clean_tx_irq(adapter); return; /* Not our interrupt */
i--;
if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
adapter->hw.get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
} }
#endif
}
#ifdef CONFIG_E1000_NAPI for(i = 0; i < E1000_MAX_INTR; i++)
static int if(!e1000_clean_rx_irq(adapter) &&
e1000_process_intr(struct net_device *netdev) !e1000_clean_tx_irq(adapter))
{
struct e1000_adapter *adapter = netdev->priv;
uint32_t icr;
int i = E1000_MAX_INTR;
int hasReceived = 0;
while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
if (icr & E1000_ICR_RXT0)
hasReceived = 1;
if (!(icr & ~(E1000_ICR_RXT0)))
break; break;
if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
adapter->hw.get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
}
e1000_clean_tx_irq(adapter);
i--;
}
return hasReceived;
} }
#endif
/** /**
* e1000_clean_tx_irq - Reclaim resources after transmit completes * e1000_clean_tx_irq - Reclaim resources after transmit completes
* @adapter: board private structure * @adapter: board private structure
**/ **/
static void static boolean_t
e1000_clean_tx_irq(struct e1000_adapter *adapter) e1000_clean_tx_irq(struct e1000_adapter *adapter)
{ {
struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
struct e1000_tx_desc *tx_desc; struct e1000_tx_desc *tx_desc;
int i; int i, cleaned = FALSE;
i = tx_ring->next_to_clean; i = tx_ring->next_to_clean;
tx_desc = E1000_TX_DESC(*tx_ring, i); tx_desc = E1000_TX_DESC(*tx_ring, i);
while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
cleaned = TRUE;
if(tx_ring->buffer_info[i].dma) { if(tx_ring->buffer_info[i].dma) {
pci_unmap_page(pdev, pci_unmap_page(pdev,
...@@ -2021,149 +1984,18 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) ...@@ -2021,149 +1984,18 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->next_to_clean = i; tx_ring->next_to_clean = i;
if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) && if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
(E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
netif_wake_queue(netdev); netif_wake_queue(netdev);
}
}
#ifdef CONFIG_E1000_NAPI
static int
e1000_poll(struct net_device *netdev, int *budget)
{
struct e1000_adapter *adapter = netdev->priv;
struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
struct sk_buff *skb;
unsigned long flags;
uint32_t length;
uint8_t last_byte;
int i;
int received = 0;
int rx_work_limit = *budget;
if(rx_work_limit > netdev->quota)
rx_work_limit = netdev->quota;
e1000_process_intr(netdev);
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i);
while(rx_desc->status & E1000_RXD_STAT_DD) {
if(--rx_work_limit < 0)
goto not_done;
pci_unmap_single(pdev,
rx_ring->buffer_info[i].dma,
rx_ring->buffer_info[i].length,
PCI_DMA_FROMDEVICE);
skb = rx_ring->buffer_info[i].skb;
length = le16_to_cpu(rx_desc->length);
if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
/* All receives must fit into a single buffer */
E1000_DBG("Receive packet consumed multiple buffers\n");
dev_kfree_skb_irq(skb);
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
continue;
}
if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
last_byte = *(skb->data + length - 1);
if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
rx_desc->errors, length, last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
e1000_tbi_adjust_stats(&adapter->hw,
&adapter->stats,
length, skb->data);
spin_unlock_irqrestore(&adapter->stats_lock,
flags);
length--;
} else {
dev_kfree_skb_irq(skb);
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
continue;
}
}
/* Good Receive */
skb_put(skb, length - ETHERNET_FCS_SIZE);
/* Receive Checksum Offload */
e1000_rx_checksum(adapter, rx_desc, skb);
skb->protocol = eth_type_trans(skb, netdev);
if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
vlan_hwaccel_rx(skb, adapter->vlgrp,
(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
} else {
netif_receive_skb(skb);
}
netdev->last_rx = jiffies;
rx_desc->status = 0;
rx_ring->buffer_info[i].skb = NULL;
i = (i + 1) % rx_ring->count; return cleaned;
rx_desc = E1000_RX_DESC(*rx_ring, i);
received++;
}
if(!received)
received = 1;
e1000_alloc_rx_buffers(adapter);
rx_ring->next_to_clean = i;
netdev->quota -= received;
*budget -= received;
netif_rx_complete(netdev);
e1000_irq_enable(adapter);
return 0;
not_done:
e1000_alloc_rx_buffers(adapter);
rx_ring->next_to_clean = i;
netdev->quota -= received;
*budget -= received;
return 1;
} }
#else
/** /**
* e1000_clean_rx_irq - Send received data up the network stack, * e1000_clean_rx_irq - Send received data up the network stack,
* @adapter: board private structure * @adapter: board private structure
**/ **/
static void static boolean_t
e1000_clean_rx_irq(struct e1000_adapter *adapter) e1000_clean_rx_irq(struct e1000_adapter *adapter)
{ {
struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
...@@ -2174,13 +2006,15 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) ...@@ -2174,13 +2006,15 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
unsigned long flags; unsigned long flags;
uint32_t length; uint32_t length;
uint8_t last_byte; uint8_t last_byte;
int i; int i, cleaned = FALSE;
i = rx_ring->next_to_clean; i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC(*rx_ring, i); rx_desc = E1000_RX_DESC(*rx_ring, i);
while(rx_desc->status & E1000_RXD_STAT_DD) { while(rx_desc->status & E1000_RXD_STAT_DD) {
cleaned = TRUE;
pci_unmap_single(pdev, pci_unmap_single(pdev,
rx_ring->buffer_info[i].dma, rx_ring->buffer_info[i].dma,
rx_ring->buffer_info[i].length, rx_ring->buffer_info[i].length,
...@@ -2260,8 +2094,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) ...@@ -2260,8 +2094,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_ring->next_to_clean = i; rx_ring->next_to_clean = i;
e1000_alloc_rx_buffers(adapter); e1000_alloc_rx_buffers(adapter);
return cleaned;
} }
#endif
/** /**
* e1000_alloc_rx_buffers - Replace used receive buffers * e1000_alloc_rx_buffers - Replace used receive buffers
......
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