aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-03-21 01:28:41 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-21 01:28:41 -0500
commitfcfa0a32c767219c1bdad621ef4a3aff1904cbbd (patch)
tree0b40b3432cc90af0e2b22da056baab173d163d65 /drivers/net
parent9c27dbdf64cba05d0cacc343118a7fd01d4b82f7 (diff)
[TG3]: Add new one-shot MSI handler
Support one-shot MSI on 5787. This one-shot MSI idea is credited to David Miller. In this mode, MSI disables itself automatically after it is generated, saving the driver a register access to disable it for NAPI. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c85
-rw-r--r--drivers/net/tg3.h1
2 files changed, 55 insertions, 31 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 5182a3be7f21..40f52897cf9b 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -546,6 +546,9 @@ static void tg3_enable_ints(struct tg3 *tp)
546 (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); 546 (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
547 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 547 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
548 (tp->last_tag << 24)); 548 (tp->last_tag << 24));
549 if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
550 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
551 (tp->last_tag << 24));
549 tg3_cond_int(tp); 552 tg3_cond_int(tp);
550} 553}
551 554
@@ -3365,6 +3368,23 @@ static inline void tg3_full_unlock(struct tg3 *tp)
3365 spin_unlock_bh(&tp->lock); 3368 spin_unlock_bh(&tp->lock);
3366} 3369}
3367 3370
3371/* One-shot MSI handler - Chip automatically disables interrupt
3372 * after sending MSI so driver doesn't have to do it.
3373 */
3374static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs)
3375{
3376 struct net_device *dev = dev_id;
3377 struct tg3 *tp = netdev_priv(dev);
3378
3379 prefetch(tp->hw_status);
3380 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
3381
3382 if (likely(!tg3_irq_sync(tp)))
3383 netif_rx_schedule(dev); /* schedule NAPI poll */
3384
3385 return IRQ_HANDLED;
3386}
3387
3368/* MSI ISR - No need to check for interrupt sharing and no need to 3388/* MSI ISR - No need to check for interrupt sharing and no need to
3369 * flush status block and interrupt mailbox. PCI ordering rules 3389 * flush status block and interrupt mailbox. PCI ordering rules
3370 * guarantee that MSI will arrive after the status block. 3390 * guarantee that MSI will arrive after the status block.
@@ -6511,6 +6531,26 @@ static void tg3_timer(unsigned long __opaque)
6511 add_timer(&tp->timer); 6531 add_timer(&tp->timer);
6512} 6532}
6513 6533
6534int tg3_request_irq(struct tg3 *tp)
6535{
6536 irqreturn_t (*fn)(int, void *, struct pt_regs *);
6537 unsigned long flags;
6538 struct net_device *dev = tp->dev;
6539
6540 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
6541 fn = tg3_msi;
6542 if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
6543 fn = tg3_msi_1shot;
6544 flags = SA_SAMPLE_RANDOM;
6545 } else {
6546 fn = tg3_interrupt;
6547 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
6548 fn = tg3_interrupt_tagged;
6549 flags = SA_SHIRQ | SA_SAMPLE_RANDOM;
6550 }
6551 return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev));
6552}
6553
6514static int tg3_test_interrupt(struct tg3 *tp) 6554static int tg3_test_interrupt(struct tg3 *tp)
6515{ 6555{
6516 struct net_device *dev = tp->dev; 6556 struct net_device *dev = tp->dev;
@@ -6547,16 +6587,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
6547 6587
6548 free_irq(tp->pdev->irq, dev); 6588 free_irq(tp->pdev->irq, dev);
6549 6589
6550 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) 6590 err = tg3_request_irq(tp);
6551 err = request_irq(tp->pdev->irq, tg3_msi,
6552 SA_SAMPLE_RANDOM, dev->name, dev);
6553 else {
6554 irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
6555 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
6556 fn = tg3_interrupt_tagged;
6557 err = request_irq(tp->pdev->irq, fn,
6558 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
6559 }
6560 6591
6561 if (err) 6592 if (err)
6562 return err; 6593 return err;
@@ -6608,14 +6639,7 @@ static int tg3_test_msi(struct tg3 *tp)
6608 6639
6609 tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; 6640 tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
6610 6641
6611 { 6642 err = tg3_request_irq(tp);
6612 irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
6613 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
6614 fn = tg3_interrupt_tagged;
6615
6616 err = request_irq(tp->pdev->irq, fn,
6617 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
6618 }
6619 if (err) 6643 if (err)
6620 return err; 6644 return err;
6621 6645
@@ -6677,17 +6701,7 @@ static int tg3_open(struct net_device *dev)
6677 tp->tg3_flags2 |= TG3_FLG2_USING_MSI; 6701 tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
6678 } 6702 }
6679 } 6703 }
6680 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) 6704 err = tg3_request_irq(tp);
6681 err = request_irq(tp->pdev->irq, tg3_msi,
6682 SA_SAMPLE_RANDOM, dev->name, dev);
6683 else {
6684 irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
6685 if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
6686 fn = tg3_interrupt_tagged;
6687
6688 err = request_irq(tp->pdev->irq, fn,
6689 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
6690 }
6691 6705
6692 if (err) { 6706 if (err) {
6693 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { 6707 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@@ -6752,6 +6766,14 @@ static int tg3_open(struct net_device *dev)
6752 6766
6753 return err; 6767 return err;
6754 } 6768 }
6769
6770 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
6771 if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
6772 u32 val = tr32(0x7c04);
6773
6774 tw32(0x7c04, val | (1 << 29));
6775 }
6776 }
6755 } 6777 }
6756 6778
6757 tg3_full_lock(tp, 0); 6779 tg3_full_lock(tp, 0);
@@ -9940,9 +9962,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
9940 tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; 9962 tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
9941 9963
9942 if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { 9964 if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
9943 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) 9965 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
9944 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; 9966 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
9945 else 9967 tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
9968 } else
9946 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1; 9969 tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1;
9947 } 9970 }
9948 9971
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index ba3466c8a96d..6b05d5786cd7 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2209,6 +2209,7 @@ struct tg3 {
2209#define TG3_FLG2_5780_CLASS 0x04000000 2209#define TG3_FLG2_5780_CLASS 0x04000000
2210#define TG3_FLG2_HW_TSO_2 0x08000000 2210#define TG3_FLG2_HW_TSO_2 0x08000000
2211#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2) 2211#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2)
2212#define TG3_FLG2_1SHOT_MSI 0x10000000
2212 2213
2213 u32 split_mode_max_reqs; 2214 u32 split_mode_max_reqs;
2214#define SPLIT_MODE_5704_MAX_REQ 3 2215#define SPLIT_MODE_5704_MAX_REQ 3