diff options
author | xiong <xiong@qca.qualcomm.com> | 2012-12-17 08:20:53 -0700 |
---|---|---|
committer | Luis R. Rodriguez <mcgrof@do-not-panic.com> | 2012-12-17 20:18:11 -0800 |
commit | fcbfd447c62159501fb817eac6cd99ea8577975f (patch) | |
tree | 0d5867597c5b88204d097b9c1591c2ff05085966 | |
parent | f1fb77cb93c8055a7630bfde676e7db87e0272c3 (diff) | |
download | alx-fcbfd447c62159501fb817eac6cd99ea8577975f.tar.gz |
alx: fix tx-timeout and WoL wrong speed setting
this patch fixed followking issues:
1. WoL seed is wrongly set to 100M, revise it to 10M.
2. tx-timeout after sleep/resume. it's caused by wrong interrupt mode.
3. add stats/diag features for ethtool.
TODO:
the diag(self-test) function is very simple for this version,
we will add loopback/interrupt test for next version.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
-rw-r--r-- | src/alx.h | 5 | ||||
-rw-r--r-- | src/alx_ethtool.c | 659 | ||||
-rw-r--r-- | src/alx_hw.c | 25 | ||||
-rw-r--r-- | src/alx_hw.h | 139 | ||||
-rw-r--r-- | src/alx_main.c | 250 |
5 files changed, 884 insertions, 194 deletions
@@ -174,6 +174,9 @@ struct alx_adapter { u16 msg_enable; unsigned long flags; + + /* ethtool private flags */ + u32 eth_pflags; }; @@ -189,6 +192,6 @@ struct alx_adapter { extern void alx_reinit(struct alx_adapter *adpt); extern void __devinit alx_set_ethtool_ops(struct net_device *dev); extern char alx_drv_name[]; - +extern char alx_drv_version[]; #endif diff --git a/src/alx_ethtool.c b/src/alx_ethtool.c index 0c04f56..cc88584 100644 --- a/src/alx_ethtool.c +++ b/src/alx_ethtool.c @@ -239,7 +239,7 @@ static const u32 hw_regs[] = { static int alx_get_regs_len(struct net_device *netdev) { - return (ARRAY_SIZE(hw_regs) + 1) * 4; + return (ARRAY_SIZE(hw_regs) + 0x20) * 4; } static void alx_get_regs(struct net_device *netdev, @@ -252,28 +252,16 @@ static void alx_get_regs(struct net_device *netdev, regs->version = (ALX_DID(hw) << 16) | (ALX_REVID(hw) << 8) | 1; - memset(buff, 0, (ARRAY_SIZE(hw_regs) + 1) * 4); + memset(buff, 0, (ARRAY_SIZE(hw_regs) + 0x20) * 4); for (i = 0; i < ARRAY_SIZE(hw_regs); i++, p++) ALX_MEM_R32(hw, hw_regs[i], p); - /* last one for PHY Link Status */ - alx_read_phy_reg(hw, MII_BMSR, (u16 *)p); -} - -static void alx_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) -{ - struct alx_adapter *adpt = netdev_priv(netdev); - - strlcpy(drvinfo->driver, alx_drv_name, sizeof(drvinfo->driver)); - strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); - strlcpy(drvinfo->bus_info, pci_name(adpt->pdev), - sizeof(drvinfo->bus_info)); - drvinfo->n_stats = 0; - drvinfo->testinfo_len = 0; - drvinfo->regdump_len = alx_get_regs_len(netdev); - drvinfo->eedump_len = 0; + /* last 0x20 for PHY register */ + for (i = 0; i < 0x20; i++) { + alx_read_phy_reg(hw, i, (u16 *)p); + p++; + } } static void alx_get_wol(struct net_device *netdev, @@ -311,6 +299,8 @@ static int alx_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & WAKE_PHY) hw->sleep_ctrl |= ALX_SLEEP_WOL_PHY; + netdev_info(adpt->netdev, "wol-ctrl=%X\n", hw->sleep_ctrl); + device_set_wakeup_enable(&adpt->pdev->dev, hw->sleep_ctrl); return 0; @@ -327,6 +317,631 @@ static int alx_nway_reset(struct net_device *netdev) return 0; } +static const char alx_gstrings_test[][ETH_GSTRING_LEN] = { + "register test (offline)", + "memory test (offline)", + "interrupt test (offline)", + "loopback test (offline)", + "link test (offline)" +}; +#define ALX_TEST_LEN (sizeof(alx_gstrings_test) / ETH_GSTRING_LEN) + +/* private flags */ +#define ALX_ETH_PF_LNK_10MH BIT(0) +#define ALX_ETH_PF_LNK_10MF BIT(1) +#define ALX_ETH_PF_LNK_100MH BIT(2) +#define ALX_ETH_PF_LNK_100MF BIT(3) +#define ALX_ETH_PF_LNK_1000MF BIT(4) +#define ALX_ETH_PF_LNK_MASK (\ + ALX_ETH_PF_LNK_10MH |\ + ALX_ETH_PF_LNK_10MF |\ + ALX_ETH_PF_LNK_100MH |\ + ALX_ETH_PF_LNK_100MF |\ + ALX_ETH_PF_LNK_1000MF) + +static const char alx_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", + "rx_bcast_packets", + "rx_mcast_packets", + "rx_pause_packets", + "rx_ctrl_packets", + "rx_fcs_errors", + "rx_length_errors", + "rx_bytes", + "rx_runt_packets", + "rx_fragments", + "rx_64B_or_less_packets", + "rx_65B_to_127B_packets", + "rx_128B_to_255B_packets", + "rx_256B_to_511B_packets", + "rx_512B_to_1023B_packets", + "rx_1024B_to_1518B_packets", + "rx_1519B_to_mtu_packets", + "rx_oversize_packets", + "rx_rxf_ov_drop_packets", + "rx_rrd_ov_drop_packets", + "rx_align_errors", + "rx_bcast_bytes", + "rx_mcast_bytes", + "rx_address_errors", + "tx_packets", + "tx_bcast_packets", + "tx_mcast_packets", + "tx_pause_packets", + "tx_exc_defer_packets", + "tx_ctrl_packets", + "tx_defer_packets", + "tx_bytes", + "tx_64B_or_less_packets", + "tx_65B_to_127B_packets", + "tx_128B_to_255B_packets", + "tx_256B_to_511B_packets", + "tx_512B_to_1023B_packets", + "tx_1024B_to_1518B_packets", + "tx_1519B_to_mtu_packets", + "tx_single_collision", + "tx_multiple_collisions", + "tx_late_collision", + "tx_abort_collision", + "tx_underrun", + "tx_trd_eop", + "tx_length_errors", + "tx_trunc_packets", + "tx_bcast_bytes", + "tx_mcast_bytes", + "tx_update", +}; + +#define ALX_STATS_LEN (sizeof(alx_gstrings_stats) / ETH_GSTRING_LEN) + +static void alx_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_TEST: + memcpy(buf, &alx_gstrings_test, sizeof(alx_gstrings_test)); + break; + case ETH_SS_STATS: + memcpy(buf, &alx_gstrings_stats, sizeof(alx_gstrings_stats)); + break; + } +} + +static int alx_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ALX_STATS_LEN; + case ETH_SS_TEST: + return ALX_TEST_LEN; + default: + return -ENOTSUPP; + } +} + +struct alx_reg_attr { + u16 reg; + u32 ro_mask; + u32 rw_mask; + u32 rc_mask; + u32 rst_val; + u8 rst_affect; +}; + +struct alx_reg_attr ar816x_regs_a[] = { + {0x1400, 0xffff80E0, 0x4D00, 0x0, 0x40020000, 0}, + {0x1404, 0x0, 0xffffffff, 0x0, 0x0, 1}, + {0x1408, 0x0, 0xffffffff, 0x0, 0x0, 1}, + {0x140c, 0xFFFF0000, 0x0, 0x0, 0xffff3800, 0}, + {0x1410, 0xffffffff, 0x0, 0x0, 0x0000, 0}, + {0x1414, 0x0, 0x0, 0x0, 0x0, 1}, + {0x141C, 0xfffffffe, 0x0, 0x0, 0x0, 1}, + {0x1420, 0xfffffffe, 0x0, 0x0, 0x0, 1}, + {0x1484, 0x0, 0x7f7f7f7f, 0x0, 0x60405060, 1}, + {0x1490, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1494, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1498, 0x0, 0xffff3ff, 0x0, 0x07a1f037, 1}, + {0x149C, 0xffff0000, 0xffff, 0x0, 0x600, 1}, + {0x14a0, 0x808078c0, 0x7f803f, 0x7f000700, 0x0, 1}, + {0x14a4, 0x0, 0xFFFFFFFF, 0x0, 0x0, 1}, + {0x14a8, 0xFF000000, 0x00FFFFFF, 0x0, 0x0, 1}, + {0x1540, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1544, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1550, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1560, 0xFFFFF000, 0xfff, 0x0, 0x0, 0}, + {0x1564, 0xFFFF0000, 0xffff, 0x0, 0x0, 0}, + {0x1568, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1578, 0xFFFFF000, 0xfff, 0x0, 0x0, 0}, + {0x157C, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1580, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1584, 0xFFFF0000, 0xffff, 0x0, 0x0, 0}, + {0x1588, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1590, 0xFF00, 0xFFFF00DF, 0x0, 0x01000045, 1}, + {0x1594, 0xFFFFF800, 0x7FF, 0x0, 191, 1}, + {0x15A0, 0x200E0040, 0x5FF1FFBF, 0x0, 0x40810083, 1}, + {0x15A4, 0xFFFFF000, 0xFFF, 0x0, 0x1210, 1}, + {0x15A8, 0xF000F000, 0x0FFF0FFF, 0x0, 0x02E003C0, 1}, + {0x15AC, 0xF000, 0xFFFF0FFF, 0x0, 0x0100, 1}, + {0x15C4, 0xFF000000, 0xFFFFFF, 0x0, 0x0, 1}, + {0x15C8, 0xFFFF0000, 0xFFFF, 0x0, 0x0100, 1}, + {0x15E0, 0xFFFFF000, 0xFFF, 0x0, 0x0, 1}, + {0x15F0, 0x0, 0xFFFFFFFF, 0x0, 0x0, 1}, + {0x15F4, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x15F8, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x15FC, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x1700, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1704, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1708, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x170c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1710, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1714, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1718, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x171c, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1720, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1724, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1728, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x172c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1730, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1734, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1738, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x173c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1740, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1744, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1748, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x174c, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x1750, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1754, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1758, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x175c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1760, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1764, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1768, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x176c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1770, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x1774, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1778, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x177c, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1780, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1784, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1788, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x178c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1790, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1794, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1798, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x179c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a0, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a4, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a8, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17ac, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b0, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b4, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b8, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17bc, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x17c0, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0xffff, 0, 0, 0, 0, 0}, +}; + +struct alx_reg_attr ar816x_regs_b[] = { + {0x1400, 0xffff80E0, 0x4D00, 0x0, 0x40020000, 0}, + {0x1404, 0x0, 0xffffffff, 0x0, 0x0, 1}, + {0x1408, 0x0, 0xffffffff, 0x0, 0x0, 1}, + {0x140c, 0xFFFF0000, 0x0, 0x0, 0xffff3800, 0}, + {0x1410, 0xffffffff, 0x0, 0x0, 0x0000, 0}, + {0x1414, 0x0, 0x0, 0x0, 0x0, 1}, + {0x141C, 0xfffffffe, 0x0, 0x0, 0x0, 1}, + {0x1420, 0xfffffffe, 0x0, 0x0, 0x0, 1}, + {0x1484, 0x0, 0x7f7f7f7f, 0x0, 0x60405018, 1}, + {0x1490, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1494, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1498, 0x0, 0xffff3ff, 0x0, 0x07a1f037, 1}, + {0x149C, 0xffff0000, 0xffff, 0x0, 0x600, 1}, + {0x14a0, 0x808078c0, 0x7f803f, 0x7f000700, 0x0, 1}, + {0x14a4, 0x0, 0xFFFFFFFF, 0x0, 0x0, 1}, + {0x14a8, 0xFF000000, 0x00FFFFFF, 0x0, 0x0, 1}, + {0x1540, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1544, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1550, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1560, 0xFFFFF000, 0xfff, 0x0, 0x0, 0}, + {0x1564, 0xFFFF0000, 0xffff, 0x0, 0x0, 0}, + {0x1568, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1578, 0xFFFFF000, 0xfff, 0x0, 0x0, 0}, + {0x157C, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1580, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1584, 0xFFFF0000, 0xffff, 0x0, 0x0, 0}, + {0x1588, 0x0, 0xffffffff, 0x0, 0x0, 0}, + {0x1590, 0xFF00, 0xFFFF00DF, 0x0, 0x01000045, 1}, + {0x1594, 0xFFFFF800, 0x7FF, 0x0, 191, 1}, + {0x15A0, 0x200E0040, 0x5FF1FFBF, 0x0, 0x40810083, 1}, + {0x15A4, 0xFFFFF000, 0xFFF, 0x0, 0x1210, 1}, + {0x15A8, 0xF000F000, 0x0FFF0FFF, 0x0, 0x02E003C0, 1}, + {0x15AC, 0xF000, 0xFFFF0FFF, 0x0, 0x0100, 1}, + {0x15C4, 0xFF000000, 0xFFFFFF, 0x0, 0x0, 1}, + {0x15C8, 0xFFFF0000, 0xFFFF, 0x0, 0x0100, 1}, + {0x15E0, 0xFFFFF000, 0xFFF, 0x0, 0x0, 1}, + {0x15F0, 0x0, 0xFFFFFFFF, 0x0, 0x0, 1}, + {0x15F4, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x15F8, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x15FC, 0xFFFFFFFF, 0x0, 0x0, 0x0, 1}, + {0x1700, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1704, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1708, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x170c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1710, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1714, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1718, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x171c, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1720, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1724, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1728, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x172c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1730, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1734, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1738, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x173c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1740, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1744, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1748, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x174c, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x1750, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1754, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1758, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x175c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1760, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1764, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1768, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x176c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1770, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x1774, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1778, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x177c, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x1780, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1784, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1788, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x178c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1790, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1794, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x1798, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x179c, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a0, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a4, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17a8, 0xffffffff, 0x0, 0xffffff, 0x0, 1}, + {0x17ac, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b0, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b4, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17b8, 0xffffffff, 0x0, 0xffff, 0x0, 1}, + {0x17bc, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0x17c0, 0xffffffff, 0x0, 0xffffffff, 0x0, 1}, + {0xffff, 0, 0, 0, 0, 0}, +}; + +static int alx_diag_register(struct alx_adapter *adpt, u64 *data) +{ + struct alx_hw *hw = &adpt->hw; + struct alx_reg_attr *preg, *oreg; + u32 val, old; + + switch (ALX_DID(hw)) { + case ALX_DEV_ID_AR8161: + case ALX_DEV_ID_AR8162: + case ALX_DEV_ID_AR8171: + case ALX_DEV_ID_AR8172: + oreg = ALX_REV_B0 == ALX_REVID(hw) ? + ar816x_regs_b : ar816x_regs_a; + break; + default: + /* unknow type */ + *data = 1; + return -EIO; + } + + /* issue a MAC-reset */ + ALX_MEM_W32(hw, ALX_MASTER, ALX_MASTER_DMA_MAC_RST); + msleep(50); + + /* check reset value */ + preg = oreg; + while (preg->reg != 0xffff) { + if (preg->rst_affect) { + ALX_MEM_R32(hw, preg->reg, &val); + if (val != preg->rst_val) { + netif_err(adpt, hw, adpt->netdev, + "register %X, hard-rst:%X, read-val:%X\n", + preg->reg, preg->rst_val, val); + *data = 2; + return -EIO; + } + } + preg++; + } + + /* check read-clear/read-write attribute */ + preg = oreg; + + while (preg->reg != 0xffff) { + ALX_MEM_R32(hw, preg->reg, &old); + + /* read clear */ + if (preg->rc_mask) { + u32 v2; + + msleep(20); + ALX_MEM_R32(hw, preg->reg, &v2); + if ((v2 & preg->rc_mask) != 0) { + netif_err(adpt, hw, adpt->netdev, + "register %X, RC-mask:%X, Old:%X, New:%X\n", + preg->reg, preg->rc_mask, old, v2); + *data = 3; + return -EIO; + } + } + + /* read/write */ + ALX_MEM_W32(hw, preg->reg, 0xffffffff & preg->rw_mask); + ALX_MEM_FLUSH(hw); + ALX_MEM_R32(hw, preg->reg, &val); + if ((val & preg->rw_mask) != preg->rw_mask) { + netif_err(adpt, hw, adpt->netdev, + "register %X, RW-mask:%X, val-1:%X\n", + preg->reg, preg->rw_mask, val); + *data = 4; + return -EIO; + } + ALX_MEM_W32(hw, preg->reg, 0); + ALX_MEM_FLUSH(hw); + ALX_MEM_R32(hw, preg->reg, &val); + if ((val & preg->rw_mask) != 0) { + netif_err(adpt, hw, adpt->netdev, + "register %X, RW-mask:%X, val-0:%X\n", + preg->reg, preg->rw_mask, val); + *data = 4; + return -EIO; + } + + /* restore */ + ALX_MEM_W32(hw, preg->reg, old); + + preg++; + } + + return 0; +} + +static int alx_diag_sram(struct alx_adapter *adpt, u64 *data) +{ + struct alx_hw *hw = &adpt->hw; + u32 ret[2]; + int i, err; + + err = alx_reset_mac(hw); + if (err) { + netif_err(adpt, hw, adpt->netdev, "reset_mac fail %d\n", err); + *data = 1; + goto out; + } + /* issue bist command */ + ALX_MEM_W32(hw, ALX_BIST0, ALX_BIST0_START); + ALX_MEM_W32(hw, ALX_BIST1, ALX_BIST1_START); + + /* wait for 100ms */ + ret[1] = ret[0] = 0; + for (i = 0; i < 5; i++) { + msleep(20); + ALX_MEM_R32(hw, ALX_BIST0, &ret[0]); + ALX_MEM_R32(hw, ALX_BIST1, &ret[1]); + if (ret[0] & ALX_BIST0_START || ret[1] & ALX_BIST1_START) + continue; + else + break; + } + + for (i = 0; i < 2; i++) { + if (ret[i] & ALX_BIST0_START) { + netif_err(adpt, hw, adpt->netdev, + "sram(%d) bist not complete(%X)!\n", + i, ret[i]); + *data = 2; + err = -EIO; + goto out; + } + if (ret[i] & ALX_BIST0_FAIL) { + netif_err(adpt, hw, adpt->netdev, + "sram(%d) bist fail(%X)!\n", + i, ret[i]); + *data = 3; + err = -EIO; + goto out; + } + } +out: + return err; +} + +static int alx_diag_reset(struct alx_adapter *adpt) +{ + struct alx_hw *hw = &adpt->hw; + int err; + + alx_reset_pcie(hw); + alx_reset_phy(hw, !hw->hib_patch); + err = alx_reset_mac(hw); + if (!err) + err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl); + + if (err) { + netif_err(adpt, hw, adpt->netdev, "alx_diag_reset err %X\n", + err); + } + + return err; +} + +static int alx_diag_link(struct alx_adapter *adpt, u64 *data) +{ + struct alx_hw *hw = &adpt->hw; + u32 flags, ethadv; + u16 speed; + u8 fc; + int i, err; + + ethadv = ADVERTISED_Autoneg; + flags = adpt->eth_pflags & ALX_ETH_PF_LNK_MASK; + if (flags == 0) + flags = ALX_ETH_PF_LNK_MASK; + if (flags & ALX_ETH_PF_LNK_10MH) + ethadv |= ADVERTISED_10baseT_Half; + if (flags & ALX_ETH_PF_LNK_10MF) + ethadv |= ADVERTISED_10baseT_Full; + if (flags & ALX_ETH_PF_LNK_100MH) + ethadv |= ADVERTISED_100baseT_Half; + if (flags & ALX_ETH_PF_LNK_100MF) + ethadv |= ADVERTISED_100baseT_Full; + if (flags & ALX_ETH_PF_LNK_1000MF) + ethadv |= ADVERTISED_1000baseT_Full; + + fc = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX; + + alx_reset_phy(hw, !hw->hib_patch); + err = alx_setup_speed_duplex(hw, ethadv, fc); + if (err) { + netif_err(adpt, hw, adpt->netdev, + "config PHY speed/duplex failed, adv=%X,err=%d\n", + ethadv, err); + *data = 1; + goto out; + } + + /* wait for linkup */ + for (i = 0; i < ALX_MAX_SETUP_LNK_CYCLE; i++) { + bool link_up; + + msleep(100); + err = alx_get_phy_link(hw, &link_up, &speed); + if (err) { + netif_err(adpt, hw, adpt->netdev, + "get PHY speed/duplex failed,err=%d\n", + err); + *data = 2; + goto out; + } + if (link_up) + break; + } + if (i == ALX_MAX_SETUP_LNK_CYCLE) { + err = ALX_LINK_TIMEOUT; + netif_err(adpt, hw, adpt->netdev, + "get PHY speed/duplex timeout.\n"); + *data = 3; + goto out; + } + + netif_info(adpt, hw, adpt->netdev, "link:%s\n", speed_desc(speed)); + +out: + return err; +} + +static int alx_diag_interrupt(struct alx_adapter *adpt, u64 *data) +{ + + return 0; +} + + +static int alx_diag_loopback(struct alx_adapter *adpt, u64 *data, bool phy_lpbk) +{ + return 0; +} + +static void alx_self_test(struct net_device *netdev, + struct ethtool_test *etest, + u64 *data) +{ + struct alx_adapter *adpt = netdev_priv(netdev); + bool if_running = netif_running(netdev); + bool phy_lpback = etest->flags & ETH_TEST_FL_EXTERNAL_LB; + + ALX_FLAG_SET(adpt, TESTING); + memset(data, 0, sizeof(u64) * ALX_TEST_LEN); + + if (if_running) + dev_close(netdev); + + if (etest->flags == ETH_TEST_FL_OFFLINE) { + netif_info(adpt, hw, adpt->netdev, "offline test start...\n"); + + if (alx_diag_register(adpt, &data[0])) + etest->flags |= ETH_TEST_FL_FAILED; + + if (alx_diag_sram(adpt, &data[1])) + etest->flags |= ETH_TEST_FL_FAILED; + + if (alx_diag_interrupt(adpt, &data[2])) + etest->flags |= ETH_TEST_FL_FAILED; + + if (phy_lpback) + etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; + if (alx_diag_loopback(adpt, &data[3], phy_lpback)) + etest->flags |= ETH_TEST_FL_FAILED; + + } else { + netif_info(adpt, hw, adpt->netdev, "online test start...\n"); + + if (alx_diag_link(adpt, &data[4])) + etest->flags |= ETH_TEST_FL_FAILED; + } + + ALX_FLAG_CLEAR(adpt, TESTING); + alx_diag_reset(adpt); + + if (if_running) + dev_open(netdev); +} + +static void alx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *estats, u64 *data) +{ + struct alx_adapter *adpt = netdev_priv(netdev); + struct alx_hw *hw = &adpt->hw; + + spin_lock(&adpt->smb_lock); + + __alx_update_hw_stats(hw); + memcpy(data, &hw->stats, sizeof(hw->stats)); + + spin_unlock(&adpt->smb_lock); +} + +static u32 alx_get_priv_flags(struct net_device *netdev) +{ + struct alx_adapter *adpt = netdev_priv(netdev); + + return adpt->eth_pflags; +} + +static int alx_set_priv_flags(struct net_device *netdev, u32 flags) +{ + struct alx_adapter *adpt = netdev_priv(netdev); + + adpt->eth_pflags = flags; + + return 0; +} + +static void alx_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct alx_adapter *adpt = netdev_priv(netdev); + + strlcpy(drvinfo->driver, alx_drv_name, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, alx_drv_version, sizeof(drvinfo->version)); + strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strlcpy(drvinfo->bus_info, pci_name(adpt->pdev), + sizeof(drvinfo->bus_info)); + drvinfo->n_stats = ALX_STATS_LEN; + drvinfo->testinfo_len = ALX_TEST_LEN; + drvinfo->n_priv_flags = 5; + drvinfo->regdump_len = alx_get_regs_len(netdev); + drvinfo->eedump_len = 0; +} static const struct ethtool_ops alx_ethtool_ops = { .get_settings = alx_get_settings, @@ -342,6 +957,12 @@ static const struct ethtool_ops alx_ethtool_ops = { .set_msglevel = alx_set_msglevel, .nway_reset = alx_nway_reset, .get_link = ethtool_op_get_link, + .get_strings = alx_get_strings, + .get_sset_count = alx_get_sset_count, + .get_ethtool_stats = alx_get_ethtool_stats, + .self_test = alx_self_test, + .get_priv_flags = alx_get_priv_flags, + .set_priv_flags = alx_set_priv_flags, }; void __devinit alx_set_ethtool_ops(struct net_device *dev) diff --git a/src/alx_hw.c b/src/alx_hw.c index 7a220c6..a15d77a 100644 --- a/src/alx_hw.c +++ b/src/alx_hw.c @@ -765,11 +765,8 @@ int alx_pre_suspend(struct alx_hw *hw, u16 speed) if (speed >= SPEED_1000) FIELD_SET32(mac, ALX_MAC_CTRL_SPEED, ALX_MAC_CTRL_SPEED_1000); phy |= ALX_PHY_CTRL_DSPRST_OUT; - if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY) - err = alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP); - if (!err) - err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, - ALX_MIIEXT_S3DIG10, ALX_MIIEXT_S3DIG10_SL); + err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, + ALX_MIIEXT_S3DIG10, ALX_MIIEXT_S3DIG10_SL); config_reg: if (!err) { @@ -1306,6 +1303,7 @@ int alx_select_powersaving_speed(struct alx_hw *hw, u16 *speed) *speed = spd; goto out; } +#if 0 if (lpa & LPA_100FULL) *speed = SPEED_100 + FULL_DUPLEX; else if (lpa & LPA_100HALF) @@ -1314,9 +1312,20 @@ int alx_select_powersaving_speed(struct alx_hw *hw, u16 *speed) *speed = SPEED_10 + FULL_DUPLEX; else *speed = SPEED_10 + HALF_DUPLEX; - +#else + if (lpa & LPA_10FULL) + *speed = SPEED_10 + FULL_DUPLEX; + else if (lpa & LPA_10HALF) + *speed = SPEED_10 + HALF_DUPLEX; + else if (lpa & LPA_100FULL) + *speed = SPEED_100 + FULL_DUPLEX; + else + *speed = SPEED_100 + HALF_DUPLEX; +#endif if (*speed != spd) { - + err = alx_write_phy_reg(hw, ALX_MII_IER, 0); + if (err) + goto out; err = alx_setup_speed_duplex(hw, ALX_SPEED_TO_ETHADV(*speed) | ADVERTISED_Autoneg, ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX); @@ -1349,7 +1358,7 @@ void __alx_update_hw_stats(struct alx_hw *hw) { u16 reg; u32 data; - unsigned long *p; + u64 *p; /* RX stats */ reg = ALX_RX_STATS_BIN; diff --git a/src/alx_hw.h b/src/alx_hw.h index 8790869..3f69b02 100644 --- a/src/alx_hw.h +++ b/src/alx_hw.h @@ -315,58 +315,58 @@ struct rrd_desc { /* Statistics counters collected by the MAC */ struct alx_hw_stats { /* rx */ - unsigned long rx_ok; - unsigned long rx_bcast; - unsigned long rx_mcast; - unsigned long rx_pause; - unsigned long rx_ctrl; - unsigned long rx_fcs_err; - unsigned long rx_len_err; - unsigned long rx_byte_cnt; - unsigned long rx_runt; - unsigned long rx_frag; - unsigned long rx_sz_64B; - unsigned long rx_sz_127B; - unsigned long rx_sz_255B; - unsigned long rx_sz_511B; - unsigned long rx_sz_1023B; - unsigned long rx_sz_1518B; - unsigned long rx_sz_max; - unsigned long rx_ov_sz; - unsigned long rx_ov_rxf; - unsigned long rx_ov_rrd; - unsigned long rx_align_err; - unsigned long rx_bc_byte_cnt; - unsigned long rx_mc_byte_cnt; - unsigned long rx_err_addr; + u64 rx_ok; + u64 rx_bcast; + u64 rx_mcast; + u64 rx_pause; + u64 rx_ctrl; + u64 rx_fcs_err; + u64 rx_len_err; + u64 rx_byte_cnt; + u64 rx_runt; + u64 rx_frag; + u64 rx_sz_64B; + u64 rx_sz_127B; + u64 rx_sz_255B; + u64 rx_sz_511B; + u64 rx_sz_1023B; + u64 rx_sz_1518B; + u64 rx_sz_max; + u64 rx_ov_sz; + u64 rx_ov_rxf; + u64 rx_ov_rrd; + u64 rx_align_err; + u64 rx_bc_byte_cnt; + u64 rx_mc_byte_cnt; + u64 rx_err_addr; /* tx */ - unsigned long tx_ok; - unsigned long tx_bcast; - unsigned long tx_mcast; - unsigned long tx_pause; - unsigned long tx_exc_defer; - unsigned long tx_ctrl; - unsigned long tx_defer; - unsigned long tx_byte_cnt; - unsigned long tx_sz_64B; - unsigned long tx_sz_127B; - unsigned long tx_sz_255B; - unsigned long tx_sz_511B; - unsigned long tx_sz_1023B; - unsigned long tx_sz_1518B; - unsigned long tx_sz_max; - unsigned long tx_single_col; - unsigned long tx_multi_col; - unsigned long tx_late_col; - unsigned long tx_abort_col; - unsigned long tx_underrun; - unsigned long tx_trd_eop; - unsigned long tx_len_err; - unsigned long tx_trunc; - unsigned long tx_bc_byte_cnt; - unsigned long tx_mc_byte_cnt; - unsigned long update; + u64 tx_ok; + u64 tx_bcast; + u64 tx_mcast; + u64 tx_pause; + u64 tx_exc_defer; + u64 tx_ctrl; + u64 tx_defer; + u64 tx_byte_cnt; + u64 tx_sz_64B; + u64 tx_sz_127B; + u64 tx_sz_255B; + u64 tx_sz_511B; + u64 tx_sz_1023B; + u64 tx_sz_1518B; + u64 tx_sz_max; + u64 tx_single_col; + u64 tx_multi_col; + u64 tx_late_col; + u64 tx_abort_col; + u64 tx_underrun; + u64 tx_trd_eop; + u64 tx_len_err; + u64 tx_trunc; + u64 tx_bc_byte_cnt; + u64 tx_mc_byte_cnt; + u64 update; }; #define SPEED_0 0 @@ -382,6 +382,19 @@ struct alx_hw_stats { (_speed) == SPEED_10 + HALF_DUPLEX ? ADVERTISED_10baseT_Half : \ 0) +#define speed_desc(_s) (\ + (_s) == SPEED_1000 + FULL_DUPLEX ? \ + "1 Gbps Full" : \ + (_s) == SPEED_100 + FULL_DUPLEX ? \ + "100 Mbps Full" : \ + (_s) == SPEED_100 + HALF_DUPLEX ? \ + "100 Mbps Half" : \ + (_s) == SPEED_10 + FULL_DUPLEX ? \ + "10 Mbps Full" : \ + (_s) == SPEED_10 + HALF_DUPLEX ? \ + "10 Mbps Half" : \ + "Unknown speed") + /* for FlowControl */ #define ALX_FC_RX 0x01 #define ALX_FC_TX 0x02 @@ -550,26 +563,52 @@ enum ALX_CAPS { #define ALX_CAP_CLEAR(_hw, _cap) (\ clear_bit(ALX_CAP_##_cap, &(_hw)->capability)) +#define ALX_READ_ISSUE_FIXED 1 + /* write to 8bit register via pci memory space */ #define ALX_MEM_W8(s, reg, val) (writeb((val), ((s)->hw_addr + reg))) /* read from 8bit register via pci memory space */ +#if ALX_READ_ISSUE_FIXED #define ALX_MEM_R8(s, reg, pdat) (\ *(u8 *)(pdat) = readb((s)->hw_addr + reg)) +#else +#define ALX_MEM_R8(s, reg, pdat) do { \ + if (!(s)->link_up) \ + readl((s)->hw_addr + ((reg) & 0xFFFC)); \ + *(u8 *)(pdat) = readb((s)->hw_addr + reg);\ + } while (0) +#endif /* write to 16bit register via pci memory space */ #define ALX_MEM_W16(s, reg, val) (writew((val), ((s)->hw_addr + reg))) /* read from 16bit register via pci memory space */ +#if ALX_READ_ISSUE_FIXED #define ALX_MEM_R16(s, reg, pdat) (\ *(u16 *)(pdat) = readw((s)->hw_addr + reg)) +#else +#define ALX_MEM_R16(s, reg, pdat) do { \ + if (!(s)->link_up) \ + readl((s)->hw_addr + ((reg) & 0xFFFC)); \ + *(u16 *)(pdat) = readw((s)->hw_addr + reg); \ + } while (0) +#endif /* write to 32bit register via pci memory space */ #define ALX_MEM_W32(s, reg, val) (writel((val), ((s)->hw_addr + reg))) /* read from 32bit register via pci memory space */ +#if ALX_READ_ISSUE_FIXED #define ALX_MEM_R32(s, reg, pdat) (\ *(u32 *)(pdat) = readl((s)->hw_addr + reg)) +#else +#define ALX_MEM_R32(s, reg, pdat) do { \ + if (!(s)->link_up) \ + readl((s)->hw_addr + (reg)); \ + *(u32 *)(pdat) = readl((s)->hw_addr + reg); \ + } while (0) +#endif /* read from 16bit register via pci config space */ #define ALX_CFG_R16(s, reg, pdat) (\ diff --git a/src/alx_main.c b/src/alx_main.c index 23b93f8..6514af9 100644 --- a/src/alx_main.c +++ b/src/alx_main.c @@ -31,7 +31,15 @@ #include "alx_hw.h" #include "alx.h" +#define DRV_MAJ 1 +#define DRV_MIN 2 +#define DRV_PATCH 1 +#define DRV_MODULE_VER \ + __stringify(DRV_MAJ) "." __stringify(DRV_MIN) "." \ + __stringify(DRV_PATCH) + char alx_drv_name[] = "alx"; +char alx_drv_version[] = DRV_MODULE_VER; static const char alx_drv_desc[] = "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"; @@ -57,7 +65,7 @@ MODULE_DEVICE_TABLE(pci, alx_pci_tbl); MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); MODULE_DESCRIPTION("Qualcomm Atheros Gigabit Ethernet Driver"); MODULE_LICENSE("Dual BSD/GPL"); - +MODULE_VERSION(DRV_MODULE_VER); static int alx_poll(struct napi_struct *napi, int budget); static irqreturn_t alx_msix_ring(int irq, void *data); @@ -927,8 +935,6 @@ static int alx_request_irq(struct alx_adapter *adpt) adpt->nr_vec = 1; adpt->nr_hwrxq = 1; alx_configure_rss(hw, false); - netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); - netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); if (!pci_enable_msi(pdev)) ALX_FLAG_SET(adpt, USING_MSI); @@ -960,12 +966,14 @@ static int alx_request_irq(struct alx_adapter *adpt) out: if (likely(!err)) { alx_config_vector_mapping(adpt); - netif_info(adpt, intr, adpt->netdev, + + netif_info(adpt, drv, adpt->netdev, "nr_rxq=%d, nr_txq=%d, nr_napi=%d, nr_vec=%d\n", adpt->nr_rxq, adpt->nr_txq, adpt->nr_napi, adpt->nr_vec); - netif_info(adpt, intr, adpt->netdev, - "Interrupt Mode: %s\n", + netif_info(adpt, drv, adpt->netdev, + "flags=%lX, Interrupt Mode: %s\n", + adpt->flags, ALX_FLAG(adpt, USING_MSIX) ? "MSIX" : ALX_FLAG(adpt, USING_MSI) ? "MSI" : "INTx"); } else @@ -1175,7 +1183,7 @@ static int alx_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } /* set MTU */ - if (old_mtu != new_mtu && netif_running(netdev)) { + if (old_mtu != new_mtu) { netif_info(adpt, drv, adpt->netdev, "changing MTU from %d to %d\n", netdev->mtu, new_mtu); @@ -1184,7 +1192,8 @@ static int alx_change_mtu(struct net_device *netdev, int new_mtu) adpt->rxbuf_size = new_mtu > ALX_DEF_RXBUF_SIZE ? ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE; netdev_update_features(netdev); - alx_reinit(adpt); + if (netif_running(netdev)) + alx_reinit(adpt); } return 0; @@ -1209,10 +1218,12 @@ static void alx_netif_stop(struct alx_adapter *adpt) int i; adpt->netdev->trans_start = jiffies; - netif_carrier_off(adpt->netdev); - netif_tx_disable(adpt->netdev); - for (i = 0; i < adpt->nr_napi; i++) - napi_disable(&adpt->qnapi[i]->napi); + if (netif_carrier_ok(adpt->netdev)) { + netif_carrier_off(adpt->netdev); + netif_tx_disable(adpt->netdev); + for (i = 0; i < adpt->nr_napi; i++) + napi_disable(&adpt->qnapi[i]->napi); + } } static void alx_netif_start(struct alx_adapter *adpt) @@ -1225,11 +1236,84 @@ static void alx_netif_start(struct alx_adapter *adpt) netif_carrier_on(adpt->netdev); } -static int __alx_open(struct alx_adapter *adpt) +static bool alx_enable_msix(struct alx_adapter *adpt) +{ + int nr_txq, nr_rxq, vec_req; + int i, err; + + nr_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); + nr_rxq = min_t(int, num_online_cpus(), ALX_MAX_RX_QUEUES); + nr_rxq = rounddown_pow_of_two(nr_rxq); + /* one more vector for PHY link change & timer & other events */ + vec_req = max_t(int, nr_txq, nr_rxq) + 1; + + if (vec_req <= 2) { + netif_info(adpt, intr, adpt->netdev, + "cpu core num is less, MSI-X isn't necessary\n"); + return false; + } + + adpt->msix_ent = kcalloc(vec_req, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!adpt->msix_ent) { + netif_warn(adpt, intr, adpt->netdev, + "can't alloc msix entries\n"); + return false; + } + for (i = 0; i < vec_req; i++) + adpt->msix_ent[i].entry = i; + + err = pci_enable_msix(adpt->pdev, adpt->msix_ent, vec_req); + if (err) { + kfree(adpt->msix_ent); + adpt->msix_ent = NULL; + netif_warn(adpt, intr, adpt->netdev, + "can't enable MSI-X interrupt\n"); + return false; + } + + adpt->nr_txq = nr_txq; + adpt->nr_rxq = nr_rxq; + adpt->nr_vec = vec_req; + adpt->nr_napi = vec_req - 1; + adpt->nr_hwrxq = ALX_CAP(&adpt->hw, MRQ) ? adpt->nr_rxq : 1; + + return true; +} + +static void alx_init_intr(struct alx_adapter *adpt) +{ + struct alx_hw *hw = &adpt->hw; + + if ((ALX_CAP(hw, MTQ) || ALX_CAP(hw, RSS)) && ALX_CAP(hw, MSIX)) { + if (alx_enable_msix(adpt)) + ALX_FLAG_SET(adpt, USING_MSIX); + } + if (!ALX_FLAG(adpt, USING_MSIX)) { + adpt->nr_txq = ALX_CAP(hw, MTQ) ? ALX_MAX_TX_QUEUES : 1; + adpt->nr_rxq = 1; + adpt->nr_napi = 1; + adpt->nr_vec = 1; + adpt->nr_hwrxq = 1; + + if (!pci_enable_msi(adpt->pdev)) + ALX_FLAG_SET(adpt, USING_MSI); + } +} + +static int __alx_open(struct alx_adapter *adpt, bool resume) { int err; - netif_carrier_off(adpt->netdev); + /* decide interrupt mode, some resources allocation depend on it */ + alx_init_intr(adpt); + + /* init rss indirection table */ + alx_init_def_rss_idt(adpt); + + if (!resume) + netif_carrier_off(adpt->netdev); /* allocate all memory resources */ err = alx_setup_all_ring_resources(adpt); @@ -1243,6 +1327,14 @@ static int __alx_open(struct alx_adapter *adpt) if (err) goto err_out; + /* netif_set_real_num_tx/rx_queues need rtnl_lock held */ + if (resume) + rtnl_lock(); + netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); + netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); + if (resume) + rtnl_unlock(); + ALX_FLAG_CLEAR(adpt, HALT); /* clear old interrupts */ @@ -1250,7 +1342,8 @@ static int __alx_open(struct alx_adapter *adpt) alx_irq_enable(adpt); - netif_tx_start_all_queues(adpt->netdev); + if (!resume) + netif_tx_start_all_queues(adpt->netdev); ALX_FLAG_SET(adpt, TASK_CHK_LINK); alx_schedule_work(adpt); @@ -1271,7 +1364,11 @@ static void alx_halt(struct alx_adapter *adpt) alx_cancel_work(adpt); alx_netif_stop(adpt); + hw->link_up = false; + hw->link_speed = SPEED_0; + alx_reset_mac(hw); + /* disable l0s/l1 */ alx_enable_aspm(hw, false, false); alx_irq_disable(adpt); @@ -1303,76 +1400,6 @@ static void __alx_stop(struct alx_adapter *adpt) alx_free_all_ring_resources(adpt); } -static bool alx_enable_msix(struct alx_adapter *adpt) -{ - int nr_txq, nr_rxq, vec_req; - int i, err; - - nr_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); - nr_rxq = min_t(int, num_online_cpus(), ALX_MAX_RX_QUEUES); - nr_rxq = rounddown_pow_of_two(nr_rxq); - /* one more vector for PHY link change & timer & other events */ - vec_req = max_t(int, nr_txq, nr_rxq) + 1; - - if (vec_req <= 2) { - netif_info(adpt, intr, adpt->netdev, - "cpu core num is less, MSI-X isn't necessary\n"); - return false; - } - - adpt->msix_ent = kcalloc(vec_req, - sizeof(struct msix_entry), - GFP_KERNEL); - if (!adpt->msix_ent) { - netif_warn(adpt, intr, adpt->netdev, - "can't alloc msix entries\n"); - return false; - } - for (i = 0; i < vec_req; i++) - adpt->msix_ent[i].entry = i; - - err = pci_enable_msix(adpt->pdev, adpt->msix_ent, vec_req); - if (err) { - kfree(adpt->msix_ent); - adpt->msix_ent = NULL; - netif_warn(adpt, intr, adpt->netdev, - "can't enable MSI-X interrupt\n"); - return false; - } - - adpt->nr_txq = nr_txq; - adpt->nr_rxq = nr_rxq; - adpt->nr_vec = vec_req; - adpt->nr_napi = vec_req - 1; - adpt->nr_hwrxq = ALX_CAP(&adpt->hw, MRQ) ? adpt->nr_rxq : 1; - - return true; -} - -static void alx_init_intr(struct alx_adapter *adpt) -{ - struct alx_hw *hw = &adpt->hw; - - if ((ALX_CAP(hw, MTQ) || ALX_CAP(hw, RSS)) && ALX_CAP(hw, MSIX)) { - if (alx_enable_msix(adpt)) - ALX_FLAG_SET(adpt, USING_MSIX); - } - if (!ALX_FLAG(adpt, USING_MSIX)) { - adpt->nr_txq = ALX_CAP(hw, MTQ) ? ALX_MAX_TX_QUEUES : 1; - adpt->nr_rxq = 1; - adpt->nr_napi = 1; - adpt->nr_vec = 1; - adpt->nr_hwrxq = 1; - - if (!pci_enable_msi(adpt->pdev)) - ALX_FLAG_SET(adpt, USING_MSI); - } - - netif_set_real_num_tx_queues(adpt->netdev, adpt->nr_txq); - netif_set_real_num_rx_queues(adpt->netdev, adpt->nr_rxq); - -} - static void alx_init_ring_ptrs(struct alx_adapter *adpt) { struct alx_hw *hw = &adpt->hw; @@ -1423,22 +1450,9 @@ static void alx_init_ring_ptrs(struct alx_adapter *adpt) static void alx_show_speed(struct alx_adapter *adpt, u16 speed) { - char *desc; - - desc = speed == SPEED_1000 + FULL_DUPLEX ? - "1 Gbps Duplex Full" : - speed == SPEED_100 + FULL_DUPLEX ? - "100 Mbps Duplex Full" : - speed == SPEED_100 + HALF_DUPLEX ? - "100 Mbps Duplex Half" : - speed == SPEED_10 + FULL_DUPLEX ? - "10 Mbps Duplex Full" : - speed == SPEED_10 + HALF_DUPLEX ? - "10 Mbps Duplex Half" : - "Unknown speed"; netif_info(adpt, link, adpt->netdev, "NIC Link Up: %s\n", - desc); + speed_desc(speed)); } static int alx_reinit_rings(struct alx_adapter *adpt) @@ -1561,13 +1575,7 @@ static int alx_open(struct net_device *netdev) if (ALX_FLAG(adpt, TESTING)) return -EBUSY; - /* decide interrupt mode, some resources allocation depend on it */ - alx_init_intr(adpt); - - /* init rss indirection table */ - alx_init_def_rss_idt(adpt); - - err = __alx_open(adpt); + err = __alx_open(adpt, false); return err; } @@ -1579,8 +1587,6 @@ static int alx_stop(struct net_device *netdev) WARN_ON(ALX_FLAG(adpt, RESETING)); - netif_info(adpt, ifdown, adpt->netdev, "alx_stop\n"); - __alx_stop(adpt); return 0; @@ -1608,14 +1614,18 @@ static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en) if (!err) err = alx_clear_phy_intr(hw); if (!err) - err = alx_config_wol(hw); - if (!err) err = alx_pre_suspend(hw, speed); + if (!err) + err = alx_config_wol(hw); if (err) goto out; *wol_en = false; if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) { + netif_info(adpt, wol, netdev, + "wol: ctrl=%X, speed=%X\n", + hw->sleep_ctrl, speed); + device_set_wakeup_enable(&pdev->dev, true); *wol_en = true; } @@ -1647,7 +1657,6 @@ static void alx_shutdown(struct pci_dev *pdev) } } - #ifdef CONFIG_PM_SLEEP static int alx_suspend(struct device *dev) { @@ -1692,6 +1701,7 @@ static int alx_resume(struct device *dev) hw->link_up = false; hw->link_speed = SPEED_0; + hw->imask = ALX_ISR_MISC; alx_reset_pcie(hw); alx_reset_phy(hw, !hw->hib_patch); @@ -1711,7 +1721,7 @@ static int alx_resume(struct device *dev) } if (netif_running(netdev)) { - err = __alx_open(adpt); + err = __alx_open(adpt, true); if (err) return err; } @@ -2312,8 +2322,8 @@ static void alx_dump_state(struct alx_adapter *adpt) for (i = 0; i < adpt->nr_txq; i++) { txq = adpt->qnapi[i]->txq; - begin = txq->pidx >= 16 ? (txq->pidx - 16) : - (txq->count + txq->pidx - 16); + begin = txq->pidx >= 8 ? (txq->pidx - 8) : + (txq->count + txq->pidx - 8); end = txq->pidx + 4; if (end >= txq->count) end -= txq->count; @@ -2335,8 +2345,8 @@ static void alx_dump_state(struct alx_adapter *adpt) netif_err(adpt, tx_err, adpt->netdev, "---------------dump registers-----------------\n"); - end = 0x2000; - for (begin = 0; begin < end; begin += 16) { + end = 0x1800; + for (begin = 0x1400; begin < end; begin += 16) { u32 v1, v2, v3, v4; ALX_MEM_R32(hw, begin, &v1); @@ -2570,6 +2580,8 @@ alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* reset PHY to a known stable status */ if (!phy_cfged) alx_reset_phy(hw, !hw->hib_patch); + else + dev_info(&pdev->dev, "PHY has been configured.\n"); /* reset mac/dma controller */ err = alx_reset_mac(hw); @@ -2698,6 +2710,8 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, struct net_device *netdev = adpt->netdev; pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; + dev_info(&pdev->dev, "pci error detectd\n"); + rtnl_lock(); if (netif_running(netdev)) { @@ -2721,6 +2735,8 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) struct alx_hw *hw = &adpt->hw; pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + dev_info(&pdev->dev, "pci error slot reset\n"); + rtnl_lock(); if (pci_enable_device(pdev)) { @@ -2749,6 +2765,8 @@ static void alx_pci_error_resume(struct pci_dev *pdev) struct alx_adapter *adpt = pci_get_drvdata(pdev); struct net_device *netdev = adpt->netdev; + dev_info(&pdev->dev, "pci error resume\n"); + rtnl_lock(); if (netif_running(netdev)) { |