diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 346 |
1 files changed, 253 insertions, 93 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f8b973a04b65..ca8160d68229 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -23,12 +23,6 @@ | |||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* | ||
27 | * TOTEST | ||
28 | * - speed setting | ||
29 | * - suspend/resume | ||
30 | */ | ||
31 | |||
32 | #include <linux/config.h> | 26 | #include <linux/config.h> |
33 | #include <linux/crc32.h> | 27 | #include <linux/crc32.h> |
34 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
@@ -57,7 +51,7 @@ | |||
57 | #include "sky2.h" | 51 | #include "sky2.h" |
58 | 52 | ||
59 | #define DRV_NAME "sky2" | 53 | #define DRV_NAME "sky2" |
60 | #define DRV_VERSION "0.13" | 54 | #define DRV_VERSION "0.15" |
61 | #define PFX DRV_NAME " " | 55 | #define PFX DRV_NAME " " |
62 | 56 | ||
63 | /* | 57 | /* |
@@ -102,6 +96,10 @@ static int copybreak __read_mostly = 256; | |||
102 | module_param(copybreak, int, 0); | 96 | module_param(copybreak, int, 0); |
103 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); | 97 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); |
104 | 98 | ||
99 | static int disable_msi = 0; | ||
100 | module_param(disable_msi, int, 0); | ||
101 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
102 | |||
105 | static const struct pci_device_id sky2_id_table[] = { | 103 | static const struct pci_device_id sky2_id_table[] = { |
106 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, | 104 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, |
107 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, | 105 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, |
@@ -197,11 +195,11 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | |||
197 | pr_debug("sky2_set_power_state %d\n", state); | 195 | pr_debug("sky2_set_power_state %d\n", state); |
198 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 196 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
199 | 197 | ||
200 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_PMC, &power_control); | 198 | power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC); |
201 | vaux = (sky2_read8(hw, B0_CTST) & Y2_VAUX_AVAIL) && | 199 | vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) && |
202 | (power_control & PCI_PM_CAP_PME_D3cold); | 200 | (power_control & PCI_PM_CAP_PME_D3cold); |
203 | 201 | ||
204 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_CTRL, &power_control); | 202 | power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); |
205 | 203 | ||
206 | power_control |= PCI_PM_CTRL_PME_STATUS; | 204 | power_control |= PCI_PM_CTRL_PME_STATUS; |
207 | power_control &= ~(PCI_PM_CTRL_STATE_MASK); | 205 | power_control &= ~(PCI_PM_CTRL_STATE_MASK); |
@@ -225,7 +223,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | |||
225 | sky2_write8(hw, B2_Y2_CLK_GATE, 0); | 223 | sky2_write8(hw, B2_Y2_CLK_GATE, 0); |
226 | 224 | ||
227 | /* Turn off phy power saving */ | 225 | /* Turn off phy power saving */ |
228 | pci_read_config_dword(hw->pdev, PCI_DEV_REG1, ®1); | 226 | reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); |
229 | reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); | 227 | reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); |
230 | 228 | ||
231 | /* looks like this XL is back asswards .. */ | 229 | /* looks like this XL is back asswards .. */ |
@@ -234,18 +232,28 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | |||
234 | if (hw->ports > 1) | 232 | if (hw->ports > 1) |
235 | reg1 |= PCI_Y2_PHY2_COMA; | 233 | reg1 |= PCI_Y2_PHY2_COMA; |
236 | } | 234 | } |
237 | pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1); | 235 | |
236 | if (hw->chip_id == CHIP_ID_YUKON_EC_U) { | ||
237 | sky2_pci_write32(hw, PCI_DEV_REG3, 0); | ||
238 | reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); | ||
239 | reg1 &= P_ASPM_CONTROL_MSK; | ||
240 | sky2_pci_write32(hw, PCI_DEV_REG4, reg1); | ||
241 | sky2_pci_write32(hw, PCI_DEV_REG5, 0); | ||
242 | } | ||
243 | |||
244 | sky2_pci_write32(hw, PCI_DEV_REG1, reg1); | ||
245 | |||
238 | break; | 246 | break; |
239 | 247 | ||
240 | case PCI_D3hot: | 248 | case PCI_D3hot: |
241 | case PCI_D3cold: | 249 | case PCI_D3cold: |
242 | /* Turn on phy power saving */ | 250 | /* Turn on phy power saving */ |
243 | pci_read_config_dword(hw->pdev, PCI_DEV_REG1, ®1); | 251 | reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); |
244 | if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) | 252 | if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) |
245 | reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); | 253 | reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); |
246 | else | 254 | else |
247 | reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); | 255 | reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); |
248 | pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1); | 256 | sky2_pci_write32(hw, PCI_DEV_REG1, reg1); |
249 | 257 | ||
250 | if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) | 258 | if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) |
251 | sky2_write8(hw, B2_Y2_CLK_GATE, 0); | 259 | sky2_write8(hw, B2_Y2_CLK_GATE, 0); |
@@ -267,7 +275,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | |||
267 | ret = -1; | 275 | ret = -1; |
268 | } | 276 | } |
269 | 277 | ||
270 | pci_write_config_byte(hw->pdev, hw->pm_cap + PCI_PM_CTRL, power_control); | 278 | sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); |
271 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); | 279 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); |
272 | return ret; | 280 | return ret; |
273 | } | 281 | } |
@@ -465,16 +473,31 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) | |||
465 | ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); | 473 | ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); |
466 | } | 474 | } |
467 | 475 | ||
468 | gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); | 476 | if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) { |
477 | /* apply fixes in PHY AFE */ | ||
478 | gm_phy_write(hw, port, 22, 255); | ||
479 | /* increase differential signal amplitude in 10BASE-T */ | ||
480 | gm_phy_write(hw, port, 24, 0xaa99); | ||
481 | gm_phy_write(hw, port, 23, 0x2011); | ||
469 | 482 | ||
470 | if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { | 483 | /* fix for IEEE A/B Symmetry failure in 1000BASE-T */ |
471 | /* turn on 100 Mbps LED (LED_LINK100) */ | 484 | gm_phy_write(hw, port, 24, 0xa204); |
472 | ledover |= PHY_M_LED_MO_100(MO_LED_ON); | 485 | gm_phy_write(hw, port, 23, 0x2002); |
473 | } | ||
474 | 486 | ||
475 | if (ledover) | 487 | /* set page register to 0 */ |
476 | gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); | 488 | gm_phy_write(hw, port, 22, 0); |
489 | } else { | ||
490 | gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); | ||
491 | |||
492 | if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { | ||
493 | /* turn on 100 Mbps LED (LED_LINK100) */ | ||
494 | ledover |= PHY_M_LED_MO_100(MO_LED_ON); | ||
495 | } | ||
496 | |||
497 | if (ledover) | ||
498 | gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); | ||
477 | 499 | ||
500 | } | ||
478 | /* Enable phy interrupt on auto-negotiation complete (or link up) */ | 501 | /* Enable phy interrupt on auto-negotiation complete (or link up) */ |
479 | if (sky2->autoneg == AUTONEG_ENABLE) | 502 | if (sky2->autoneg == AUTONEG_ENABLE) |
480 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); | 503 | gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); |
@@ -522,10 +545,16 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) | |||
522 | 545 | ||
523 | switch (sky2->speed) { | 546 | switch (sky2->speed) { |
524 | case SPEED_1000: | 547 | case SPEED_1000: |
548 | reg &= ~GM_GPCR_SPEED_100; | ||
525 | reg |= GM_GPCR_SPEED_1000; | 549 | reg |= GM_GPCR_SPEED_1000; |
526 | /* fallthru */ | 550 | break; |
527 | case SPEED_100: | 551 | case SPEED_100: |
552 | reg &= ~GM_GPCR_SPEED_1000; | ||
528 | reg |= GM_GPCR_SPEED_100; | 553 | reg |= GM_GPCR_SPEED_100; |
554 | break; | ||
555 | case SPEED_10: | ||
556 | reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100); | ||
557 | break; | ||
529 | } | 558 | } |
530 | 559 | ||
531 | if (sky2->duplex == DUPLEX_FULL) | 560 | if (sky2->duplex == DUPLEX_FULL) |
@@ -949,6 +978,12 @@ static int sky2_rx_start(struct sky2_port *sky2) | |||
949 | 978 | ||
950 | sky2->rx_put = sky2->rx_next = 0; | 979 | sky2->rx_put = sky2->rx_next = 0; |
951 | sky2_qset(hw, rxq); | 980 | sky2_qset(hw, rxq); |
981 | |||
982 | if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) { | ||
983 | /* MAC Rx RAM Read is controlled by hardware */ | ||
984 | sky2_write32(hw, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS); | ||
985 | } | ||
986 | |||
952 | sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); | 987 | sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); |
953 | 988 | ||
954 | rx_set_checksum(sky2); | 989 | rx_set_checksum(sky2); |
@@ -1031,9 +1066,10 @@ static int sky2_up(struct net_device *dev) | |||
1031 | RB_RST_SET); | 1066 | RB_RST_SET); |
1032 | 1067 | ||
1033 | sky2_qset(hw, txqaddr[port]); | 1068 | sky2_qset(hw, txqaddr[port]); |
1034 | if (hw->chip_id == CHIP_ID_YUKON_EC_U) | ||
1035 | sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0); | ||
1036 | 1069 | ||
1070 | /* Set almost empty threshold */ | ||
1071 | if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == 1) | ||
1072 | sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0); | ||
1037 | 1073 | ||
1038 | sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, | 1074 | sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, |
1039 | TX_RING_SIZE - 1); | 1075 | TX_RING_SIZE - 1); |
@@ -1043,8 +1079,10 @@ static int sky2_up(struct net_device *dev) | |||
1043 | goto err_out; | 1079 | goto err_out; |
1044 | 1080 | ||
1045 | /* Enable interrupts from phy/mac for port */ | 1081 | /* Enable interrupts from phy/mac for port */ |
1082 | spin_lock_irq(&hw->hw_lock); | ||
1046 | hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; | 1083 | hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; |
1047 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 1084 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
1085 | spin_unlock_irq(&hw->hw_lock); | ||
1048 | return 0; | 1086 | return 0; |
1049 | 1087 | ||
1050 | err_out: | 1088 | err_out: |
@@ -1344,10 +1382,10 @@ static int sky2_down(struct net_device *dev) | |||
1344 | netif_stop_queue(dev); | 1382 | netif_stop_queue(dev); |
1345 | 1383 | ||
1346 | /* Disable port IRQ */ | 1384 | /* Disable port IRQ */ |
1347 | local_irq_disable(); | 1385 | spin_lock_irq(&hw->hw_lock); |
1348 | hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); | 1386 | hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); |
1349 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 1387 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
1350 | local_irq_enable(); | 1388 | spin_unlock_irq(&hw->hw_lock); |
1351 | 1389 | ||
1352 | flush_scheduled_work(); | 1390 | flush_scheduled_work(); |
1353 | 1391 | ||
@@ -1448,6 +1486,29 @@ static void sky2_link_up(struct sky2_port *sky2) | |||
1448 | sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); | 1486 | sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); |
1449 | 1487 | ||
1450 | reg = gma_read16(hw, port, GM_GP_CTRL); | 1488 | reg = gma_read16(hw, port, GM_GP_CTRL); |
1489 | if (sky2->autoneg == AUTONEG_DISABLE) { | ||
1490 | reg |= GM_GPCR_AU_ALL_DIS; | ||
1491 | |||
1492 | /* Is write/read necessary? Copied from sky2_mac_init */ | ||
1493 | gma_write16(hw, port, GM_GP_CTRL, reg); | ||
1494 | gma_read16(hw, port, GM_GP_CTRL); | ||
1495 | |||
1496 | switch (sky2->speed) { | ||
1497 | case SPEED_1000: | ||
1498 | reg &= ~GM_GPCR_SPEED_100; | ||
1499 | reg |= GM_GPCR_SPEED_1000; | ||
1500 | break; | ||
1501 | case SPEED_100: | ||
1502 | reg &= ~GM_GPCR_SPEED_1000; | ||
1503 | reg |= GM_GPCR_SPEED_100; | ||
1504 | break; | ||
1505 | case SPEED_10: | ||
1506 | reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100); | ||
1507 | break; | ||
1508 | } | ||
1509 | } else | ||
1510 | reg &= ~GM_GPCR_AU_ALL_DIS; | ||
1511 | |||
1451 | if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE) | 1512 | if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE) |
1452 | reg |= GM_GPCR_DUP_FULL; | 1513 | reg |= GM_GPCR_DUP_FULL; |
1453 | 1514 | ||
@@ -1606,10 +1667,10 @@ static void sky2_phy_task(void *arg) | |||
1606 | out: | 1667 | out: |
1607 | up(&sky2->phy_sema); | 1668 | up(&sky2->phy_sema); |
1608 | 1669 | ||
1609 | local_irq_disable(); | 1670 | spin_lock_irq(&hw->hw_lock); |
1610 | hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; | 1671 | hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; |
1611 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 1672 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
1612 | local_irq_enable(); | 1673 | spin_unlock_irq(&hw->hw_lock); |
1613 | } | 1674 | } |
1614 | 1675 | ||
1615 | 1676 | ||
@@ -1834,6 +1895,19 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1834 | u16 hwidx; | 1895 | u16 hwidx; |
1835 | u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS }; | 1896 | u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS }; |
1836 | 1897 | ||
1898 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); | ||
1899 | |||
1900 | /* | ||
1901 | * Kick the STAT_LEV_TIMER_CTRL timer. | ||
1902 | * This fixes my hangs on Yukon-EC (0xb6) rev 1. | ||
1903 | * The if clause is there to start the timer only if it has been | ||
1904 | * configured correctly and not been disabled via ethtool. | ||
1905 | */ | ||
1906 | if (sky2_read8(hw, STAT_LEV_TIMER_CTRL) == TIM_START) { | ||
1907 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_STOP); | ||
1908 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); | ||
1909 | } | ||
1910 | |||
1837 | hwidx = sky2_read16(hw, STAT_PUT_IDX); | 1911 | hwidx = sky2_read16(hw, STAT_PUT_IDX); |
1838 | BUG_ON(hwidx >= STATUS_RING_SIZE); | 1912 | BUG_ON(hwidx >= STATUS_RING_SIZE); |
1839 | rmb(); | 1913 | rmb(); |
@@ -1913,21 +1987,22 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
1913 | } | 1987 | } |
1914 | 1988 | ||
1915 | exit_loop: | 1989 | exit_loop: |
1916 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); | ||
1917 | |||
1918 | sky2_tx_check(hw, 0, tx_done[0]); | 1990 | sky2_tx_check(hw, 0, tx_done[0]); |
1919 | sky2_tx_check(hw, 1, tx_done[1]); | 1991 | sky2_tx_check(hw, 1, tx_done[1]); |
1920 | 1992 | ||
1921 | if (sky2_read16(hw, STAT_PUT_IDX) == hw->st_idx) { | 1993 | if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { |
1922 | /* need to restart TX timer */ | 1994 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); |
1923 | if (is_ec_a1(hw)) { | 1995 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); |
1924 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); | 1996 | } |
1925 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); | 1997 | |
1926 | } | 1998 | if (likely(work_done < to_do)) { |
1999 | spin_lock_irq(&hw->hw_lock); | ||
2000 | __netif_rx_complete(dev0); | ||
1927 | 2001 | ||
1928 | netif_rx_complete(dev0); | ||
1929 | hw->intr_mask |= Y2_IS_STAT_BMU; | 2002 | hw->intr_mask |= Y2_IS_STAT_BMU; |
1930 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 2003 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
2004 | spin_unlock_irq(&hw->hw_lock); | ||
2005 | |||
1931 | return 0; | 2006 | return 0; |
1932 | } else { | 2007 | } else { |
1933 | *budget -= work_done; | 2008 | *budget -= work_done; |
@@ -1990,13 +2065,13 @@ static void sky2_hw_intr(struct sky2_hw *hw) | |||
1990 | if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) { | 2065 | if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) { |
1991 | u16 pci_err; | 2066 | u16 pci_err; |
1992 | 2067 | ||
1993 | pci_read_config_word(hw->pdev, PCI_STATUS, &pci_err); | 2068 | pci_err = sky2_pci_read16(hw, PCI_STATUS); |
1994 | if (net_ratelimit()) | 2069 | if (net_ratelimit()) |
1995 | printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", | 2070 | printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", |
1996 | pci_name(hw->pdev), pci_err); | 2071 | pci_name(hw->pdev), pci_err); |
1997 | 2072 | ||
1998 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 2073 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
1999 | pci_write_config_word(hw->pdev, PCI_STATUS, | 2074 | sky2_pci_write16(hw, PCI_STATUS, |
2000 | pci_err | PCI_STATUS_ERROR_BITS); | 2075 | pci_err | PCI_STATUS_ERROR_BITS); |
2001 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); | 2076 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); |
2002 | } | 2077 | } |
@@ -2005,7 +2080,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) | |||
2005 | /* PCI-Express uncorrectable Error occurred */ | 2080 | /* PCI-Express uncorrectable Error occurred */ |
2006 | u32 pex_err; | 2081 | u32 pex_err; |
2007 | 2082 | ||
2008 | pci_read_config_dword(hw->pdev, PEX_UNC_ERR_STAT, &pex_err); | 2083 | pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); |
2009 | 2084 | ||
2010 | if (net_ratelimit()) | 2085 | if (net_ratelimit()) |
2011 | printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", | 2086 | printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", |
@@ -2013,7 +2088,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) | |||
2013 | 2088 | ||
2014 | /* clear the interrupt */ | 2089 | /* clear the interrupt */ |
2015 | sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 2090 | sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
2016 | pci_write_config_dword(hw->pdev, PEX_UNC_ERR_STAT, | 2091 | sky2_pci_write32(hw, PEX_UNC_ERR_STAT, |
2017 | 0xffffffffUL); | 2092 | 0xffffffffUL); |
2018 | sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); | 2093 | sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); |
2019 | 2094 | ||
@@ -2059,6 +2134,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) | |||
2059 | 2134 | ||
2060 | hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); | 2135 | hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); |
2061 | sky2_write32(hw, B0_IMSK, hw->intr_mask); | 2136 | sky2_write32(hw, B0_IMSK, hw->intr_mask); |
2137 | |||
2062 | schedule_work(&sky2->phy_task); | 2138 | schedule_work(&sky2->phy_task); |
2063 | } | 2139 | } |
2064 | 2140 | ||
@@ -2072,6 +2148,7 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) | |||
2072 | if (status == 0 || status == ~0) | 2148 | if (status == 0 || status == ~0) |
2073 | return IRQ_NONE; | 2149 | return IRQ_NONE; |
2074 | 2150 | ||
2151 | spin_lock(&hw->hw_lock); | ||
2075 | if (status & Y2_IS_HW_ERR) | 2152 | if (status & Y2_IS_HW_ERR) |
2076 | sky2_hw_intr(hw); | 2153 | sky2_hw_intr(hw); |
2077 | 2154 | ||
@@ -2100,7 +2177,7 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) | |||
2100 | 2177 | ||
2101 | sky2_write32(hw, B0_Y2_SP_ICR, 2); | 2178 | sky2_write32(hw, B0_Y2_SP_ICR, 2); |
2102 | 2179 | ||
2103 | sky2_read32(hw, B0_IMSK); | 2180 | spin_unlock(&hw->hw_lock); |
2104 | 2181 | ||
2105 | return IRQ_HANDLED; | 2182 | return IRQ_HANDLED; |
2106 | } | 2183 | } |
@@ -2141,14 +2218,12 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) | |||
2141 | 2218 | ||
2142 | static int sky2_reset(struct sky2_hw *hw) | 2219 | static int sky2_reset(struct sky2_hw *hw) |
2143 | { | 2220 | { |
2144 | u32 ctst; | ||
2145 | u16 status; | 2221 | u16 status; |
2146 | u8 t8, pmd_type; | 2222 | u8 t8, pmd_type; |
2147 | int i; | 2223 | int i; |
2148 | 2224 | ||
2149 | ctst = sky2_read32(hw, B0_CTST); | ||
2150 | |||
2151 | sky2_write8(hw, B0_CTST, CS_RST_CLR); | 2225 | sky2_write8(hw, B0_CTST, CS_RST_CLR); |
2226 | |||
2152 | hw->chip_id = sky2_read8(hw, B2_CHIP_ID); | 2227 | hw->chip_id = sky2_read8(hw, B2_CHIP_ID); |
2153 | if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { | 2228 | if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { |
2154 | printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", | 2229 | printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", |
@@ -2156,12 +2231,6 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2156 | return -EOPNOTSUPP; | 2231 | return -EOPNOTSUPP; |
2157 | } | 2232 | } |
2158 | 2233 | ||
2159 | /* ring for status responses */ | ||
2160 | hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, | ||
2161 | &hw->st_dma); | ||
2162 | if (!hw->st_le) | ||
2163 | return -ENOMEM; | ||
2164 | |||
2165 | /* disable ASF */ | 2234 | /* disable ASF */ |
2166 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { | 2235 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { |
2167 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); | 2236 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); |
@@ -2173,20 +2242,18 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2173 | sky2_write8(hw, B0_CTST, CS_RST_CLR); | 2242 | sky2_write8(hw, B0_CTST, CS_RST_CLR); |
2174 | 2243 | ||
2175 | /* clear PCI errors, if any */ | 2244 | /* clear PCI errors, if any */ |
2176 | pci_read_config_word(hw->pdev, PCI_STATUS, &status); | 2245 | status = sky2_pci_read16(hw, PCI_STATUS); |
2246 | |||
2177 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 2247 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
2178 | pci_write_config_word(hw->pdev, PCI_STATUS, | 2248 | sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS); |
2179 | status | PCI_STATUS_ERROR_BITS); | 2249 | |
2180 | 2250 | ||
2181 | sky2_write8(hw, B0_CTST, CS_MRST_CLR); | 2251 | sky2_write8(hw, B0_CTST, CS_MRST_CLR); |
2182 | 2252 | ||
2183 | /* clear any PEX errors */ | 2253 | /* clear any PEX errors */ |
2184 | if (is_pciex(hw)) { | 2254 | if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) |
2185 | u16 lstat; | 2255 | sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); |
2186 | pci_write_config_dword(hw->pdev, PEX_UNC_ERR_STAT, | 2256 | |
2187 | 0xffffffffUL); | ||
2188 | pci_read_config_word(hw->pdev, PEX_LNK_STAT, &lstat); | ||
2189 | } | ||
2190 | 2257 | ||
2191 | pmd_type = sky2_read8(hw, B2_PMD_TYP); | 2258 | pmd_type = sky2_read8(hw, B2_PMD_TYP); |
2192 | hw->copper = !(pmd_type == 'L' || pmd_type == 'S'); | 2259 | hw->copper = !(pmd_type == 'L' || pmd_type == 'S'); |
@@ -2285,8 +2352,7 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2285 | sky2_write8(hw, STAT_FIFO_ISR_WM, 16); | 2352 | sky2_write8(hw, STAT_FIFO_ISR_WM, 16); |
2286 | 2353 | ||
2287 | sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); | 2354 | sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); |
2288 | sky2_write32(hw, STAT_LEV_TIMER_INI, sky2_us2clk(hw, 100)); | 2355 | sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 7)); |
2289 | sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 20)); | ||
2290 | } | 2356 | } |
2291 | 2357 | ||
2292 | /* enable status unit */ | 2358 | /* enable status unit */ |
@@ -2551,19 +2617,24 @@ static struct net_device_stats *sky2_get_stats(struct net_device *dev) | |||
2551 | static int sky2_set_mac_address(struct net_device *dev, void *p) | 2617 | static int sky2_set_mac_address(struct net_device *dev, void *p) |
2552 | { | 2618 | { |
2553 | struct sky2_port *sky2 = netdev_priv(dev); | 2619 | struct sky2_port *sky2 = netdev_priv(dev); |
2554 | struct sockaddr *addr = p; | 2620 | struct sky2_hw *hw = sky2->hw; |
2621 | unsigned port = sky2->port; | ||
2622 | const struct sockaddr *addr = p; | ||
2555 | 2623 | ||
2556 | if (!is_valid_ether_addr(addr->sa_data)) | 2624 | if (!is_valid_ether_addr(addr->sa_data)) |
2557 | return -EADDRNOTAVAIL; | 2625 | return -EADDRNOTAVAIL; |
2558 | 2626 | ||
2559 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 2627 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
2560 | memcpy_toio(sky2->hw->regs + B2_MAC_1 + sky2->port * 8, | 2628 | memcpy_toio(hw->regs + B2_MAC_1 + port * 8, |
2561 | dev->dev_addr, ETH_ALEN); | 2629 | dev->dev_addr, ETH_ALEN); |
2562 | memcpy_toio(sky2->hw->regs + B2_MAC_2 + sky2->port * 8, | 2630 | memcpy_toio(hw->regs + B2_MAC_2 + port * 8, |
2563 | dev->dev_addr, ETH_ALEN); | 2631 | dev->dev_addr, ETH_ALEN); |
2564 | 2632 | ||
2565 | if (netif_running(dev)) | 2633 | /* virtual address for data */ |
2566 | sky2_phy_reinit(sky2); | 2634 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); |
2635 | |||
2636 | /* physical address: used for pause frames */ | ||
2637 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); | ||
2567 | 2638 | ||
2568 | return 0; | 2639 | return 0; |
2569 | } | 2640 | } |
@@ -2815,11 +2886,11 @@ static int sky2_set_coalesce(struct net_device *dev, | |||
2815 | (ecmd->rx_coalesce_usecs_irq < tmin || ecmd->rx_coalesce_usecs_irq > tmax)) | 2886 | (ecmd->rx_coalesce_usecs_irq < tmin || ecmd->rx_coalesce_usecs_irq > tmax)) |
2816 | return -EINVAL; | 2887 | return -EINVAL; |
2817 | 2888 | ||
2818 | if (ecmd->tx_max_coalesced_frames > 0xffff) | 2889 | if (ecmd->tx_max_coalesced_frames >= TX_RING_SIZE-1) |
2819 | return -EINVAL; | 2890 | return -EINVAL; |
2820 | if (ecmd->rx_max_coalesced_frames > 0xff) | 2891 | if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING) |
2821 | return -EINVAL; | 2892 | return -EINVAL; |
2822 | if (ecmd->rx_max_coalesced_frames_irq > 0xff) | 2893 | if (ecmd->rx_max_coalesced_frames_irq >RX_MAX_PENDING) |
2823 | return -EINVAL; | 2894 | return -EINVAL; |
2824 | 2895 | ||
2825 | if (ecmd->tx_coalesce_usecs == 0) | 2896 | if (ecmd->tx_coalesce_usecs == 0) |
@@ -2843,7 +2914,7 @@ static int sky2_set_coalesce(struct net_device *dev, | |||
2843 | if (ecmd->rx_coalesce_usecs_irq == 0) | 2914 | if (ecmd->rx_coalesce_usecs_irq == 0) |
2844 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_STOP); | 2915 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_STOP); |
2845 | else { | 2916 | else { |
2846 | sky2_write32(hw, STAT_TX_TIMER_INI, | 2917 | sky2_write32(hw, STAT_ISR_TIMER_INI, |
2847 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs_irq)); | 2918 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs_irq)); |
2848 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | 2919 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); |
2849 | } | 2920 | } |
@@ -3055,6 +3126,61 @@ static void __devinit sky2_show_addr(struct net_device *dev) | |||
3055 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); | 3126 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); |
3056 | } | 3127 | } |
3057 | 3128 | ||
3129 | /* Handle software interrupt used during MSI test */ | ||
3130 | static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id, | ||
3131 | struct pt_regs *regs) | ||
3132 | { | ||
3133 | struct sky2_hw *hw = dev_id; | ||
3134 | u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2); | ||
3135 | |||
3136 | if (status == 0) | ||
3137 | return IRQ_NONE; | ||
3138 | |||
3139 | if (status & Y2_IS_IRQ_SW) { | ||
3140 | sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); | ||
3141 | hw->msi = 1; | ||
3142 | } | ||
3143 | sky2_write32(hw, B0_Y2_SP_ICR, 2); | ||
3144 | |||
3145 | sky2_read32(hw, B0_IMSK); | ||
3146 | return IRQ_HANDLED; | ||
3147 | } | ||
3148 | |||
3149 | /* Test interrupt path by forcing a a software IRQ */ | ||
3150 | static int __devinit sky2_test_msi(struct sky2_hw *hw) | ||
3151 | { | ||
3152 | struct pci_dev *pdev = hw->pdev; | ||
3153 | int i, err; | ||
3154 | |||
3155 | sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); | ||
3156 | |||
3157 | err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw); | ||
3158 | if (err) { | ||
3159 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", | ||
3160 | pci_name(pdev), pdev->irq); | ||
3161 | return err; | ||
3162 | } | ||
3163 | |||
3164 | sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); | ||
3165 | wmb(); | ||
3166 | |||
3167 | for (i = 0; i < 10; i++) { | ||
3168 | barrier(); | ||
3169 | if (hw->msi) | ||
3170 | goto found; | ||
3171 | mdelay(1); | ||
3172 | } | ||
3173 | |||
3174 | err = -EOPNOTSUPP; | ||
3175 | sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); | ||
3176 | found: | ||
3177 | sky2_write32(hw, B0_IMSK, 0); | ||
3178 | |||
3179 | free_irq(pdev->irq, hw); | ||
3180 | |||
3181 | return err; | ||
3182 | } | ||
3183 | |||
3058 | static int __devinit sky2_probe(struct pci_dev *pdev, | 3184 | static int __devinit sky2_probe(struct pci_dev *pdev, |
3059 | const struct pci_device_id *ent) | 3185 | const struct pci_device_id *ent) |
3060 | { | 3186 | { |
@@ -3106,17 +3232,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3106 | } | 3232 | } |
3107 | } | 3233 | } |
3108 | 3234 | ||
3109 | #ifdef __BIG_ENDIAN | ||
3110 | /* byte swap descriptors in hardware */ | ||
3111 | { | ||
3112 | u32 reg; | ||
3113 | |||
3114 | pci_read_config_dword(pdev, PCI_DEV_REG2, ®); | ||
3115 | reg |= PCI_REV_DESC; | ||
3116 | pci_write_config_dword(pdev, PCI_DEV_REG2, reg); | ||
3117 | } | ||
3118 | #endif | ||
3119 | |||
3120 | err = -ENOMEM; | 3235 | err = -ENOMEM; |
3121 | hw = kzalloc(sizeof(*hw), GFP_KERNEL); | 3236 | hw = kzalloc(sizeof(*hw), GFP_KERNEL); |
3122 | if (!hw) { | 3237 | if (!hw) { |
@@ -3134,6 +3249,24 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3134 | goto err_out_free_hw; | 3249 | goto err_out_free_hw; |
3135 | } | 3250 | } |
3136 | hw->pm_cap = pm_cap; | 3251 | hw->pm_cap = pm_cap; |
3252 | spin_lock_init(&hw->hw_lock); | ||
3253 | |||
3254 | #ifdef __BIG_ENDIAN | ||
3255 | /* byte swap descriptors in hardware */ | ||
3256 | { | ||
3257 | u32 reg; | ||
3258 | |||
3259 | reg = sky2_pci_read32(hw, PCI_DEV_REG2); | ||
3260 | reg |= PCI_REV_DESC; | ||
3261 | sky2_pci_write32(hw, PCI_DEV_REG2, reg); | ||
3262 | } | ||
3263 | #endif | ||
3264 | |||
3265 | /* ring for status responses */ | ||
3266 | hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, | ||
3267 | &hw->st_dma); | ||
3268 | if (!hw->st_le) | ||
3269 | goto err_out_iounmap; | ||
3137 | 3270 | ||
3138 | err = sky2_reset(hw); | 3271 | err = sky2_reset(hw); |
3139 | if (err) | 3272 | if (err) |
@@ -3169,7 +3302,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3169 | } | 3302 | } |
3170 | } | 3303 | } |
3171 | 3304 | ||
3172 | err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); | 3305 | if (!disable_msi && pci_enable_msi(pdev) == 0) { |
3306 | err = sky2_test_msi(hw); | ||
3307 | if (err == -EOPNOTSUPP) { | ||
3308 | /* MSI test failed, go back to INTx mode */ | ||
3309 | printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " | ||
3310 | "switching to INTx mode. Please report this failure to " | ||
3311 | "the PCI maintainer and include system chipset information.\n", | ||
3312 | pci_name(pdev)); | ||
3313 | pci_disable_msi(pdev); | ||
3314 | } | ||
3315 | else if (err) | ||
3316 | goto err_out_unregister; | ||
3317 | } | ||
3318 | |||
3319 | err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, | ||
3320 | DRV_NAME, hw); | ||
3173 | if (err) { | 3321 | if (err) { |
3174 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", | 3322 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", |
3175 | pci_name(pdev), pdev->irq); | 3323 | pci_name(pdev), pdev->irq); |
@@ -3184,6 +3332,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3184 | return 0; | 3332 | return 0; |
3185 | 3333 | ||
3186 | err_out_unregister: | 3334 | err_out_unregister: |
3335 | if (hw->msi) | ||
3336 | pci_disable_msi(pdev); | ||
3187 | if (dev1) { | 3337 | if (dev1) { |
3188 | unregister_netdev(dev1); | 3338 | unregister_netdev(dev1); |
3189 | free_netdev(dev1); | 3339 | free_netdev(dev1); |
@@ -3226,6 +3376,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) | |||
3226 | sky2_read8(hw, B0_CTST); | 3376 | sky2_read8(hw, B0_CTST); |
3227 | 3377 | ||
3228 | free_irq(pdev->irq, hw); | 3378 | free_irq(pdev->irq, hw); |
3379 | if (hw->msi) | ||
3380 | pci_disable_msi(pdev); | ||
3229 | pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); | 3381 | pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); |
3230 | pci_release_regions(pdev); | 3382 | pci_release_regions(pdev); |
3231 | pci_disable_device(pdev); | 3383 | pci_disable_device(pdev); |
@@ -3263,25 +3415,33 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3263 | static int sky2_resume(struct pci_dev *pdev) | 3415 | static int sky2_resume(struct pci_dev *pdev) |
3264 | { | 3416 | { |
3265 | struct sky2_hw *hw = pci_get_drvdata(pdev); | 3417 | struct sky2_hw *hw = pci_get_drvdata(pdev); |
3266 | int i; | 3418 | int i, err; |
3267 | 3419 | ||
3268 | pci_restore_state(pdev); | 3420 | pci_restore_state(pdev); |
3269 | pci_enable_wake(pdev, PCI_D0, 0); | 3421 | pci_enable_wake(pdev, PCI_D0, 0); |
3270 | sky2_set_power_state(hw, PCI_D0); | 3422 | err = sky2_set_power_state(hw, PCI_D0); |
3423 | if (err) | ||
3424 | goto out; | ||
3271 | 3425 | ||
3272 | sky2_reset(hw); | 3426 | err = sky2_reset(hw); |
3427 | if (err) | ||
3428 | goto out; | ||
3273 | 3429 | ||
3274 | for (i = 0; i < 2; i++) { | 3430 | for (i = 0; i < 2; i++) { |
3275 | struct net_device *dev = hw->dev[i]; | 3431 | struct net_device *dev = hw->dev[i]; |
3276 | if (dev) { | 3432 | if (dev && netif_running(dev)) { |
3277 | if (netif_running(dev)) { | 3433 | netif_device_attach(dev); |
3278 | netif_device_attach(dev); | 3434 | err = sky2_up(dev); |
3279 | if (sky2_up(dev)) | 3435 | if (err) { |
3280 | dev_close(dev); | 3436 | printk(KERN_ERR PFX "%s: could not up: %d\n", |
3437 | dev->name, err); | ||
3438 | dev_close(dev); | ||
3439 | break; | ||
3281 | } | 3440 | } |
3282 | } | 3441 | } |
3283 | } | 3442 | } |
3284 | return 0; | 3443 | out: |
3444 | return err; | ||
3285 | } | 3445 | } |
3286 | #endif | 3446 | #endif |
3287 | 3447 | ||