diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-01-30 14:38:00 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-02-07 02:00:36 -0500 |
commit | 4d52b48b43d0d1d5959fa722ee0046e3542e5e1b (patch) | |
tree | ce8c99092e5039e2827d072a0ecbb5013f16f8e0 /drivers | |
parent | db992c970dcfbbf24e6a681e66d22ddda62452c4 (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.c | 77 | ||||
-rw-r--r-- | drivers/net/sky2.h | 1 |
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; | |||
101 | module_param(copybreak, int, 0); | 101 | module_param(copybreak, int, 0); |
102 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); | 102 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); |
103 | 103 | ||
104 | static int disable_msi = 0; | ||
105 | module_param(disable_msi, int, 0); | ||
106 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
107 | |||
104 | static const struct pci_device_id sky2_id_table[] = { | 108 | static 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 */ | ||
3072 | static 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 */ | ||
3092 | static 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 | |||
3067 | static int __devinit sky2_probe(struct pci_dev *pdev, | 3126 | static 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 | ||
3202 | err_out_unregister: | 3275 | err_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; |