Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fbnic: Replace use of internal PCS w/ Designware XPCS

As we have exposed the PCS registers via the SWMII we can now start looking
at connecting the XPCS driver to those registers and let it mange the PCS
instead of us doing it directly from the fbnic driver.

For now this just gets us the ability to detect link. The hope is in the
future to add some of the vendor specific registers to begin enabling XPCS
configuration of the interface.

Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
Link: https://patch.msgid.link/176374325295.959489.14521115864034905277.stgit@ahduyck-xeon-server.home.arpa
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Alexander Duyck and committed by
Paolo Abeni
d0fe7104 d0ce9fd7

+55 -63
+1
drivers/net/ethernet/meta/Kconfig
··· 26 26 depends on PTP_1588_CLOCK_OPTIONAL 27 27 select NET_DEVLINK 28 28 select PAGE_POOL 29 + select PCS_XPCS 29 30 select PHYLINK 30 31 select PLDMFW 31 32 help
+1 -1
drivers/net/ethernet/meta/fbnic/fbnic_irq.c
··· 133 133 134 134 /* Record link down events */ 135 135 if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec)) 136 - phylink_pcs_change(&fbn->phylink_pcs, false); 136 + phylink_pcs_change(fbn->pcs, false); 137 137 138 138 return IRQ_HANDLED; 139 139 }
+2 -5
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
··· 697 697 **/ 698 698 void fbnic_netdev_free(struct fbnic_dev *fbd) 699 699 { 700 - struct fbnic_net *fbn = netdev_priv(fbd->netdev); 701 - 702 - if (fbn->phylink) 703 - phylink_destroy(fbn->phylink); 700 + fbnic_phylink_destroy(fbd->netdev); 704 701 705 702 free_netdev(fbd->netdev); 706 703 fbd->netdev = NULL; ··· 799 802 800 803 netif_tx_stop_all_queues(netdev); 801 804 802 - if (fbnic_phylink_init(netdev)) { 805 + if (fbnic_phylink_create(netdev)) { 803 806 fbnic_netdev_free(fbd); 804 807 return NULL; 805 808 }
+3 -1
drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
··· 44 44 45 45 struct phylink *phylink; 46 46 struct phylink_config phylink_config; 47 - struct phylink_pcs phylink_pcs; 47 + struct phylink_pcs *pcs; 48 48 49 49 u8 aui; 50 50 u8 fec; ··· 108 108 struct ethtool_link_ksettings *cmd); 109 109 int fbnic_phylink_get_fecparam(struct net_device *netdev, 110 110 struct ethtool_fecparam *fecparam); 111 + int fbnic_phylink_create(struct net_device *netdev); 112 + void fbnic_phylink_destroy(struct net_device *netdev); 111 113 int fbnic_phylink_init(struct net_device *netdev); 112 114 void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev); 113 115 bool fbnic_check_split_frames(struct bpf_prog *prog,
+48 -56
drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 3 4 + #include <linux/pcs/pcs-xpcs.h> 4 5 #include <linux/phy.h> 5 6 #include <linux/phylink.h> 6 7 ··· 102 101 return 0; 103 102 } 104 103 105 - static struct fbnic_net * 106 - fbnic_pcs_to_net(struct phylink_pcs *pcs) 107 - { 108 - return container_of(pcs, struct fbnic_net, phylink_pcs); 109 - } 110 - 111 - static void 112 - fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, 113 - struct phylink_link_state *state) 114 - { 115 - struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 116 - struct fbnic_dev *fbd = fbn->fbd; 117 - 118 - switch (fbn->aui) { 119 - case FBNIC_AUI_25GAUI: 120 - state->speed = SPEED_25000; 121 - break; 122 - case FBNIC_AUI_LAUI2: 123 - case FBNIC_AUI_50GAUI1: 124 - state->speed = SPEED_50000; 125 - break; 126 - case FBNIC_AUI_100GAUI2: 127 - state->speed = SPEED_100000; 128 - break; 129 - default: 130 - state->link = 0; 131 - return; 132 - } 133 - 134 - state->duplex = DUPLEX_FULL; 135 - 136 - state->link = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) && 137 - (rd32(fbd, FBNIC_PCS(MDIO_STAT1, 0)) & 138 - MDIO_STAT1_LSTATUS); 139 - } 140 - 141 - static int 142 - fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, 143 - phy_interface_t interface, 144 - const unsigned long *advertising, 145 - bool permit_pause_to_mac) 146 - { 147 - return 0; 148 - } 149 - 150 - static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = { 151 - .pcs_config = fbnic_phylink_pcs_config, 152 - .pcs_get_state = fbnic_phylink_pcs_get_state, 153 - }; 154 - 155 104 static struct phylink_pcs * 156 105 fbnic_phylink_mac_select_pcs(struct phylink_config *config, 157 106 phy_interface_t interface) ··· 109 158 struct net_device *netdev = to_net_dev(config->dev); 110 159 struct fbnic_net *fbn = netdev_priv(netdev); 111 160 112 - return &fbn->phylink_pcs; 161 + return fbn->pcs; 113 162 } 114 163 115 164 static int ··· 183 232 .mac_link_up = fbnic_phylink_mac_link_up, 184 233 }; 185 234 186 - int fbnic_phylink_init(struct net_device *netdev) 235 + /** 236 + * fbnic_phylink_create - Phylink device creation 237 + * @netdev: Network Device struct to attach phylink device 238 + * 239 + * Initialize and attach a phylink instance to the device. The phylink 240 + * device will make use of the netdev struct to track carrier and will 241 + * eventually be used to expose the current state of the MAC and PCS 242 + * setup. 243 + * 244 + * Return: 0 on success, negative on failure 245 + **/ 246 + int fbnic_phylink_create(struct net_device *netdev) 187 247 { 188 248 struct fbnic_net *fbn = netdev_priv(netdev); 189 249 struct fbnic_dev *fbd = fbn->fbd; 250 + struct phylink_pcs *pcs; 190 251 struct phylink *phylink; 252 + int err; 191 253 192 - fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops; 254 + pcs = xpcs_create_pcs_mdiodev(fbd->mdio_bus, 0); 255 + if (IS_ERR(pcs)) { 256 + err = PTR_ERR(pcs); 257 + dev_err(fbd->dev, "Failed to create PCS device: %d\n", err); 258 + return err; 259 + } 260 + 261 + fbn->pcs = pcs; 193 262 194 263 fbn->phylink_config.dev = &netdev->dev; 195 264 fbn->phylink_config.type = PHYLINK_NETDEV; ··· 232 261 phylink = phylink_create(&fbn->phylink_config, NULL, 233 262 fbnic_phylink_select_interface(fbn->aui), 234 263 &fbnic_phylink_mac_ops); 235 - if (IS_ERR(phylink)) 236 - return PTR_ERR(phylink); 264 + if (IS_ERR(phylink)) { 265 + err = PTR_ERR(phylink); 266 + dev_err(netdev->dev.parent, 267 + "Failed to create Phylink interface, err: %d\n", err); 268 + xpcs_destroy_pcs(pcs); 269 + return err; 270 + } 237 271 238 272 fbn->phylink = phylink; 239 273 240 274 return 0; 275 + } 276 + 277 + /** 278 + * fbnic_phylink_destroy - Teardown phylink related interfaces 279 + * @netdev: Network Device struct containing phylink device 280 + * 281 + * Detach and free resources related to phylink interface. 282 + **/ 283 + void fbnic_phylink_destroy(struct net_device *netdev) 284 + { 285 + struct fbnic_net *fbn = netdev_priv(netdev); 286 + 287 + if (fbn->phylink) 288 + phylink_destroy(fbn->phylink); 289 + if (fbn->pcs) 290 + xpcs_destroy_pcs(fbn->pcs); 241 291 } 242 292 243 293 /** ··· 307 315 FBNIC_PMD_SEND_DATA) != FBNIC_PMD_LINK_READY) 308 316 return; 309 317 310 - phylink_pcs_change(&fbn->phylink_pcs, false); 318 + phylink_pcs_change(fbn->pcs, false); 311 319 }