diff options
author | Jesse Brandeburg <jesse.brandeburg@intel.com> | 2006-11-01 11:48:10 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-02 00:12:00 -0500 |
commit | 9ac98284428961bd5be285a6cc1f5e6f5b6644aa (patch) | |
tree | e32ace513de471df3e552a3dc53fc64510b5f07c /drivers/net/e1000/e1000_main.c | |
parent | 04fedbfbc3dac1158519f8ef8cc8aca4fe79695b (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>
Diffstat (limited to 'drivers/net/e1000/e1000_main.c')
-rw-r--r-- | drivers/net/e1000/e1000_main.c | 90 |
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); | |||
157 | static int e1000_change_mtu(struct net_device *netdev, int new_mtu); | 157 | static int e1000_change_mtu(struct net_device *netdev, int new_mtu); |
158 | static int e1000_set_mac(struct net_device *netdev, void *p); | 158 | static int e1000_set_mac(struct net_device *netdev, void *p); |
159 | static irqreturn_t e1000_intr(int irq, void *data); | 159 | static irqreturn_t e1000_intr(int irq, void *data); |
160 | #ifdef CONFIG_PCI_MSI | ||
161 | static irqreturn_t e1000_intr_msi(int irq, void *data); | ||
162 | #endif | ||
160 | static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter, | 163 | static 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 | |||
3486 | static | ||
3487 | irqreturn_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 |