diff options
author | stephen hemminger <shemminger@vyatta.com> | 2011-11-16 08:42:55 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-16 20:27:08 -0500 |
commit | 1401a8008a09e079236261be37e98847c799760a (patch) | |
tree | 5ab8aadb5add5b196b46ee075979d68eab9c42fe /drivers/net | |
parent | bbc13ab9d26f4ff675775dd7dc24d5cae17b85d5 (diff) |
sky2: fix hang on shutdown (and other irq issues)
There are several problems with recent change to how IRQ's are setup.
* synchronize_irq in sky2_shutdown would hang because there
was no IRQ setup.
* when device was set to down, some IRQ bits left enabled so a
hardware error would produce IRQ with no handler
* quick link on Optima chip set was enabled without handler
* suspend/resume would leave IRQ on with no handler if device
was down
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/marvell/sky2.c | 45 |
1 files changed, 27 insertions, 18 deletions
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index fdc6c394c683..f9c4529299bd 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c | |||
@@ -1747,6 +1747,11 @@ static int sky2_up(struct net_device *dev) | |||
1747 | 1747 | ||
1748 | sky2_hw_up(sky2); | 1748 | sky2_hw_up(sky2); |
1749 | 1749 | ||
1750 | if (hw->chip_id == CHIP_ID_YUKON_OPT || | ||
1751 | hw->chip_id == CHIP_ID_YUKON_PRM || | ||
1752 | hw->chip_id == CHIP_ID_YUKON_OP_2) | ||
1753 | imask |= Y2_IS_PHY_QLNK; /* enable PHY Quick Link */ | ||
1754 | |||
1750 | /* Enable interrupts from phy/mac for port */ | 1755 | /* Enable interrupts from phy/mac for port */ |
1751 | imask = sky2_read32(hw, B0_IMSK); | 1756 | imask = sky2_read32(hw, B0_IMSK); |
1752 | imask |= portirq_msk[port]; | 1757 | imask |= portirq_msk[port]; |
@@ -2101,15 +2106,21 @@ static int sky2_down(struct net_device *dev) | |||
2101 | 2106 | ||
2102 | netif_info(sky2, ifdown, dev, "disabling interface\n"); | 2107 | netif_info(sky2, ifdown, dev, "disabling interface\n"); |
2103 | 2108 | ||
2104 | /* Disable port IRQ */ | ||
2105 | sky2_write32(hw, B0_IMSK, | ||
2106 | sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]); | ||
2107 | sky2_read32(hw, B0_IMSK); | ||
2108 | |||
2109 | if (hw->ports == 1) { | 2109 | if (hw->ports == 1) { |
2110 | sky2_write32(hw, B0_IMSK, 0); | ||
2111 | sky2_read32(hw, B0_IMSK); | ||
2112 | |||
2110 | napi_disable(&hw->napi); | 2113 | napi_disable(&hw->napi); |
2111 | free_irq(hw->pdev->irq, hw); | 2114 | free_irq(hw->pdev->irq, hw); |
2112 | } else { | 2115 | } else { |
2116 | u32 imask; | ||
2117 | |||
2118 | /* Disable port IRQ */ | ||
2119 | imask = sky2_read32(hw, B0_IMSK); | ||
2120 | imask &= ~portirq_msk[sky2->port]; | ||
2121 | sky2_write32(hw, B0_IMSK, imask); | ||
2122 | sky2_read32(hw, B0_IMSK); | ||
2123 | |||
2113 | synchronize_irq(hw->pdev->irq); | 2124 | synchronize_irq(hw->pdev->irq); |
2114 | napi_synchronize(&hw->napi); | 2125 | napi_synchronize(&hw->napi); |
2115 | } | 2126 | } |
@@ -3258,7 +3269,6 @@ static void sky2_reset(struct sky2_hw *hw) | |||
3258 | hw->chip_id == CHIP_ID_YUKON_PRM || | 3269 | hw->chip_id == CHIP_ID_YUKON_PRM || |
3259 | hw->chip_id == CHIP_ID_YUKON_OP_2) { | 3270 | hw->chip_id == CHIP_ID_YUKON_OP_2) { |
3260 | u16 reg; | 3271 | u16 reg; |
3261 | u32 msk; | ||
3262 | 3272 | ||
3263 | if (hw->chip_id == CHIP_ID_YUKON_OPT && hw->chip_rev == 0) { | 3273 | if (hw->chip_id == CHIP_ID_YUKON_OPT && hw->chip_rev == 0) { |
3264 | /* disable PCI-E PHY power down (set PHY reg 0x80, bit 7 */ | 3274 | /* disable PCI-E PHY power down (set PHY reg 0x80, bit 7 */ |
@@ -3281,11 +3291,6 @@ static void sky2_reset(struct sky2_hw *hw) | |||
3281 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 3291 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
3282 | sky2_pci_write16(hw, PSM_CONFIG_REG4, reg); | 3292 | sky2_pci_write16(hw, PSM_CONFIG_REG4, reg); |
3283 | 3293 | ||
3284 | /* enable PHY Quick Link */ | ||
3285 | msk = sky2_read32(hw, B0_IMSK); | ||
3286 | msk |= Y2_IS_PHY_QLNK; | ||
3287 | sky2_write32(hw, B0_IMSK, msk); | ||
3288 | |||
3289 | /* check if PSMv2 was running before */ | 3294 | /* check if PSMv2 was running before */ |
3290 | reg = sky2_pci_read16(hw, PSM_CONFIG_REG3); | 3295 | reg = sky2_pci_read16(hw, PSM_CONFIG_REG3); |
3291 | if (reg & PCI_EXP_LNKCTL_ASPMC) | 3296 | if (reg & PCI_EXP_LNKCTL_ASPMC) |
@@ -3412,7 +3417,9 @@ static void sky2_all_down(struct sky2_hw *hw) | |||
3412 | 3417 | ||
3413 | sky2_read32(hw, B0_IMSK); | 3418 | sky2_read32(hw, B0_IMSK); |
3414 | sky2_write32(hw, B0_IMSK, 0); | 3419 | sky2_write32(hw, B0_IMSK, 0); |
3415 | synchronize_irq(hw->pdev->irq); | 3420 | |
3421 | if (hw->ports > 1 || netif_running(hw->dev[0])) | ||
3422 | synchronize_irq(hw->pdev->irq); | ||
3416 | napi_disable(&hw->napi); | 3423 | napi_disable(&hw->napi); |
3417 | 3424 | ||
3418 | for (i = 0; i < hw->ports; i++) { | 3425 | for (i = 0; i < hw->ports; i++) { |
@@ -3430,7 +3437,7 @@ static void sky2_all_down(struct sky2_hw *hw) | |||
3430 | 3437 | ||
3431 | static void sky2_all_up(struct sky2_hw *hw) | 3438 | static void sky2_all_up(struct sky2_hw *hw) |
3432 | { | 3439 | { |
3433 | u32 imask = Y2_IS_BASE; | 3440 | u32 imask = 0; |
3434 | int i; | 3441 | int i; |
3435 | 3442 | ||
3436 | for (i = 0; i < hw->ports; i++) { | 3443 | for (i = 0; i < hw->ports; i++) { |
@@ -3446,11 +3453,13 @@ static void sky2_all_up(struct sky2_hw *hw) | |||
3446 | netif_wake_queue(dev); | 3453 | netif_wake_queue(dev); |
3447 | } | 3454 | } |
3448 | 3455 | ||
3449 | sky2_write32(hw, B0_IMSK, imask); | 3456 | if (imask || hw->ports > 1) { |
3450 | sky2_read32(hw, B0_IMSK); | 3457 | imask |= Y2_IS_BASE; |
3451 | 3458 | sky2_write32(hw, B0_IMSK, imask); | |
3452 | sky2_read32(hw, B0_Y2_SP_LISR); | 3459 | sky2_read32(hw, B0_IMSK); |
3453 | napi_enable(&hw->napi); | 3460 | sky2_read32(hw, B0_Y2_SP_LISR); |
3461 | napi_enable(&hw->napi); | ||
3462 | } | ||
3454 | } | 3463 | } |
3455 | 3464 | ||
3456 | static void sky2_restart(struct work_struct *work) | 3465 | static void sky2_restart(struct work_struct *work) |