aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2005-04-21 20:13:59 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-04-21 20:13:59 -0400
commit7938109fff944e0117976a39946d99d2b0b0250d (patch)
tree1e1c24ad874db00f827fc6d9087402db6becefc9 /drivers/net/tg3.c
parent88b06bc26b87cf0490b0e3faea7fefc7549dd75d (diff)
[TG3]: Add msi test
Add MSI test for chips that support MSI. If MSI test fails, it will switch back to INTx mode and will print a message asking the user to report the failure. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c154
1 files changed, 151 insertions, 3 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 2a17af9bd1ce..f65ca3b2da6f 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -2996,6 +2996,22 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
2996 return IRQ_RETVAL(handled); 2996 return IRQ_RETVAL(handled);
2997} 2997}
2998 2998
2999/* ISR for interrupt test */
3000static irqreturn_t tg3_test_isr(int irq, void *dev_id,
3001 struct pt_regs *regs)
3002{
3003 struct net_device *dev = dev_id;
3004 struct tg3 *tp = netdev_priv(dev);
3005 struct tg3_hw_status *sblk = tp->hw_status;
3006
3007 if (sblk->status & SD_STATUS_UPDATED) {
3008 tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
3009 0x00000001);
3010 return IRQ_RETVAL(1);
3011 }
3012 return IRQ_RETVAL(0);
3013}
3014
2999static int tg3_init_hw(struct tg3 *); 3015static int tg3_init_hw(struct tg3 *);
3000static int tg3_halt(struct tg3 *); 3016static int tg3_halt(struct tg3 *);
3001 3017
@@ -5796,6 +5812,118 @@ static void tg3_timer(unsigned long __opaque)
5796 add_timer(&tp->timer); 5812 add_timer(&tp->timer);
5797} 5813}
5798 5814
5815static int tg3_test_interrupt(struct tg3 *tp)
5816{
5817 struct net_device *dev = tp->dev;
5818 int err, i;
5819 u32 int_mbox = 0;
5820
5821 tg3_disable_ints(tp);
5822
5823 free_irq(tp->pdev->irq, dev);
5824
5825 err = request_irq(tp->pdev->irq, tg3_test_isr,
5826 SA_SHIRQ, dev->name, dev);
5827 if (err)
5828 return err;
5829
5830 tg3_enable_ints(tp);
5831
5832 tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
5833 HOSTCC_MODE_NOW);
5834
5835 for (i = 0; i < 5; i++) {
5836 int_mbox = tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
5837 if (int_mbox != 0)
5838 break;
5839 msleep(10);
5840 }
5841
5842 tg3_disable_ints(tp);
5843
5844 free_irq(tp->pdev->irq, dev);
5845
5846 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
5847 err = request_irq(tp->pdev->irq, tg3_msi,
5848 0, dev->name, dev);
5849 else
5850 err = request_irq(tp->pdev->irq, tg3_interrupt,
5851 SA_SHIRQ, dev->name, dev);
5852
5853 if (err)
5854 return err;
5855
5856 if (int_mbox != 0)
5857 return 0;
5858
5859 return -EIO;
5860}
5861
5862/* Returns 0 if MSI test succeeds or MSI test fails and INTx mode is
5863 * successfully restored
5864 */
5865static int tg3_test_msi(struct tg3 *tp)
5866{
5867 struct net_device *dev = tp->dev;
5868 int err;
5869 u16 pci_cmd;
5870
5871 if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI))
5872 return 0;
5873
5874 /* Turn off SERR reporting in case MSI terminates with Master
5875 * Abort.
5876 */
5877 pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
5878 pci_write_config_word(tp->pdev, PCI_COMMAND,
5879 pci_cmd & ~PCI_COMMAND_SERR);
5880
5881 err = tg3_test_interrupt(tp);
5882
5883 pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
5884
5885 if (!err)
5886 return 0;
5887
5888 /* other failures */
5889 if (err != -EIO)
5890 return err;
5891
5892 /* MSI test failed, go back to INTx mode */
5893 printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
5894 "switching to INTx mode. Please report this failure to "
5895 "the PCI maintainer and include system chipset information.\n",
5896 tp->dev->name);
5897
5898 free_irq(tp->pdev->irq, dev);
5899 pci_disable_msi(tp->pdev);
5900
5901 tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
5902
5903 err = request_irq(tp->pdev->irq, tg3_interrupt,
5904 SA_SHIRQ, dev->name, dev);
5905
5906 if (err)
5907 return err;
5908
5909 /* Need to reset the chip because the MSI cycle may have terminated
5910 * with Master Abort.
5911 */
5912 spin_lock_irq(&tp->lock);
5913 spin_lock(&tp->tx_lock);
5914
5915 tg3_halt(tp);
5916 err = tg3_init_hw(tp);
5917
5918 spin_unlock(&tp->tx_lock);
5919 spin_unlock_irq(&tp->lock);
5920
5921 if (err)
5922 free_irq(tp->pdev->irq, dev);
5923
5924 return err;
5925}
5926
5799static int tg3_open(struct net_device *dev) 5927static int tg3_open(struct net_device *dev)
5800{ 5928{
5801 struct tg3 *tp = netdev_priv(dev); 5929 struct tg3 *tp = netdev_priv(dev);
@@ -5860,9 +5988,6 @@ static int tg3_open(struct net_device *dev)
5860 tp->timer.expires = jiffies + tp->timer_offset; 5988 tp->timer.expires = jiffies + tp->timer_offset;
5861 tp->timer.data = (unsigned long) tp; 5989 tp->timer.data = (unsigned long) tp;
5862 tp->timer.function = tg3_timer; 5990 tp->timer.function = tg3_timer;
5863 add_timer(&tp->timer);
5864
5865 tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
5866 } 5991 }
5867 5992
5868 spin_unlock(&tp->tx_lock); 5993 spin_unlock(&tp->tx_lock);
@@ -5878,9 +6003,32 @@ static int tg3_open(struct net_device *dev)
5878 return err; 6003 return err;
5879 } 6004 }
5880 6005
6006 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
6007 err = tg3_test_msi(tp);
6008 if (err) {
6009 spin_lock_irq(&tp->lock);
6010 spin_lock(&tp->tx_lock);
6011
6012 if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
6013 pci_disable_msi(tp->pdev);
6014 tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
6015 }
6016 tg3_halt(tp);
6017 tg3_free_rings(tp);
6018 tg3_free_consistent(tp);
6019
6020 spin_unlock(&tp->tx_lock);
6021 spin_unlock_irq(&tp->lock);
6022
6023 return err;
6024 }
6025 }
6026
5881 spin_lock_irq(&tp->lock); 6027 spin_lock_irq(&tp->lock);
5882 spin_lock(&tp->tx_lock); 6028 spin_lock(&tp->tx_lock);
5883 6029
6030 add_timer(&tp->timer);
6031 tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
5884 tg3_enable_ints(tp); 6032 tg3_enable_ints(tp);
5885 6033
5886 spin_unlock(&tp->tx_lock); 6034 spin_unlock(&tp->tx_lock);