1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include <linux/pcs/pcs-xpcs.h> 5 #include <linux/phy.h> 6 #include <linux/phylink.h> 7 8 #include "fbnic.h" 9 #include "fbnic_mac.h" 10 #include "fbnic_netdev.h" 11 12 static phy_interface_t fbnic_phylink_select_interface(u8 aui) 13 { 14 switch (aui) { 15 case FBNIC_AUI_100GAUI2: 16 return PHY_INTERFACE_MODE_100GBASEP; 17 case FBNIC_AUI_50GAUI1: 18 return PHY_INTERFACE_MODE_50GBASER; 19 case FBNIC_AUI_LAUI2: 20 return PHY_INTERFACE_MODE_LAUI; 21 case FBNIC_AUI_25GAUI: 22 return PHY_INTERFACE_MODE_25GBASER; 23 } 24 25 return PHY_INTERFACE_MODE_NA; 26 } 27 28 void fbnic_phylink_get_pauseparam(struct net_device *netdev, 29 struct ethtool_pauseparam *pause) 30 { 31 struct fbnic_net *fbn = netdev_priv(netdev); 32 33 phylink_ethtool_get_pauseparam(fbn->phylink, pause); 34 } 35 36 int fbnic_phylink_set_pauseparam(struct net_device *netdev, 37 struct ethtool_pauseparam *pause) 38 { 39 struct fbnic_net *fbn = netdev_priv(netdev); 40 41 return phylink_ethtool_set_pauseparam(fbn->phylink, pause); 42 } 43 44 static void 45 fbnic_phylink_get_supported_fec_modes(unsigned long *supported) 46 { 47 /* The NIC can support up to 8 possible combinations. 48 * Either 50G-CR, or 100G-CR2 49 * This is with RS FEC mode only 50 * Either 25G-CR, or 50G-CR2 51 * This is with No FEC, RS, or Base-R 52 */ 53 if (phylink_test(supported, 100000baseCR2_Full) || 54 phylink_test(supported, 50000baseCR_Full)) 55 phylink_set(supported, FEC_RS); 56 if (phylink_test(supported, 50000baseCR2_Full) || 57 phylink_test(supported, 25000baseCR_Full)) { 58 phylink_set(supported, FEC_BASER); 59 phylink_set(supported, FEC_NONE); 60 phylink_set(supported, FEC_RS); 61 } 62 } 63 64 int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev, 65 struct ethtool_link_ksettings *cmd) 66 { 67 struct fbnic_net *fbn = netdev_priv(netdev); 68 int err; 69 70 err = phylink_ethtool_ksettings_get(fbn->phylink, cmd); 71 if (!err) { 72 unsigned long *supp = cmd->link_modes.supported; 73 74 cmd->base.port = PORT_DA; 75 cmd->lanes = (fbn->aui & FBNIC_AUI_MODE_R2) ? 2 : 1; 76 77 fbnic_phylink_get_supported_fec_modes(supp); 78 } 79 80 return err; 81 } 82 83 int fbnic_phylink_get_fecparam(struct net_device *netdev, 84 struct ethtool_fecparam *fecparam) 85 { 86 struct fbnic_net *fbn = netdev_priv(netdev); 87 88 if (fbn->fec & FBNIC_FEC_RS) { 89 fecparam->active_fec = ETHTOOL_FEC_RS; 90 fecparam->fec = ETHTOOL_FEC_RS; 91 } else if (fbn->fec & FBNIC_FEC_BASER) { 92 fecparam->active_fec = ETHTOOL_FEC_BASER; 93 fecparam->fec = ETHTOOL_FEC_BASER; 94 } else { 95 fecparam->active_fec = ETHTOOL_FEC_OFF; 96 fecparam->fec = ETHTOOL_FEC_OFF; 97 } 98 99 if (fbn->aui & FBNIC_AUI_MODE_PAM4) 100 fecparam->fec |= ETHTOOL_FEC_AUTO; 101 102 return 0; 103 } 104 105 static struct phylink_pcs * 106 fbnic_phylink_mac_select_pcs(struct phylink_config *config, 107 phy_interface_t interface) 108 { 109 struct net_device *netdev = to_net_dev(config->dev); 110 struct fbnic_net *fbn = netdev_priv(netdev); 111 112 return fbn->pcs; 113 } 114 115 static int 116 fbnic_phylink_mac_prepare(struct phylink_config *config, unsigned int mode, 117 phy_interface_t iface) 118 { 119 struct net_device *netdev = to_net_dev(config->dev); 120 struct fbnic_net *fbn = netdev_priv(netdev); 121 struct fbnic_dev *fbd = fbn->fbd; 122 123 fbd->mac->prepare(fbd, fbn->aui, fbn->fec); 124 125 return 0; 126 } 127 128 static void 129 fbnic_phylink_mac_config(struct phylink_config *config, unsigned int mode, 130 const struct phylink_link_state *state) 131 { 132 } 133 134 static int 135 fbnic_phylink_mac_finish(struct phylink_config *config, unsigned int mode, 136 phy_interface_t iface) 137 { 138 struct net_device *netdev = to_net_dev(config->dev); 139 struct fbnic_net *fbn = netdev_priv(netdev); 140 struct fbnic_dev *fbd = fbn->fbd; 141 142 /* Retest the link state and restart interrupts */ 143 fbd->mac->get_link(fbd, fbn->aui, fbn->fec); 144 145 return 0; 146 } 147 148 static void 149 fbnic_phylink_mac_link_down(struct phylink_config *config, unsigned int mode, 150 phy_interface_t interface) 151 { 152 struct net_device *netdev = to_net_dev(config->dev); 153 struct fbnic_net *fbn = netdev_priv(netdev); 154 struct fbnic_dev *fbd = fbn->fbd; 155 156 fbd->mac->link_down(fbd); 157 158 fbn->link_down_events++; 159 } 160 161 static void 162 fbnic_phylink_mac_link_up(struct phylink_config *config, 163 struct phy_device *phy, unsigned int mode, 164 phy_interface_t interface, int speed, int duplex, 165 bool tx_pause, bool rx_pause) 166 { 167 struct net_device *netdev = to_net_dev(config->dev); 168 struct fbnic_net *fbn = netdev_priv(netdev); 169 struct fbnic_dev *fbd = fbn->fbd; 170 171 fbn->tx_pause = tx_pause; 172 fbnic_config_drop_mode(fbn, tx_pause); 173 174 fbd->mac->link_up(fbd, tx_pause, rx_pause); 175 } 176 177 static const struct phylink_mac_ops fbnic_phylink_mac_ops = { 178 .mac_select_pcs = fbnic_phylink_mac_select_pcs, 179 .mac_prepare = fbnic_phylink_mac_prepare, 180 .mac_config = fbnic_phylink_mac_config, 181 .mac_finish = fbnic_phylink_mac_finish, 182 .mac_link_down = fbnic_phylink_mac_link_down, 183 .mac_link_up = fbnic_phylink_mac_link_up, 184 }; 185 186 /** 187 * fbnic_phylink_create - Phylink device creation 188 * @netdev: Network Device struct to attach phylink device 189 * 190 * Initialize and attach a phylink instance to the device. The phylink 191 * device will make use of the netdev struct to track carrier and will 192 * eventually be used to expose the current state of the MAC and PCS 193 * setup. 194 * 195 * Return: 0 on success, negative on failure 196 **/ 197 int fbnic_phylink_create(struct net_device *netdev) 198 { 199 struct fbnic_net *fbn = netdev_priv(netdev); 200 struct fbnic_dev *fbd = fbn->fbd; 201 struct phylink_pcs *pcs; 202 struct phylink *phylink; 203 int err; 204 205 pcs = xpcs_create_pcs_mdiodev(fbd->mdio_bus, 0); 206 if (IS_ERR(pcs)) { 207 err = PTR_ERR(pcs); 208 dev_err(fbd->dev, "Failed to create PCS device: %d\n", err); 209 return err; 210 } 211 212 fbn->pcs = pcs; 213 214 fbn->phylink_config.dev = &netdev->dev; 215 fbn->phylink_config.type = PHYLINK_NETDEV; 216 fbn->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | 217 MAC_25000FD | MAC_50000FD | 218 MAC_100000FD; 219 fbn->phylink_config.default_an_inband = true; 220 221 __set_bit(PHY_INTERFACE_MODE_100GBASEP, 222 fbn->phylink_config.supported_interfaces); 223 __set_bit(PHY_INTERFACE_MODE_50GBASER, 224 fbn->phylink_config.supported_interfaces); 225 __set_bit(PHY_INTERFACE_MODE_LAUI, 226 fbn->phylink_config.supported_interfaces); 227 __set_bit(PHY_INTERFACE_MODE_25GBASER, 228 fbn->phylink_config.supported_interfaces); 229 230 fbnic_mac_get_fw_settings(fbd, &fbn->aui, &fbn->fec); 231 232 phylink = phylink_create(&fbn->phylink_config, NULL, 233 fbnic_phylink_select_interface(fbn->aui), 234 &fbnic_phylink_mac_ops); 235 if (IS_ERR(phylink)) { 236 err = PTR_ERR(phylink); 237 dev_err(netdev->dev.parent, 238 "Failed to create Phylink interface, err: %d\n", err); 239 xpcs_destroy_pcs(pcs); 240 return err; 241 } 242 243 fbn->phylink = phylink; 244 245 return 0; 246 } 247 248 /** 249 * fbnic_phylink_destroy - Teardown phylink related interfaces 250 * @netdev: Network Device struct containing phylink device 251 * 252 * Detach and free resources related to phylink interface. 253 **/ 254 void fbnic_phylink_destroy(struct net_device *netdev) 255 { 256 struct fbnic_net *fbn = netdev_priv(netdev); 257 258 if (fbn->phylink) 259 phylink_destroy(fbn->phylink); 260 if (fbn->pcs) 261 xpcs_destroy_pcs(fbn->pcs); 262 } 263 264 /** 265 * fbnic_phylink_pmd_training_complete_notify - PMD training complete notifier 266 * @netdev: Netdev struct phylink device attached to 267 * 268 * When the link first comes up the PMD will have a period of 2 to 3 seconds 269 * where the link will flutter due to link training. To avoid spamming the 270 * kernel log with messages about this we add a delay of 4 seconds from the 271 * time of the last PCS report of link so that we can guarantee we are unlikely 272 * to see any further link loss events due to link training. 273 **/ 274 void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev) 275 { 276 struct fbnic_net *fbn = netdev_priv(netdev); 277 struct fbnic_dev *fbd = fbn->fbd; 278 279 if (fbd->pmd_state != FBNIC_PMD_TRAINING) 280 return; 281 282 /* Prevent reading end_of_pmd_training until we verified state */ 283 smp_rmb(); 284 285 if (!time_before(READ_ONCE(fbd->end_of_pmd_training), jiffies)) 286 return; 287 288 /* At this point we have verified that the link has been up for 289 * the full training duration. As a first step we will try 290 * transitioning to link ready. 291 */ 292 if (cmpxchg(&fbd->pmd_state, FBNIC_PMD_TRAINING, 293 FBNIC_PMD_LINK_READY) != FBNIC_PMD_TRAINING) 294 return; 295 296 /* Perform a follow-up check to verify that the link didn't flap 297 * just before our transition by rechecking the training timer. 298 */ 299 if (!time_before(READ_ONCE(fbd->end_of_pmd_training), jiffies)) 300 return; 301 302 /* The training timeout has been completed. We are good to swap out 303 * link_ready for send_data assuming no other events have occurred 304 * that would have pulled us back into initialization or training. 305 */ 306 if (cmpxchg(&fbd->pmd_state, FBNIC_PMD_LINK_READY, 307 FBNIC_PMD_SEND_DATA) != FBNIC_PMD_LINK_READY) 308 return; 309 310 phylink_pcs_change(fbn->pcs, false); 311 } 312