diff options
Diffstat (limited to 'drivers/net/ethernet/wangxun')
-rw-r--r-- | drivers/net/ethernet/wangxun/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/libwx/wx_hw.c | 68 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/libwx/wx_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/libwx/wx_lib.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/libwx/wx_type.h | 34 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c | 35 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 64 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c | 88 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c | 39 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 56 | ||||
-rw-r--r-- | drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 188 |
13 files changed, 434 insertions, 164 deletions
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 39596cd13539..23cd610bd376 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -41,6 +41,7 @@ config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI depends on COMMON_CLK + select MARVELL_10G_PHY select REGMAP select I2C select I2C_DESIGNWARE_PLATFORM diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index 6321178fc814..85dc16faca54 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -432,71 +432,6 @@ out: EXPORT_SYMBOL(wx_read_ee_hostif_buffer); /** - * wx_calculate_checksum - Calculate checksum for buffer - * @buffer: pointer to EEPROM - * @length: size of EEPROM to calculate a checksum for - * Calculates the checksum for some buffer on a specified length. The - * checksum calculated is returned. - **/ -static u8 wx_calculate_checksum(u8 *buffer, u32 length) -{ - u8 sum = 0; - u32 i; - - if (!buffer) - return 0; - - for (i = 0; i < length; i++) - sum += buffer[i]; - - return (u8)(0 - sum); -} - -/** - * wx_reset_hostif - send reset cmd to fw - * @wx: pointer to hardware structure - * - * Sends reset cmd to firmware through the manageability - * block. - **/ -int wx_reset_hostif(struct wx *wx) -{ - struct wx_hic_reset reset_cmd; - int ret_val = 0; - int i; - - reset_cmd.hdr.cmd = FW_RESET_CMD; - reset_cmd.hdr.buf_len = FW_RESET_LEN; - reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; - reset_cmd.lan_id = wx->bus.func; - reset_cmd.reset_type = (u16)wx->reset_type; - reset_cmd.hdr.checksum = 0; - reset_cmd.hdr.checksum = wx_calculate_checksum((u8 *)&reset_cmd, - (FW_CEM_HDR_LEN + - reset_cmd.hdr.buf_len)); - - for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { - ret_val = wx_host_interface_command(wx, (u32 *)&reset_cmd, - sizeof(reset_cmd), - WX_HI_COMMAND_TIMEOUT, - true); - if (ret_val != 0) - continue; - - if (reset_cmd.hdr.cmd_or_resp.ret_status == - FW_CEM_RESP_STATUS_SUCCESS) - ret_val = 0; - else - ret_val = -EFAULT; - - break; - } - - return ret_val; -} -EXPORT_SYMBOL(wx_reset_hostif); - -/** * wx_init_eeprom_params - Initialize EEPROM params * @wx: pointer to hardware structure * @@ -1501,7 +1436,7 @@ static void wx_restore_vlan(struct wx *wx) * * Configure the Rx unit of the MAC after a reset. **/ -static void wx_configure_rx(struct wx *wx) +void wx_configure_rx(struct wx *wx) { u32 psrtype, i; int ret; @@ -1544,6 +1479,7 @@ static void wx_configure_rx(struct wx *wx) wx_enable_rx(wx); wx_enable_sec_rx_path(wx); } +EXPORT_SYMBOL(wx_configure_rx); static void wx_configure_isb(struct wx *wx) { diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h index 1f93ca32c921..0b3447bc6f2f 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h @@ -14,7 +14,6 @@ int wx_host_interface_command(struct wx *wx, u32 *buffer, int wx_read_ee_hostif(struct wx *wx, u16 offset, u16 *data); int wx_read_ee_hostif_buffer(struct wx *wx, u16 offset, u16 words, u16 *data); -int wx_reset_hostif(struct wx *wx); void wx_init_eeprom_params(struct wx *wx); void wx_get_mac_addr(struct wx *wx, u8 *mac_addr); void wx_init_rx_addrs(struct wx *wx); @@ -25,6 +24,7 @@ void wx_disable_rx(struct wx *wx); void wx_set_rx_mode(struct net_device *netdev); int wx_change_mtu(struct net_device *netdev, int new_mtu); void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring); +void wx_configure_rx(struct wx *wx); void wx_configure(struct wx *wx); void wx_start_hw(struct wx *wx); int wx_disable_pcie_master(struct wx *wx); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 2c3f08be8c37..e04d4a5eed7b 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -3,7 +3,7 @@ #include <linux/etherdevice.h> #include <net/ip6_checksum.h> -#include <net/page_pool.h> +#include <net/page_pool/helpers.h> #include <net/inet_ecn.h> #include <linux/iopoll.h> #include <linux/sctp.h> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 29dfb561887d..c5cbd177ef62 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -160,6 +160,10 @@ #define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16)) #define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16)) +#define WX_PSR_WKUP_CTL 0x15B80 +/* Wake Up Filter Control Bit */ +#define WX_PSR_WKUP_CTL_MAG BIT(1) /* Magic Packet Wakeup Enable */ + /* vlan tbl */ #define WX_PSR_VLAN_TBL(_i) (0x16000 + ((_i) * 4)) @@ -201,6 +205,8 @@ #define WX_TSC_CTL 0x1D000 #define WX_TSC_CTL_TX_DIS BIT(1) #define WX_TSC_CTL_TSEC_DIS BIT(0) +#define WX_TSC_ST 0x1D004 +#define WX_TSC_ST_SECTX_RDY BIT(0) #define WX_TSC_BUF_AE 0x1D00C #define WX_TSC_BUF_AE_THR GENMASK(9, 0) @@ -227,6 +233,24 @@ #define WX_MAC_WDG_TIMEOUT 0x1100C #define WX_MAC_RX_FLOW_CTRL 0x11090 #define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */ +/* MDIO Registers */ +#define WX_MSCA 0x11200 +#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v) +#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v) +#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v) +#define WX_MSCC 0x11204 +#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v) + +enum WX_MSCA_CMD_value { + WX_MSCA_CMD_RSV = 0, + WX_MSCA_CMD_WRITE, + WX_MSCA_CMD_POST_READ, + WX_MSCA_CMD_READ, +}; + +#define WX_MSCC_SADDR BIT(18) +#define WX_MSCC_BUSY BIT(22) +#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v) #define WX_MMC_CONTROL 0x11800 #define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */ @@ -576,6 +600,13 @@ enum wx_mac_type { wx_mac_em }; +enum sp_media_type { + sp_media_unknown = 0, + sp_media_fiber, + sp_media_copper, + sp_media_backplane +}; + enum em_mac_type { em_mac_type_unknown = 0, em_mac_type_mdi, @@ -823,6 +854,7 @@ struct wx { struct wx_bus_info bus; struct wx_mac_info mac; enum em_mac_type mac_type; + enum sp_media_type media_type; struct wx_eeprom_info eeprom; struct wx_addr_filter_info addr_ctrl; struct wx_mac_addr *mac_table; @@ -846,7 +878,7 @@ struct wx { int duplex; struct phy_device *phydev; - bool wol_enabled; + bool wol_hw_supported; bool ncsi_enabled; bool gpio_ctrl; raw_spinlock_t gpio_lock; diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c index 5b25834baf38..ec0e869e9aac 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c @@ -6,14 +6,49 @@ #include <linux/netdevice.h> #include "../libwx/wx_ethtool.h" +#include "../libwx/wx_type.h" #include "ngbe_ethtool.h" +static void ngbe_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct wx *wx = netdev_priv(netdev); + + if (!wx->wol_hw_supported) + return; + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + if (wx->wol & WX_PSR_WKUP_CTL_MAG) + wol->wolopts |= WAKE_MAGIC; +} + +static int ngbe_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct wx *wx = netdev_priv(netdev); + struct pci_dev *pdev = wx->pdev; + + if (!wx->wol_hw_supported) + return -EOPNOTSUPP; + + wx->wol = 0; + if (wol->wolopts & WAKE_MAGIC) + wx->wol = WX_PSR_WKUP_CTL_MAG; + netdev->wol_enabled = !!(wx->wol); + wr32(wx, WX_PSR_WKUP_CTL, wx->wol); + device_set_wakeup_enable(&pdev->dev, netdev->wol_enabled); + + return 0; +} + static const struct ethtool_ops ngbe_ethtool_ops = { .get_drvinfo = wx_get_drvinfo, .get_link = ethtool_op_get_link, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .nway_reset = phy_ethtool_nway_reset, + .get_wol = ngbe_get_wol, + .set_wol = ngbe_set_wol, }; void ngbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index c99a5d3de72e..2b431db6085a 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -62,7 +62,7 @@ static void ngbe_init_type_code(struct wx *wx) em_mac_type_rgmii : em_mac_type_mdi; - wx->wol_enabled = (wol_mask == NGBE_WOL_SUP) ? 1 : 0; + wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0; wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK || type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0; @@ -440,14 +440,26 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct wx *wx = pci_get_drvdata(pdev); struct net_device *netdev; + u32 wufc = wx->wol; netdev = wx->netdev; + rtnl_lock(); netif_device_detach(netdev); - rtnl_lock(); if (netif_running(netdev)) - ngbe_down(wx); + ngbe_close(netdev); + wx_clear_interrupt_scheme(wx); rtnl_unlock(); + + if (wufc) { + wx_set_rx_mode(netdev); + wx_configure_rx(wx); + wr32(wx, NGBE_PSR_WKUP_CTL, wufc); + } else { + wr32(wx, NGBE_PSR_WKUP_CTL, 0); + } + pci_wake_from_d3(pdev, !!wufc); + *enable_wake = !!wufc; wx_control_hw(wx, false); pci_disable_device(pdev); @@ -621,12 +633,11 @@ static int ngbe_probe(struct pci_dev *pdev, } wx->wol = 0; - if (wx->wol_enabled) + if (wx->wol_hw_supported) wx->wol = NGBE_PSR_WKUP_CTL_MAG; - wx->wol_enabled = !!(wx->wol); + netdev->wol_enabled = !!(wx->wol); wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol); - device_set_wakeup_enable(&pdev->dev, wx->wol); /* Save off EEPROM version number and Option Rom version which @@ -712,11 +723,52 @@ static void ngbe_remove(struct pci_dev *pdev) pci_disable_device(pdev); } +static int ngbe_suspend(struct pci_dev *pdev, pm_message_t state) +{ + bool wake; + + ngbe_dev_shutdown(pdev, &wake); + device_set_wakeup_enable(&pdev->dev, wake); + + return 0; +} + +static int ngbe_resume(struct pci_dev *pdev) +{ + struct net_device *netdev; + struct wx *wx; + u32 err; + + wx = pci_get_drvdata(pdev); + netdev = wx->netdev; + + err = pci_enable_device_mem(pdev); + if (err) { + wx_err(wx, "Cannot enable PCI device from suspend\n"); + return err; + } + pci_set_master(pdev); + device_wakeup_disable(&pdev->dev); + + ngbe_reset_hw(wx); + rtnl_lock(); + err = wx_init_interrupt_scheme(wx); + if (!err && netif_running(netdev)) + err = ngbe_open(netdev); + if (!err) + netif_device_attach(netdev); + rtnl_unlock(); + + return 0; +} + static struct pci_driver ngbe_driver = { .name = ngbe_driver_name, .id_table = ngbe_pci_tbl, .probe = ngbe_probe, .remove = ngbe_remove, + .suspend = ngbe_suspend, + .resume = ngbe_resume, .shutdown = ngbe_shutdown, }; diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c index c9ddbbc3fa4f..591f5b7b6da6 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c @@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF); /* setup and write the address cycle command */ - command = NGBE_MSCA_RA(regnum) | - NGBE_MSCA_PA(phy_addr) | - NGBE_MSCA_DA(device_type); - wr32(wx, NGBE_MSCA, command); - command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) | - NGBE_MSCC_BUSY | - NGBE_MDIO_CLK(6); - wr32(wx, NGBE_MSCC, command); + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(device_type); + wr32(wx, WX_MSCA, command); + command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | + WX_MSCC_BUSY | + WX_MDIO_CLK(6); + wr32(wx, WX_MSCC, command); /* wait to complete */ - ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, - 100000, false, wx, NGBE_MSCC); + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); if (ret) { wx_err(wx, "Mdio read c22 command did not complete.\n"); return ret; } - return (u16)rd32(wx, NGBE_MSCC); + return (u16)rd32(wx, WX_MSCC); } static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value) @@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF); /* setup and write the address cycle command */ - command = NGBE_MSCA_RA(regnum) | - NGBE_MSCA_PA(phy_addr) | - NGBE_MSCA_DA(device_type); - wr32(wx, NGBE_MSCA, command); + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(device_type); + wr32(wx, WX_MSCA, command); command = value | - NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) | - NGBE_MSCC_BUSY | - NGBE_MDIO_CLK(6); - wr32(wx, NGBE_MSCC, command); + WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | + WX_MSCC_BUSY | + WX_MDIO_CLK(6); + wr32(wx, WX_MSCC, command); /* wait to complete */ - ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, - 100000, false, wx, NGBE_MSCC); + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); if (ret) wx_err(wx, "Mdio write c22 command did not complete.\n"); @@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0); /* setup and write the address cycle command */ - command = NGBE_MSCA_RA(regnum) | - NGBE_MSCA_PA(phy_addr) | - NGBE_MSCA_DA(devnum); - wr32(wx, NGBE_MSCA, command); - command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) | - NGBE_MSCC_BUSY | - NGBE_MDIO_CLK(6); - wr32(wx, NGBE_MSCC, command); + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(devnum); + wr32(wx, WX_MSCA, command); + command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | + WX_MSCC_BUSY | + WX_MDIO_CLK(6); + wr32(wx, WX_MSCC, command); /* wait to complete */ - ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, - 100000, false, wx, NGBE_MSCC); + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); if (ret) { wx_err(wx, "Mdio read c45 command did not complete.\n"); return ret; } - return (u16)rd32(wx, NGBE_MSCC); + return (u16)rd32(wx, WX_MSCC); } static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr, @@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr, wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0); /* setup and write the address cycle command */ - command = NGBE_MSCA_RA(regnum) | - NGBE_MSCA_PA(phy_addr) | - NGBE_MSCA_DA(devnum); - wr32(wx, NGBE_MSCA, command); + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(devnum); + wr32(wx, WX_MSCA, command); command = value | - NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) | - NGBE_MSCC_BUSY | - NGBE_MDIO_CLK(6); - wr32(wx, NGBE_MSCC, command); + WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | + WX_MSCC_BUSY | + WX_MDIO_CLK(6); + wr32(wx, WX_MSCC, command); /* wait to complete */ - ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000, - 100000, false, wx, NGBE_MSCC); + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); if (ret) wx_err(wx, "Mdio write c45 command did not complete.\n"); @@ -236,6 +236,7 @@ static void ngbe_phy_fixup(struct wx *wx) phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phydev->mac_managed_pm = true; if (wx->mac_type != em_mac_type_mdi) return; /* disable EEE, internal phy does not support eee */ @@ -265,8 +266,7 @@ int ngbe_mdio_init(struct wx *wx) mii_bus->write_c45 = ngbe_phy_write_reg_mdi_c45; } - snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", - (pdev->bus->number << 8) | pdev->devfn); + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev)); ret = devm_mdiobus_register(&pdev->dev, mii_bus); if (ret) return ret; diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h index b70eca397b67..72c8cd2d5575 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h @@ -59,25 +59,6 @@ #define NGBE_EEPROM_VERSION_L 0x1D #define NGBE_EEPROM_VERSION_H 0x1E -/* mdio access */ -#define NGBE_MSCA 0x11200 -#define NGBE_MSCA_RA(v) FIELD_PREP(U16_MAX, v) -#define NGBE_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v) -#define NGBE_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v) -#define NGBE_MSCC 0x11204 -#define NGBE_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v) - -enum NGBE_MSCA_CMD_value { - NGBE_MSCA_CMD_RSV = 0, - NGBE_MSCA_CMD_WRITE, - NGBE_MSCA_CMD_POST_READ, - NGBE_MSCA_CMD_READ, -}; - -#define NGBE_MSCC_SADDR BIT(18) -#define NGBE_MSCC_BUSY BIT(22) -#define NGBE_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v) - /* Media-dependent registers. */ #define NGBE_MDIO_CLAUSE_SELECT 0x11220 diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c index 0772eb14eabf..372745250270 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c @@ -14,6 +14,34 @@ #include "txgbe_hw.h" /** + * txgbe_disable_sec_tx_path - Stops the transmit data path + * @wx: pointer to hardware structure + * + * Stops the transmit data path and waits for the HW to internally empty + * the tx security block + **/ +int txgbe_disable_sec_tx_path(struct wx *wx) +{ + int val; + + wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, WX_TSC_CTL_TX_DIS); + return read_poll_timeout(rd32, val, val & WX_TSC_ST_SECTX_RDY, + 1000, 20000, false, wx, WX_TSC_ST); +} + +/** + * txgbe_enable_sec_tx_path - Enables the transmit data path + * @wx: pointer to hardware structure + * + * Enables the transmit data path. + **/ +void txgbe_enable_sec_tx_path(struct wx *wx) +{ + wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, 0); + WX_WRITE_FLUSH(wx); +} + +/** * txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds * @wx: pointer to hardware structure * @@ -263,11 +291,14 @@ int txgbe_reset_hw(struct wx *wx) if (status != 0) return status; - if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) || - ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) - wx_reset_hostif(wx); + if (wx->media_type != sp_media_copper) { + u32 val; - usleep_range(10, 100); + val = WX_MIS_RST_LAN_RST(wx->bus.func); + wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST)); + WX_WRITE_FLUSH(wx); + usleep_range(10, 100); + } status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func)); if (status != 0) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h index e82f65dff8a6..abc729eb187a 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h @@ -4,6 +4,8 @@ #ifndef _TXGBE_HW_H_ #define _TXGBE_HW_H_ +int txgbe_disable_sec_tx_path(struct wx *wx); +void txgbe_enable_sec_tx_path(struct wx *wx); int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size); int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val); int txgbe_reset_hw(struct wx *wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 46eba6d6188b..5c3aed516ac2 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -301,6 +301,49 @@ static void txgbe_down(struct wx *wx) } /** + * txgbe_init_type_code - Initialize the shared code + * @wx: pointer to hardware structure + **/ +static void txgbe_init_type_code(struct wx *wx) +{ + u8 device_type = wx->subsystem_device_id & 0xF0; + + switch (wx->device_id) { + case TXGBE_DEV_ID_SP1000: + case TXGBE_DEV_ID_WX1820: + wx->mac.type = wx_mac_sp; + break; + default: + wx->mac.type = wx_mac_unknown; + break; + } + + switch (device_type) { + case TXGBE_ID_SFP: + wx->media_type = sp_media_fiber; + break; + case TXGBE_ID_XAUI: + case TXGBE_ID_SGMII: + wx->media_type = sp_media_copper; + break; + case TXGBE_ID_KR_KX_KX4: + case TXGBE_ID_MAC_XAUI: + case TXGBE_ID_MAC_SGMII: + wx->media_type = sp_media_backplane; + break; + case TXGBE_ID_SFI_XAUI: + if (wx->bus.func == 0) + wx->media_type = sp_media_fiber; + else + wx->media_type = sp_media_copper; + break; + default: + wx->media_type = sp_media_unknown; + break; + } +} + +/** * txgbe_sw_init - Initialize general software structures (struct wx) * @wx: board private structure to initialize **/ @@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx) return err; } - switch (wx->device_id) { - case TXGBE_DEV_ID_SP1000: - case TXGBE_DEV_ID_WX1820: - wx->mac.type = wx_mac_sp; - break; - default: - wx->mac.type = wx_mac_unknown; - break; - } + txgbe_init_type_code(wx); /* Set common capability flags and settings */ wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS; @@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev, "0x%08x", etrack_id); } + if (etrack_id < 0x20010) + dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n"); + txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); if (!txgbe) { err = -ENOMEM; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 8779645a54be..4159c84035fd 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -18,6 +18,7 @@ #include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_phy.h" +#include "txgbe_hw.h" static int txgbe_swnodes_register(struct txgbe *txgbe) { @@ -26,7 +27,7 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) struct software_node *swnodes; u32 id; - id = (pdev->bus->number << 8) | pdev->devfn; + id = pci_dev_id(pdev); snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id); snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id); @@ -140,7 +141,7 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe) mii_bus->phy_mask = ~0; mii_bus->priv = wx; snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x", - (pdev->bus->number << 8) | pdev->devfn); + pci_dev_id(pdev)); ret = devm_mdiobus_register(&pdev->dev, mii_bus); if (ret) @@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi { struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev)); - return &txgbe->xpcs->pcs; + if (interface == PHY_INTERFACE_MODE_10GBASER) + return &txgbe->xpcs->pcs; + + return NULL; } static void txgbe_mac_config(struct phylink_config *config, unsigned int mode, @@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config, wr32(wx, WX_MAC_WDG_TIMEOUT, wdg); } +static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + + wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0); + wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0); + + return txgbe_disable_sec_tx_path(wx); +} + +static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + + txgbe_enable_sec_tx_path(wx); + wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE); + + return 0; +} + static const struct phylink_mac_ops txgbe_mac_ops = { .mac_select_pcs = txgbe_phylink_mac_select, + .mac_prepare = txgbe_mac_prepare, + .mac_finish = txgbe_mac_finish, .mac_config = txgbe_mac_config, .mac_link_down = txgbe_mac_link_down, .mac_link_up = txgbe_mac_link_up, @@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = { static int txgbe_phylink_init(struct txgbe *txgbe) { + struct fwnode_handle *fwnode = NULL; struct phylink_config *config; - struct fwnode_handle *fwnode; struct wx *wx = txgbe->wx; phy_interface_t phy_mode; struct phylink *phylink; @@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe) config->dev = &wx->netdev->dev; config->type = PHYLINK_NETDEV; - config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE; - phy_mode = PHY_INTERFACE_MODE_10GBASER; - __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces); - fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]); + config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD | + MAC_SYM_PAUSE | MAC_ASYM_PAUSE; + + if (wx->media_type == sp_media_copper) { + phy_mode = PHY_INTERFACE_MODE_XAUI; + __set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces); + } else { + phy_mode = PHY_INTERFACE_MODE_10GBASER; + fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]); + __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces); + } + phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops); if (IS_ERR(phylink)) return PTR_ERR(phylink); + if (wx->phydev) { + int ret; + + ret = phylink_connect_phy(phylink, wx->phydev); + if (ret) { + phylink_destroy(phylink); + return ret; + } + } + txgbe->phylink = phylink; return 0; @@ -431,7 +479,8 @@ static void txgbe_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); - if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) { + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | + TXGBE_PX_MISC_ETH_AN)) { u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); @@ -459,7 +508,7 @@ static int txgbe_gpio_init(struct txgbe *txgbe) return -ENOMEM; gc->label = devm_kasprintf(dev, GFP_KERNEL, "txgbe_gpio-%x", - (wx->pdev->bus->number << 8) | wx->pdev->devfn); + pci_dev_id(wx->pdev)); if (!gc->label) return -ENOMEM; @@ -503,7 +552,7 @@ static int txgbe_clock_register(struct txgbe *txgbe) struct clk *clk; snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d", - (pdev->bus->number << 8) | pdev->devfn); + pci_dev_id(pdev)); clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000); if (IS_ERR(clk)) @@ -566,7 +615,7 @@ static int txgbe_i2c_register(struct txgbe *txgbe) info.parent = &pdev->dev; info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]); info.name = "i2c_designware"; - info.id = (pdev->bus->number << 8) | pdev->devfn; + info.id = pci_dev_id(pdev); info.res = &DEFINE_RES_IRQ(pdev->irq); info.num_res = 1; @@ -588,7 +637,7 @@ static int txgbe_sfp_register(struct txgbe *txgbe) info.parent = &pdev->dev; info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]); info.name = "sfp"; - info.id = (pdev->bus->number << 8) | pdev->devfn; + info.id = pci_dev_id(pdev); sfp_dev = platform_device_register_full(&info); if (IS_ERR(sfp_dev)) return PTR_ERR(sfp_dev); @@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe) return 0; } +static int txgbe_phy_read(struct mii_bus *bus, int phy_addr, + int devnum, int regnum) +{ + struct wx *wx = bus->priv; + u32 val, command; + int ret; + + /* setup and write the address cycle command */ + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(devnum); + wr32(wx, WX_MSCA, command); + + command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY; + wr32(wx, WX_MSCC, command); + + /* wait to complete */ + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); + if (ret) { + wx_err(wx, "Mdio read c45 command did not complete.\n"); + return ret; + } + + return (u16)rd32(wx, WX_MSCC); +} + +static int txgbe_phy_write(struct mii_bus *bus, int phy_addr, + int devnum, int regnum, u16 value) +{ + struct wx *wx = bus->priv; + int ret, command; + u16 val; + + /* setup and write the address cycle command */ + command = WX_MSCA_RA(regnum) | + WX_MSCA_PA(phy_addr) | + WX_MSCA_DA(devnum); + wr32(wx, WX_MSCA, command); + + command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY; + wr32(wx, WX_MSCC, command); + + /* wait to complete */ + ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000, + 100000, false, wx, WX_MSCC); + if (ret) + wx_err(wx, "Mdio write c45 command did not complete.\n"); + + return ret; +} + +static int txgbe_ext_phy_init(struct txgbe *txgbe) +{ + struct phy_device *phydev; + struct mii_bus *mii_bus; + struct pci_dev *pdev; + struct wx *wx; + int ret = 0; + + wx = txgbe->wx; + pdev = wx->pdev; + + mii_bus = devm_mdiobus_alloc(&pdev->dev); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "txgbe_mii_bus"; + mii_bus->read_c45 = &txgbe_phy_read; + mii_bus->write_c45 = &txgbe_phy_write; + mii_bus->parent = &pdev->dev; + mii_bus->phy_mask = GENMASK(31, 1); + mii_bus->priv = wx; + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x", + (pdev->bus->number << 8) | pdev->devfn); + + ret = devm_mdiobus_register(&pdev->dev, mii_bus); + if (ret) { + wx_err(wx, "failed to register MDIO bus: %d\n", ret); + return ret; + } + + phydev = phy_find_first(mii_bus); + if (!phydev) { + wx_err(wx, "no PHY found\n"); + return -ENODEV; + } + + phy_attached_info(phydev); + + wx->link = 0; + wx->speed = 0; + wx->duplex = 0; + wx->phydev = phydev; + + ret = txgbe_phylink_init(txgbe); + if (ret) { + wx_err(wx, "failed to init phylink: %d\n", ret); + return ret; + } + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; + if (txgbe->wx->media_type == sp_media_copper) + return txgbe_ext_phy_init(txgbe); + ret = txgbe_swnodes_register(txgbe); if (ret) { wx_err(txgbe->wx, "failed to register software nodes\n"); @@ -663,6 +819,12 @@ err_unregister_swnode: void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->wx->media_type == sp_media_copper) { + phylink_disconnect_phy(txgbe->phylink); + phylink_destroy(txgbe->phylink); + return; + } + platform_device_unregister(txgbe->sfp_dev); platform_device_unregister(txgbe->i2c_dev); clkdev_drop(txgbe->clock); |