aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c81
1 files changed, 77 insertions, 4 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7e3353f55c38..2e29972b8d0b 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -92,6 +92,10 @@ static int copybreak __read_mostly = 256;
92module_param(copybreak, int, 0); 92module_param(copybreak, int, 0);
93MODULE_PARM_DESC(copybreak, "Receive copy threshold"); 93MODULE_PARM_DESC(copybreak, "Receive copy threshold");
94 94
95static int disable_msi = 0;
96module_param(disable_msi, int, 0);
97MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
98
95static const struct pci_device_id sky2_id_table[] = { 99static const struct pci_device_id sky2_id_table[] = {
96 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, 100 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
97 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, 101 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
@@ -2045,7 +2049,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2045 struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; 2049 struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
2046 int work_limit = min(dev0->quota, *budget); 2050 int work_limit = min(dev0->quota, *budget);
2047 int work_done = 0; 2051 int work_done = 0;
2048 u32 status = sky2_read32(hw, B0_ISRC); 2052 u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
2049 2053
2050 if (status & Y2_IS_HW_ERR) 2054 if (status & Y2_IS_HW_ERR)
2051 sky2_hw_intr(hw); 2055 sky2_hw_intr(hw);
@@ -2075,8 +2079,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2075 2079
2076 netif_rx_complete(dev0); 2080 netif_rx_complete(dev0);
2077 2081
2078 /* Ack interrupt and re-enable */ 2082 status = sky2_read32(hw, B0_Y2_SP_LISR);
2079 sky2_write32(hw, B0_Y2_SP_ICR, 2);
2080 return 0; 2083 return 0;
2081} 2084}
2082 2085
@@ -3001,6 +3004,66 @@ static void __devinit sky2_show_addr(struct net_device *dev)
3001 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); 3004 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
3002} 3005}
3003 3006
3007/* Handle software interrupt used during MSI test */
3008static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id,
3009 struct pt_regs *regs)
3010{
3011 struct sky2_hw *hw = dev_id;
3012 u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2);
3013
3014 if (status == 0)
3015 return IRQ_NONE;
3016
3017 if (status & Y2_IS_IRQ_SW) {
3018 hw->msi_detected = 1;
3019 wake_up(&hw->msi_wait);
3020 sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
3021 }
3022 sky2_write32(hw, B0_Y2_SP_ICR, 2);
3023
3024 return IRQ_HANDLED;
3025}
3026
3027/* Test interrupt path by forcing a a software IRQ */
3028static int __devinit sky2_test_msi(struct sky2_hw *hw)
3029{
3030 struct pci_dev *pdev = hw->pdev;
3031 int err;
3032
3033 sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
3034
3035 err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw);
3036 if (err) {
3037 printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
3038 pci_name(pdev), pdev->irq);
3039 return err;
3040 }
3041
3042 init_waitqueue_head (&hw->msi_wait);
3043
3044 sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
3045 wmb();
3046
3047 wait_event_timeout(hw->msi_wait, hw->msi_detected, HZ/10);
3048
3049 if (!hw->msi_detected) {
3050 /* MSI test failed, go back to INTx mode */
3051 printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
3052 "switching to INTx mode. Please report this failure to "
3053 "the PCI maintainer and include system chipset information.\n",
3054 pci_name(pdev));
3055
3056 err = -EOPNOTSUPP;
3057 sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
3058 }
3059
3060 sky2_write32(hw, B0_IMSK, 0);
3061
3062 free_irq(pdev->irq, hw);
3063
3064 return err;
3065}
3066
3004static int __devinit sky2_probe(struct pci_dev *pdev, 3067static int __devinit sky2_probe(struct pci_dev *pdev,
3005 const struct pci_device_id *ent) 3068 const struct pci_device_id *ent)
3006{ 3069{
@@ -3121,7 +3184,15 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3121 } 3184 }
3122 } 3185 }
3123 3186
3124 err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); 3187 if (!disable_msi && pci_enable_msi(pdev) == 0) {
3188 err = sky2_test_msi(hw);
3189 if (err == -EOPNOTSUPP)
3190 pci_disable_msi(pdev);
3191 else if (err)
3192 goto err_out_unregister;
3193 }
3194
3195 err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw);
3125 if (err) { 3196 if (err) {
3126 printk(KERN_ERR PFX "%s: cannot assign irq %d\n", 3197 printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
3127 pci_name(pdev), pdev->irq); 3198 pci_name(pdev), pdev->irq);
@@ -3135,6 +3206,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3135 return 0; 3206 return 0;
3136 3207
3137err_out_unregister: 3208err_out_unregister:
3209 pci_disable_msi(pdev);
3138 if (dev1) { 3210 if (dev1) {
3139 unregister_netdev(dev1); 3211 unregister_netdev(dev1);
3140 free_netdev(dev1); 3212 free_netdev(dev1);
@@ -3177,6 +3249,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
3177 sky2_read8(hw, B0_CTST); 3249 sky2_read8(hw, B0_CTST);
3178 3250
3179 free_irq(pdev->irq, hw); 3251 free_irq(pdev->irq, hw);
3252 pci_disable_msi(pdev);
3180 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); 3253 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
3181 pci_release_regions(pdev); 3254 pci_release_regions(pdev);
3182 pci_disable_device(pdev); 3255 pci_disable_device(pdev);