aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-01-30 14:38:00 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-02-07 02:00:36 -0500
commit4d52b48b43d0d1d5959fa722ee0046e3542e5e1b (patch)
treece8c99092e5039e2827d072a0ecbb5013f16f8e0 /drivers
parentdb992c970dcfbbf24e6a681e66d22ddda62452c4 (diff)
[PATCH] sky2: support msi interrupt (revised)
This hardware supports Message Signaled interrupts. When setting up, use software interrupt to check for bad hardware. Signed-off-by: Stephen Hemminger <shemminger @osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/sky2.c77
-rw-r--r--drivers/net/sky2.h1
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 62733a6ec758..8ed4bd17c0cf 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -101,6 +101,10 @@ static int copybreak __read_mostly = 256;
101module_param(copybreak, int, 0); 101module_param(copybreak, int, 0);
102MODULE_PARM_DESC(copybreak, "Receive copy threshold"); 102MODULE_PARM_DESC(copybreak, "Receive copy threshold");
103 103
104static int disable_msi = 0;
105module_param(disable_msi, int, 0);
106MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
107
104static const struct pci_device_id sky2_id_table[] = { 108static const struct pci_device_id sky2_id_table[] = {
105 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, 109 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
106 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, 110 { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
@@ -3064,6 +3068,61 @@ static void __devinit sky2_show_addr(struct net_device *dev)
3064 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); 3068 dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
3065} 3069}
3066 3070
3071/* Handle software interrupt used during MSI test */
3072static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id,
3073 struct pt_regs *regs)
3074{
3075 struct sky2_hw *hw = dev_id;
3076 u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2);
3077
3078 if (status == 0)
3079 return IRQ_NONE;
3080
3081 if (status & Y2_IS_IRQ_SW) {
3082 sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
3083 hw->msi = 1;
3084 }
3085 sky2_write32(hw, B0_Y2_SP_ICR, 2);
3086
3087 sky2_read32(hw, B0_IMSK);
3088 return IRQ_HANDLED;
3089}
3090
3091/* Test interrupt path by forcing a a software IRQ */
3092static int __devinit sky2_test_msi(struct sky2_hw *hw)
3093{
3094 struct pci_dev *pdev = hw->pdev;
3095 int i, err;
3096
3097 sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
3098
3099 err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw);
3100 if (err) {
3101 printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
3102 pci_name(pdev), pdev->irq);
3103 return err;
3104 }
3105
3106 sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
3107 wmb();
3108
3109 for (i = 0; i < 10; i++) {
3110 barrier();
3111 if (hw->msi)
3112 goto found;
3113 mdelay(1);
3114 }
3115
3116 err = -EOPNOTSUPP;
3117 sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
3118 found:
3119 sky2_write32(hw, B0_IMSK, 0);
3120
3121 free_irq(pdev->irq, hw);
3122
3123 return err;
3124}
3125
3067static int __devinit sky2_probe(struct pci_dev *pdev, 3126static int __devinit sky2_probe(struct pci_dev *pdev,
3068 const struct pci_device_id *ent) 3127 const struct pci_device_id *ent)
3069{ 3128{
@@ -3184,6 +3243,20 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3184 } 3243 }
3185 } 3244 }
3186 3245
3246 if (!disable_msi && pci_enable_msi(pdev) == 0) {
3247 err = sky2_test_msi(hw);
3248 if (err == -EOPNOTSUPP) {
3249 /* MSI test failed, go back to INTx mode */
3250 printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
3251 "switching to INTx mode. Please report this failure to "
3252 "the PCI maintainer and include system chipset information.\n",
3253 pci_name(pdev));
3254 pci_disable_msi(pdev);
3255 }
3256 else if (err)
3257 goto err_out_unregister;
3258 }
3259
3187 err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, 3260 err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
3188 DRV_NAME, hw); 3261 DRV_NAME, hw);
3189 if (err) { 3262 if (err) {
@@ -3200,6 +3273,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3200 return 0; 3273 return 0;
3201 3274
3202err_out_unregister: 3275err_out_unregister:
3276 if (hw->msi)
3277 pci_disable_msi(pdev);
3203 if (dev1) { 3278 if (dev1) {
3204 unregister_netdev(dev1); 3279 unregister_netdev(dev1);
3205 free_netdev(dev1); 3280 free_netdev(dev1);
@@ -3242,6 +3317,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
3242 sky2_read8(hw, B0_CTST); 3317 sky2_read8(hw, B0_CTST);
3243 3318
3244 free_irq(pdev->irq, hw); 3319 free_irq(pdev->irq, hw);
3320 if (hw->msi)
3321 pci_disable_msi(pdev);
3245 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); 3322 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
3246 pci_release_regions(pdev); 3323 pci_release_regions(pdev);
3247 pci_disable_device(pdev); 3324 pci_disable_device(pdev);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 70525ac501de..fd12c289a238 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1841,6 +1841,7 @@ struct sky2_hw {
1841 struct net_device *dev[2]; 1841 struct net_device *dev[2];
1842 1842
1843 int pm_cap; 1843 int pm_cap;
1844 int msi;
1844 u8 chip_id; 1845 u8 chip_id;
1845 u8 chip_rev; 1846 u8 chip_rev;
1846 u8 copper; 1847 u8 copper;