diff options
| -rw-r--r-- | drivers/net/sky2.c | 81 | ||||
| -rw-r--r-- | drivers/net/sky2.h | 2 |
2 files changed, 79 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; | |||
| 92 | module_param(copybreak, int, 0); | 92 | module_param(copybreak, int, 0); |
| 93 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); | 93 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); |
| 94 | 94 | ||
| 95 | static int disable_msi = 0; | ||
| 96 | module_param(disable_msi, int, 0); | ||
| 97 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
| 98 | |||
| 95 | static const struct pci_device_id sky2_id_table[] = { | 99 | static 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 */ | ||
| 3008 | static 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 */ | ||
| 3028 | static 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 | |||
| 3004 | static int __devinit sky2_probe(struct pci_dev *pdev, | 3067 | static 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 | ||
| 3137 | err_out_unregister: | 3208 | err_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); |
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index db362b69b0bb..50e9f7d38bf3 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h | |||
| @@ -1879,6 +1879,8 @@ struct sky2_hw { | |||
| 1879 | struct sky2_status_le *st_le; | 1879 | struct sky2_status_le *st_le; |
| 1880 | u32 st_idx; | 1880 | u32 st_idx; |
| 1881 | dma_addr_t st_dma; | 1881 | dma_addr_t st_dma; |
| 1882 | int msi_detected; | ||
| 1883 | wait_queue_head_t msi_wait; | ||
| 1882 | }; | 1884 | }; |
| 1883 | 1885 | ||
| 1884 | /* Register accessor for memory mapped device */ | 1886 | /* Register accessor for memory mapped device */ |
