1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/ethtool.h> 5 #include <linux/iopoll.h> 6 #include <linux/pci.h> 7 #include <linux/phy.h> 8 9 #include "../libwx/wx_type.h" 10 #include "../libwx/wx_ptp.h" 11 #include "../libwx/wx_hw.h" 12 #include "../libwx/wx_sriov.h" 13 #include "ngbe_type.h" 14 #include "ngbe_mdio.h" 15 16 static int ngbe_phy_read_reg_internal(struct mii_bus *bus, int phy_addr, int regnum) 17 { 18 struct wx *wx = bus->priv; 19 20 if (phy_addr != 0) 21 return 0xffff; 22 return (u16)rd32(wx, NGBE_PHY_CONFIG(regnum)); 23 } 24 25 static int ngbe_phy_write_reg_internal(struct mii_bus *bus, int phy_addr, int regnum, u16 value) 26 { 27 struct wx *wx = bus->priv; 28 29 if (phy_addr == 0) 30 wr32(wx, NGBE_PHY_CONFIG(regnum), value); 31 return 0; 32 } 33 34 static int ngbe_phy_read_reg_c22(struct mii_bus *bus, int phy_addr, int regnum) 35 { 36 struct wx *wx = bus->priv; 37 u16 phy_data; 38 39 if (wx->mac_type == em_mac_type_mdi) 40 phy_data = ngbe_phy_read_reg_internal(bus, phy_addr, regnum); 41 else 42 phy_data = wx_phy_read_reg_mdi_c22(bus, phy_addr, regnum); 43 44 return phy_data; 45 } 46 47 static int ngbe_phy_write_reg_c22(struct mii_bus *bus, int phy_addr, 48 int regnum, u16 value) 49 { 50 struct wx *wx = bus->priv; 51 int ret; 52 53 if (wx->mac_type == em_mac_type_mdi) 54 ret = ngbe_phy_write_reg_internal(bus, phy_addr, regnum, value); 55 else 56 ret = wx_phy_write_reg_mdi_c22(bus, phy_addr, regnum, value); 57 58 return ret; 59 } 60 61 static void ngbe_mac_config(struct phylink_config *config, unsigned int mode, 62 const struct phylink_link_state *state) 63 { 64 } 65 66 static void ngbe_mac_link_down(struct phylink_config *config, 67 unsigned int mode, phy_interface_t interface) 68 { 69 struct wx *wx = phylink_to_wx(config); 70 71 wx->speed = SPEED_UNKNOWN; 72 if (test_bit(WX_STATE_PTP_RUNNING, wx->state)) 73 wx_ptp_reset_cyclecounter(wx); 74 /* ping all the active vfs to let them know we are going down */ 75 wx_ping_all_vfs_with_link_status(wx, false); 76 } 77 78 static void ngbe_mac_link_up(struct phylink_config *config, 79 struct phy_device *phy, 80 unsigned int mode, phy_interface_t interface, 81 int speed, int duplex, 82 bool tx_pause, bool rx_pause) 83 { 84 struct wx *wx = phylink_to_wx(config); 85 u32 lan_speed, reg; 86 87 wx_fc_enable(wx, tx_pause, rx_pause); 88 89 switch (speed) { 90 case SPEED_10: 91 lan_speed = 0; 92 break; 93 case SPEED_100: 94 lan_speed = 1; 95 break; 96 case SPEED_1000: 97 default: 98 lan_speed = 2; 99 break; 100 } 101 102 wr32m(wx, NGBE_CFG_LAN_SPEED, 0x3, lan_speed); 103 104 reg = rd32(wx, WX_MAC_TX_CFG); 105 reg &= ~WX_MAC_TX_CFG_SPEED_MASK; 106 reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE; 107 wr32(wx, WX_MAC_TX_CFG, reg); 108 109 /* Re configure MAC Rx */ 110 reg = rd32(wx, WX_MAC_RX_CFG); 111 wr32(wx, WX_MAC_RX_CFG, reg); 112 wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); 113 reg = rd32(wx, WX_MAC_WDG_TIMEOUT); 114 wr32(wx, WX_MAC_WDG_TIMEOUT, reg); 115 116 wx->speed = speed; 117 wx->last_rx_ptp_check = jiffies; 118 if (test_bit(WX_STATE_PTP_RUNNING, wx->state)) 119 wx_ptp_reset_cyclecounter(wx); 120 /* ping all the active vfs to let them know we are going up */ 121 wx_ping_all_vfs_with_link_status(wx, true); 122 } 123 124 static const struct phylink_mac_ops ngbe_mac_ops = { 125 .mac_config = ngbe_mac_config, 126 .mac_link_down = ngbe_mac_link_down, 127 .mac_link_up = ngbe_mac_link_up, 128 }; 129 130 static int ngbe_phylink_init(struct wx *wx) 131 { 132 struct phylink_config *config; 133 phy_interface_t phy_mode; 134 struct phylink *phylink; 135 136 config = &wx->phylink_config; 137 config->dev = &wx->netdev->dev; 138 config->type = PHYLINK_NETDEV; 139 config->mac_capabilities = MAC_1000FD | MAC_100FD | MAC_10FD | 140 MAC_SYM_PAUSE | MAC_ASYM_PAUSE; 141 config->mac_managed_pm = true; 142 143 /* The MAC only has add the Tx delay and it can not be modified. 144 * So just disable TX delay in PHY, and it is does not matter to 145 * internal phy. 146 */ 147 phy_mode = PHY_INTERFACE_MODE_RGMII_RXID; 148 __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, config->supported_interfaces); 149 150 phylink = phylink_create(config, NULL, phy_mode, &ngbe_mac_ops); 151 if (IS_ERR(phylink)) 152 return PTR_ERR(phylink); 153 154 wx->phylink = phylink; 155 156 return 0; 157 } 158 159 int ngbe_mdio_init(struct wx *wx) 160 { 161 struct pci_dev *pdev = wx->pdev; 162 struct mii_bus *mii_bus; 163 int ret; 164 165 mii_bus = devm_mdiobus_alloc(&pdev->dev); 166 if (!mii_bus) 167 return -ENOMEM; 168 169 mii_bus->name = "ngbe_mii_bus"; 170 mii_bus->read = ngbe_phy_read_reg_c22; 171 mii_bus->write = ngbe_phy_write_reg_c22; 172 mii_bus->phy_mask = GENMASK(31, 4); 173 mii_bus->parent = &pdev->dev; 174 mii_bus->priv = wx; 175 176 if (wx->mac_type == em_mac_type_rgmii) { 177 mii_bus->read_c45 = wx_phy_read_reg_mdi_c45; 178 mii_bus->write_c45 = wx_phy_write_reg_mdi_c45; 179 } 180 181 snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev)); 182 ret = devm_mdiobus_register(&pdev->dev, mii_bus); 183 if (ret) 184 return ret; 185 186 wx->phydev = phy_find_first(mii_bus); 187 if (!wx->phydev) 188 return -ENODEV; 189 190 phy_attached_info(wx->phydev); 191 192 wx->link = 0; 193 wx->speed = 0; 194 wx->duplex = 0; 195 196 ret = ngbe_phylink_init(wx); 197 if (ret) { 198 wx_err(wx, "failed to init phylink: %d\n", ret); 199 return ret; 200 } 201 202 return 0; 203 } 204