aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Brandeburg <jesse.brandeburg@intel.com>2006-11-01 11:48:10 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-02 00:12:00 -0500
commit9ac98284428961bd5be285a6cc1f5e6f5b6644aa (patch)
treee32ace513de471df3e552a3dc53fc64510b5f07c
parent04fedbfbc3dac1158519f8ef8cc8aca4fe79695b (diff)
e1000: add dynamic generic MSI interrupt routine
Add a generic MSI interrupt routine that is IO read-free, speeding up MSI interrupt handling. Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
-rw-r--r--drivers/net/e1000/e1000_main.c90
1 files changed, 88 insertions, 2 deletions
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index fe22ae8f0a3d..35e4e32c7702 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -157,6 +157,9 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
157static int e1000_change_mtu(struct net_device *netdev, int new_mtu); 157static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
158static int e1000_set_mac(struct net_device *netdev, void *p); 158static int e1000_set_mac(struct net_device *netdev, void *p);
159static irqreturn_t e1000_intr(int irq, void *data); 159static irqreturn_t e1000_intr(int irq, void *data);
160#ifdef CONFIG_PCI_MSI
161static irqreturn_t e1000_intr_msi(int irq, void *data);
162#endif
160static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, 163static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
161 struct e1000_tx_ring *tx_ring); 164 struct e1000_tx_ring *tx_ring);
162#ifdef CONFIG_E1000_NAPI 165#ifdef CONFIG_E1000_NAPI
@@ -288,7 +291,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
288 291
289 flags = IRQF_SHARED; 292 flags = IRQF_SHARED;
290#ifdef CONFIG_PCI_MSI 293#ifdef CONFIG_PCI_MSI
291 if (adapter->hw.mac_type > e1000_82547_rev_2) { 294 if (adapter->hw.mac_type >= e1000_82571) {
292 adapter->have_msi = TRUE; 295 adapter->have_msi = TRUE;
293 if ((err = pci_enable_msi(adapter->pdev))) { 296 if ((err = pci_enable_msi(adapter->pdev))) {
294 DPRINTK(PROBE, ERR, 297 DPRINTK(PROBE, ERR,
@@ -296,8 +299,14 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
296 adapter->have_msi = FALSE; 299 adapter->have_msi = FALSE;
297 } 300 }
298 } 301 }
299 if (adapter->have_msi) 302 if (adapter->have_msi) {
300 flags &= ~IRQF_SHARED; 303 flags &= ~IRQF_SHARED;
304 err = request_irq(adapter->pdev->irq, &e1000_intr_msi, flags,
305 netdev->name, netdev);
306 if (err)
307 DPRINTK(PROBE, ERR,
308 "Unable to allocate interrupt Error: %d\n", err);
309 } else
301#endif 310#endif
302 if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags, 311 if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags,
303 netdev->name, netdev))) 312 netdev->name, netdev)))
@@ -3466,6 +3475,83 @@ e1000_update_stats(struct e1000_adapter *adapter)
3466 3475
3467 spin_unlock_irqrestore(&adapter->stats_lock, flags); 3476 spin_unlock_irqrestore(&adapter->stats_lock, flags);
3468} 3477}
3478#ifdef CONFIG_PCI_MSI
3479
3480/**
3481 * e1000_intr_msi - Interrupt Handler
3482 * @irq: interrupt number
3483 * @data: pointer to a network interface device structure
3484 **/
3485
3486static
3487irqreturn_t e1000_intr_msi(int irq, void *data)
3488{
3489 struct net_device *netdev = data;
3490 struct e1000_adapter *adapter = netdev_priv(netdev);
3491 struct e1000_hw *hw = &adapter->hw;
3492#ifndef CONFIG_E1000_NAPI
3493 int i;
3494#endif
3495
3496 /* this code avoids the read of ICR but has to get 1000 interrupts
3497 * at every link change event before it will notice the change */
3498 if (++adapter->detect_link >= 1000) {
3499 uint32_t icr = E1000_READ_REG(hw, ICR);
3500#ifdef CONFIG_E1000_NAPI
3501 /* read ICR disables interrupts using IAM, so keep up with our
3502 * enable/disable accounting */
3503 atomic_inc(&adapter->irq_sem);
3504#endif
3505 adapter->detect_link = 0;
3506 if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
3507 (icr & E1000_ICR_INT_ASSERTED)) {
3508 hw->get_link_status = 1;
3509 /* 80003ES2LAN workaround--
3510 * For packet buffer work-around on link down event;
3511 * disable receives here in the ISR and
3512 * reset adapter in watchdog
3513 */
3514 if (netif_carrier_ok(netdev) &&
3515 (adapter->hw.mac_type == e1000_80003es2lan)) {
3516 /* disable receives */
3517 uint32_t rctl = E1000_READ_REG(hw, RCTL);
3518 E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
3519 }
3520 /* guard against interrupt when we're going down */
3521 if (!test_bit(__E1000_DOWN, &adapter->flags))
3522 mod_timer(&adapter->watchdog_timer,
3523 jiffies + 1);
3524 }
3525 } else {
3526 E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
3527 E1000_ICR_LSC)));
3528 /* bummer we have to flush here, but things break otherwise as
3529 * some event appears to be lost or delayed and throughput
3530 * drops. In almost all tests this flush is un-necessary */
3531 E1000_WRITE_FLUSH(hw);
3532#ifdef CONFIG_E1000_NAPI
3533 /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
3534 * masked. No need for the IMC write, but it does mean we
3535 * should account for it ASAP. */
3536 atomic_inc(&adapter->irq_sem);
3537#endif
3538 }
3539
3540#ifdef CONFIG_E1000_NAPI
3541 if (likely(netif_rx_schedule_prep(netdev)))
3542 __netif_rx_schedule(netdev);
3543 else
3544 e1000_irq_enable(adapter);
3545#else
3546 for (i = 0; i < E1000_MAX_INTR; i++)
3547 if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
3548 !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
3549 break;
3550#endif
3551
3552 return IRQ_HANDLED;
3553}
3554#endif
3469 3555
3470/** 3556/**
3471 * e1000_intr - Interrupt Handler 3557 * e1000_intr - Interrupt Handler