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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-phy-add-support-for-fbnic-phy-w-25g-50g-and-100g-support'

Alexander Duyck says:

====================
net: phy: Add support for fbnic PHY w/ 25G, 50G, and 100G support

To transition the fbnic driver to using the XPCS driver we need to address
the fact that we need a representation for the FW managed PMD that is
actually a SerDes PHY to handle link bouncing during link training.

This patch set introduces the necessary bits to the XPCS driver code to
enable it to read 25G, 50G, and 100G speeds from the PCS ctrl1 register,
and adds support for the approriate interfaces.

The rest of this patch set enables the changes to fbnic to make use of
these interfaces and expose a PMD that can provide a necessary link delay
to avoid link flapping in the event that a cable is disconnected and
reconnected, and to correctly expose the count for the link down events.

With this we have the basic groundwork laid as with this all the bits and
pieces are in place in terms of reading the configuration. The general plan
for follow-on patch sets is to start looking at enabling changing the
configuration in environments where that is supported.
====================

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

+620 -154
+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
drivers/net/ethernet/meta/fbnic/Makefile
··· 21 21 fbnic_pci.o \ 22 22 fbnic_phylink.o \ 23 23 fbnic_rpc.o \ 24 + fbnic_mdio.o \ 24 25 fbnic_time.o \ 25 26 fbnic_tlv.o \ 26 27 fbnic_txrx.o \
+12 -3
drivers/net/ethernet/meta/fbnic/fbnic.h
··· 34 34 u32 __iomem *uc_addr4; 35 35 const struct fbnic_mac *mac; 36 36 unsigned int fw_msix_vector; 37 - unsigned int pcs_msix_vector; 37 + unsigned int mac_msix_vector; 38 38 unsigned short num_irqs; 39 39 40 40 struct { ··· 83 83 /* Last @time_high refresh time in jiffies (to catch stalls) */ 84 84 unsigned long last_read; 85 85 86 + /* PMD specific data */ 87 + unsigned long end_of_pmd_training; 88 + u8 pmd_state; 89 + 86 90 /* Local copy of hardware statistics */ 87 91 struct fbnic_hw_stats hw_stats; 88 92 ··· 95 91 u64 prev_firmware_time; 96 92 97 93 struct fbnic_fw_log fw_log; 94 + 95 + /* MDIO bus for PHYs */ 96 + struct mii_bus *mdio_bus; 98 97 }; 99 98 100 99 /* Reserve entry 0 in the MSI-X "others" array until we have filled all ··· 182 175 void fbnic_hwmon_register(struct fbnic_dev *fbd); 183 176 void fbnic_hwmon_unregister(struct fbnic_dev *fbd); 184 177 185 - int fbnic_pcs_request_irq(struct fbnic_dev *fbd); 186 - void fbnic_pcs_free_irq(struct fbnic_dev *fbd); 178 + int fbnic_mac_request_irq(struct fbnic_dev *fbd); 179 + void fbnic_mac_free_irq(struct fbnic_dev *fbd); 187 180 188 181 void fbnic_napi_name_irqs(struct fbnic_dev *fbd); 189 182 int fbnic_napi_request_irq(struct fbnic_dev *fbd, ··· 206 199 void fbnic_dbg_exit(void); 207 200 208 201 void fbnic_rpc_reset_valid_entries(struct fbnic_dev *fbd); 202 + 203 + int fbnic_mdiobus_create(struct fbnic_dev *fbd); 209 204 210 205 void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version); 211 206 int fbnic_csr_regs_len(struct fbnic_dev *fbd);
+2
drivers/net/ethernet/meta/fbnic/fbnic_csr.h
··· 787 787 788 788 /* MAC PCS registers */ 789 789 #define FBNIC_CSR_START_PCS 0x10000 /* CSR section delimiter */ 790 + #define FBNIC_PCS_PAGE(n) (0x10000 + 0x400 * (n)) /* 0x40000 + 1024*n */ 791 + #define FBNIC_PCS(reg, n) ((reg) + FBNIC_PCS_PAGE(n)) 790 792 #define FBNIC_CSR_END_PCS 0x10668 /* CSR section delimiter */ 791 793 792 794 #define FBNIC_CSR_START_RSFEC 0x10800 /* CSR section delimiter */
+9
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
··· 1863 1863 *ranges = fbnic_rmon_ranges; 1864 1864 } 1865 1865 1866 + static void fbnic_get_link_ext_stats(struct net_device *netdev, 1867 + struct ethtool_link_ext_stats *stats) 1868 + { 1869 + struct fbnic_net *fbn = netdev_priv(netdev); 1870 + 1871 + stats->link_down_events = fbn->link_down_events; 1872 + } 1873 + 1866 1874 static const struct ethtool_ops fbnic_ethtool_ops = { 1867 1875 .cap_link_lanes_supported = true, 1868 1876 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ··· 1882 1874 .get_regs_len = fbnic_get_regs_len, 1883 1875 .get_regs = fbnic_get_regs, 1884 1876 .get_link = ethtool_op_get_link, 1877 + .get_link_ext_stats = fbnic_get_link_ext_stats, 1885 1878 .get_coalesce = fbnic_get_coalesce, 1886 1879 .set_coalesce = fbnic_set_coalesce, 1887 1880 .get_ringparam = fbnic_get_ringparam,
+18 -16
drivers/net/ethernet/meta/fbnic/fbnic_irq.c
··· 118 118 fbd->fw_msix_vector = 0; 119 119 } 120 120 121 - static irqreturn_t fbnic_pcs_msix_intr(int __always_unused irq, void *data) 121 + static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data) 122 122 { 123 123 struct fbnic_dev *fbd = data; 124 124 struct fbnic_net *fbn; 125 125 126 - if (fbd->mac->pcs_get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) { 126 + if (fbd->mac->get_link_event(fbd) == FBNIC_LINK_EVENT_NONE) { 127 127 fbnic_wr32(fbd, FBNIC_INTR_MASK_CLEAR(0), 128 128 1u << FBNIC_PCS_MSIX_ENTRY); 129 129 return IRQ_HANDLED; ··· 131 131 132 132 fbn = netdev_priv(fbd->netdev); 133 133 134 - phylink_pcs_change(&fbn->phylink_pcs, false); 134 + /* Record link down events */ 135 + if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec)) 136 + phylink_pcs_change(fbn->pcs, false); 135 137 136 138 return IRQ_HANDLED; 137 139 } 138 140 139 141 /** 140 - * fbnic_pcs_request_irq - Configure the PCS to enable it to advertise link 142 + * fbnic_mac_request_irq - Configure the MAC to enable it to advertise link 141 143 * @fbd: Pointer to device to initialize 142 144 * 143 - * This function provides basic bringup for the MAC/PCS IRQ. For now the IRQ 145 + * This function provides basic bringup for the MAC/PHY IRQ. For now the IRQ 144 146 * will remain disabled until we start the MAC/PCS/PHY logic via phylink. 145 147 * 146 148 * Return: non-zero on failure. 147 149 **/ 148 - int fbnic_pcs_request_irq(struct fbnic_dev *fbd) 150 + int fbnic_mac_request_irq(struct fbnic_dev *fbd) 149 151 { 150 152 struct pci_dev *pdev = to_pci_dev(fbd->dev); 151 153 int vector, err; 152 154 153 - WARN_ON(fbd->pcs_msix_vector); 155 + WARN_ON(fbd->mac_msix_vector); 154 156 155 157 vector = pci_irq_vector(pdev, FBNIC_PCS_MSIX_ENTRY); 156 158 if (vector < 0) ··· 161 159 /* Request the IRQ for PCS link vector. 162 160 * Map PCS cause to it, and unmask it 163 161 */ 164 - err = request_irq(vector, &fbnic_pcs_msix_intr, 0, 162 + err = request_irq(vector, &fbnic_mac_msix_intr, 0, 165 163 fbd->netdev->name, fbd); 166 164 if (err) 167 165 return err; ··· 170 168 fbnic_wr32(fbd, FBNIC_INTR_MSIX_CTRL(FBNIC_INTR_MSIX_CTRL_PCS_IDX), 171 169 FBNIC_PCS_MSIX_ENTRY | FBNIC_INTR_MSIX_CTRL_ENABLE); 172 170 173 - fbd->pcs_msix_vector = vector; 171 + fbd->mac_msix_vector = vector; 174 172 175 173 return 0; 176 174 } 177 175 178 176 /** 179 - * fbnic_pcs_free_irq - Teardown the PCS IRQ to prepare for stopping 177 + * fbnic_mac_free_irq - Teardown the MAC IRQ to prepare for stopping 180 178 * @fbd: Pointer to device that is stopping 181 179 * 182 - * This function undoes the work done in fbnic_pcs_request_irq and prepares 180 + * This function undoes the work done in fbnic_mac_request_irq and prepares 183 181 * the device to no longer receive traffic on the host interface. 184 182 **/ 185 - void fbnic_pcs_free_irq(struct fbnic_dev *fbd) 183 + void fbnic_mac_free_irq(struct fbnic_dev *fbd) 186 184 { 187 185 /* Vector has already been freed */ 188 - if (!fbd->pcs_msix_vector) 186 + if (!fbd->mac_msix_vector) 189 187 return; 190 188 191 189 /* Disable interrupt */ ··· 194 192 fbnic_wrfl(fbd); 195 193 196 194 /* Synchronize IRQ to prevent race that would unmask vector */ 197 - synchronize_irq(fbd->pcs_msix_vector); 195 + synchronize_irq(fbd->mac_msix_vector); 198 196 199 197 /* Mask the vector */ 200 198 fbnic_wr32(fbd, FBNIC_INTR_MASK_SET(0), 1u << FBNIC_PCS_MSIX_ENTRY); 201 199 202 200 /* Free the vector */ 203 - free_irq(fbd->pcs_msix_vector, fbd); 204 - fbd->pcs_msix_vector = 0; 201 + free_irq(fbd->mac_msix_vector, fbd); 202 + fbd->mac_msix_vector = 0; 205 203 } 206 204 207 205 void fbnic_synchronize_irq(struct fbnic_dev *fbd, int nr)
+57 -24
drivers/net/ethernet/meta/fbnic/fbnic_mac.c
··· 434 434 wr32(fbd, FBNIC_RXB_PAUSE_DROP_CTRL, rxb_pause_ctrl); 435 435 } 436 436 437 - static int fbnic_pcs_get_link_event_asic(struct fbnic_dev *fbd) 437 + static int fbnic_mac_get_link_event(struct fbnic_dev *fbd) 438 438 { 439 - u32 pcs_intr_mask = rd32(fbd, FBNIC_SIG_PCS_INTR_STS); 439 + u32 intr_mask = rd32(fbd, FBNIC_SIG_PCS_INTR_STS); 440 440 441 - if (pcs_intr_mask & FBNIC_SIG_PCS_INTR_LINK_DOWN) 441 + if (intr_mask & FBNIC_SIG_PCS_INTR_LINK_DOWN) 442 442 return FBNIC_LINK_EVENT_DOWN; 443 443 444 - return (pcs_intr_mask & FBNIC_SIG_PCS_INTR_LINK_UP) ? 444 + return (intr_mask & FBNIC_SIG_PCS_INTR_LINK_UP) ? 445 445 FBNIC_LINK_EVENT_UP : FBNIC_LINK_EVENT_NONE; 446 446 } 447 447 ··· 466 466 return command_config; 467 467 } 468 468 469 - static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd) 469 + static bool fbnic_mac_get_link_status(struct fbnic_dev *fbd, u8 aui, u8 fec) 470 470 { 471 - struct fbnic_net *fbn = netdev_priv(fbd->netdev); 472 471 u32 pcs_status, lane_mask = ~0; 473 472 474 473 pcs_status = rd32(fbd, FBNIC_SIG_PCS_OUT0); ··· 475 476 return false; 476 477 477 478 /* Define the expected lane mask for the status bits we need to check */ 478 - switch (fbn->aui) { 479 + switch (aui) { 479 480 case FBNIC_AUI_100GAUI2: 480 481 lane_mask = 0xf; 481 482 break; ··· 483 484 lane_mask = 3; 484 485 break; 485 486 case FBNIC_AUI_LAUI2: 486 - switch (fbn->fec) { 487 + switch (fec) { 487 488 case FBNIC_FEC_OFF: 488 489 lane_mask = 0x63; 489 490 break; ··· 501 502 } 502 503 503 504 /* Use an XOR to remove the bits we expect to see set */ 504 - switch (fbn->fec) { 505 + switch (fec) { 505 506 case FBNIC_FEC_OFF: 506 507 lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK, 507 508 pcs_status); ··· 520 521 return !lane_mask; 521 522 } 522 523 523 - static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd) 524 + static bool fbnic_pmd_update_state(struct fbnic_dev *fbd, bool signal_detect) 525 + { 526 + /* Delay link up for 4 seconds to allow for link training. 527 + * The state transitions for this are as follows: 528 + * 529 + * All states have the following two transitions in common: 530 + * Loss of signal -> FBNIC_PMD_INITIALIZE 531 + * The condition handled below (!signal) 532 + * Reconfiguration -> FBNIC_PMD_INITIALIZE 533 + * Occurs when mac_prepare starts a PHY reconfig 534 + * FBNIC_PMD_TRAINING: 535 + * signal still detected && 4s have passed -> Report link up 536 + * When link is brought up in link_up -> FBNIC_PMD_SEND_DATA 537 + * FBNIC_PMD_INITIALIZE: 538 + * signal detected -> FBNIC_PMD_TRAINING 539 + */ 540 + if (!signal_detect) { 541 + fbd->pmd_state = FBNIC_PMD_INITIALIZE; 542 + return false; 543 + } 544 + 545 + switch (fbd->pmd_state) { 546 + case FBNIC_PMD_TRAINING: 547 + return time_before(fbd->end_of_pmd_training, jiffies); 548 + case FBNIC_PMD_LINK_READY: 549 + case FBNIC_PMD_SEND_DATA: 550 + return true; 551 + } 552 + 553 + fbd->end_of_pmd_training = jiffies + 4 * HZ; 554 + 555 + /* Ensure end_of_training is visible before the state change */ 556 + smp_wmb(); 557 + 558 + fbd->pmd_state = FBNIC_PMD_TRAINING; 559 + 560 + return false; 561 + } 562 + 563 + static bool fbnic_mac_get_link(struct fbnic_dev *fbd, u8 aui, u8 fec) 524 564 { 525 565 bool link; 526 566 ··· 576 538 wr32(fbd, FBNIC_SIG_PCS_INTR_STS, 577 539 FBNIC_SIG_PCS_INTR_LINK_DOWN | FBNIC_SIG_PCS_INTR_LINK_UP); 578 540 579 - link = fbnic_mac_get_pcs_link_status(fbd); 541 + link = fbnic_mac_get_link_status(fbd, aui, fec); 542 + link = fbnic_pmd_update_state(fbd, link); 580 543 581 544 /* Enable interrupt to only capture changes in link state */ 582 545 wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ··· 625 586 } 626 587 } 627 588 628 - static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd) 589 + static void fbnic_mac_prepare(struct fbnic_dev *fbd, u8 aui, u8 fec) 629 590 { 630 591 /* Mask and clear the PCS interrupt, will be enabled by link handler */ 631 592 wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0); 632 593 wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); 633 594 634 - return 0; 635 - } 636 - 637 - static void fbnic_pcs_disable_asic(struct fbnic_dev *fbd) 638 - { 639 - /* Mask and clear the PCS interrupt */ 640 - wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0); 641 - wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0); 595 + /* If we don't have link tear it all down and start over */ 596 + if (!fbnic_mac_get_link_status(fbd, aui, fec)) 597 + fbd->pmd_state = FBNIC_PMD_INITIALIZE; 642 598 } 643 599 644 600 static void fbnic_mac_link_down_asic(struct fbnic_dev *fbd) ··· 901 867 902 868 static const struct fbnic_mac fbnic_mac_asic = { 903 869 .init_regs = fbnic_mac_init_regs, 904 - .pcs_enable = fbnic_pcs_enable_asic, 905 - .pcs_disable = fbnic_pcs_disable_asic, 906 - .pcs_get_link = fbnic_pcs_get_link_asic, 907 - .pcs_get_link_event = fbnic_pcs_get_link_event_asic, 870 + .get_link = fbnic_mac_get_link, 871 + .get_link_event = fbnic_mac_get_link_event, 872 + .prepare = fbnic_mac_prepare, 908 873 .get_fec_stats = fbnic_mac_get_fec_stats, 909 874 .get_pcs_stats = fbnic_mac_get_pcs_stats, 910 875 .get_eth_mac_stats = fbnic_mac_get_eth_mac_stats,
+30 -11
drivers/net/ethernet/meta/fbnic/fbnic_mac.h
··· 10 10 11 11 #define FBNIC_MAX_JUMBO_FRAME_SIZE 9742 12 12 13 + /* States loosely based on section 136.8.11.7.5 of IEEE 802.3-2022 Ethernet 14 + * Standard. These are needed to track the state of the PHY as it has a delay 15 + * of several seconds from the time link comes up until it has completed 16 + * training that we need to wait to report the link. 17 + * 18 + * Currently we treat training as a single block as this is managed by the 19 + * firmware. 20 + * 21 + * We have FBNIC_PMD_SEND_DATA set to 0 as the expected default at driver load 22 + * and we initialize the structure containing it to zero at allocation. 23 + */ 24 + enum { 25 + FBNIC_PMD_SEND_DATA = 0x0, 26 + FBNIC_PMD_INITIALIZE = 0x1, 27 + FBNIC_PMD_TRAINING = 0x2, 28 + FBNIC_PMD_LINK_READY = 0x3, 29 + }; 30 + 13 31 enum { 14 32 FBNIC_LINK_EVENT_NONE = 0, 15 33 FBNIC_LINK_EVENT_UP = 1, ··· 56 38 FBNIC_AUI_50GAUI1 = 2, /* 53.125GBd 53.125 * 1 */ 57 39 FBNIC_AUI_100GAUI2 = 3, /* 106.25GBd 53.125 * 2 */ 58 40 FBNIC_AUI_UNKNOWN = 4, 41 + __FBNIC_AUI_MAX__ 59 42 }; 60 43 61 44 #define FBNIC_AUI_MODE_R2 (FBNIC_AUI_LAUI2) ··· 74 55 * void (*init_regs)(struct fbnic_dev *fbd); 75 56 * Initialize MAC registers to enable Tx/Rx paths and FIFOs. 76 57 * 77 - * void (*pcs_enable)(struct fbnic_dev *fbd); 78 - * Configure and enable PCS to enable link if not already enabled 79 - * void (*pcs_disable)(struct fbnic_dev *fbd); 80 - * Shutdown the link if we are the only consumer of it. 81 - * bool (*pcs_get_link)(struct fbnic_dev *fbd); 82 - * Check PCS link status 83 - * int (*pcs_get_link_event)(struct fbnic_dev *fbd) 58 + * int (*get_link_event)(struct fbnic_dev *fbd) 84 59 * Get the current link event status, reports true if link has 85 60 * changed to either FBNIC_LINK_EVENT_DOWN or FBNIC_LINK_EVENT_UP 61 + * bool (*get_link)(struct fbnic_dev *fbd, u8 aui, u8 fec); 62 + * Check link status 63 + * 64 + * void (*prepare)(struct fbnic_dev *fbd, u8 aui, u8 fec); 65 + * Prepare PHY for init by fetching settings, disabling interrupts, 66 + * and sending an updated PHY config to FW if needed. 86 67 * 87 68 * void (*link_down)(struct fbnic_dev *fbd); 88 69 * Configure MAC for link down event ··· 93 74 struct fbnic_mac { 94 75 void (*init_regs)(struct fbnic_dev *fbd); 95 76 96 - int (*pcs_enable)(struct fbnic_dev *fbd); 97 - void (*pcs_disable)(struct fbnic_dev *fbd); 98 - bool (*pcs_get_link)(struct fbnic_dev *fbd); 99 - int (*pcs_get_link_event)(struct fbnic_dev *fbd); 77 + int (*get_link_event)(struct fbnic_dev *fbd); 78 + bool (*get_link)(struct fbnic_dev *fbd, u8 aui, u8 fec); 79 + 80 + void (*prepare)(struct fbnic_dev *fbd, u8 aui, u8 fec); 100 81 101 82 void (*get_fec_stats)(struct fbnic_dev *fbd, bool reset, 102 83 struct fbnic_fec_stats *fec_stats);
+195
drivers/net/ethernet/meta/fbnic/fbnic_mdio.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <linux/mdio.h> 5 + #include <linux/pcs/pcs-xpcs.h> 6 + 7 + #include "fbnic.h" 8 + #include "fbnic_netdev.h" 9 + 10 + #define DW_VENDOR BIT(15) 11 + #define FBNIC_PCS_VENDOR BIT(9) 12 + #define FBNIC_PCS_ZERO_MASK (DW_VENDOR - FBNIC_PCS_VENDOR) 13 + 14 + static int 15 + fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) 16 + { 17 + u8 aui = FBNIC_AUI_UNKNOWN; 18 + struct fbnic_net *fbn; 19 + int ret = 0; 20 + 21 + /* We don't need a second PMD, just one can handle both lanes */ 22 + if (addr) 23 + return 0; 24 + 25 + if (fbd->netdev) { 26 + fbn = netdev_priv(fbd->netdev); 27 + if (fbn->aui < FBNIC_AUI_UNKNOWN) 28 + aui = fbn->aui; 29 + } 30 + 31 + switch (regnum) { 32 + case MDIO_DEVID1: 33 + ret = MP_FBNIC_XPCS_PMA_100G_ID >> 16; 34 + break; 35 + case MDIO_DEVID2: 36 + ret = MP_FBNIC_XPCS_PMA_100G_ID & 0xffff; 37 + break; 38 + case MDIO_DEVS1: 39 + ret = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS; 40 + break; 41 + case MDIO_STAT2: 42 + ret = MDIO_STAT2_DEVPRST_VAL; 43 + break; 44 + case MDIO_PMA_RXDET: 45 + /* If training isn't complete default to 0 */ 46 + if (fbd->pmd_state != FBNIC_PMD_SEND_DATA) 47 + break; 48 + /* Report either 1 or 2 lanes detected depending on config */ 49 + ret = (MDIO_PMD_RXDET_GLOBAL | MDIO_PMD_RXDET_0) | 50 + ((aui & FBNIC_AUI_MODE_R2) * 51 + (MDIO_PMD_RXDET_1 / FBNIC_AUI_MODE_R2)); 52 + break; 53 + default: 54 + break; 55 + } 56 + 57 + dev_dbg(fbd->dev, 58 + "SWMII PMD Rd: Addr: %d RegNum: %d Value: 0x%04x\n", 59 + addr, regnum, ret); 60 + 61 + return ret; 62 + } 63 + 64 + static int 65 + fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum) 66 + { 67 + int ret, offset = 0; 68 + 69 + /* We will need access to both PCS instances to get config info */ 70 + if (addr >= 2) 71 + return 0; 72 + 73 + /* Report 0 for reserved registers */ 74 + if (regnum & FBNIC_PCS_ZERO_MASK) 75 + return 0; 76 + 77 + /* Intercept and return correct ID for PCS */ 78 + if (regnum == MDIO_DEVID1) 79 + return DW_XPCS_ID >> 16; 80 + if (regnum == MDIO_DEVID2) 81 + return DW_XPCS_ID & 0xffff; 82 + if (regnum == MDIO_DEVS1) 83 + return MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS; 84 + 85 + /* Swap vendor page bit for FBNIC PCS vendor page bit */ 86 + if (regnum & DW_VENDOR) 87 + offset ^= DW_VENDOR | FBNIC_PCS_VENDOR; 88 + 89 + ret = fbnic_rd32(fbd, FBNIC_PCS_PAGE(addr) + (regnum ^ offset)); 90 + 91 + dev_dbg(fbd->dev, 92 + "SWMII PCS Rd: Addr: %d RegNum: %d Value: 0x%04x\n", 93 + addr, regnum, ret); 94 + 95 + return ret; 96 + } 97 + 98 + static int 99 + fbnic_mdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum) 100 + { 101 + struct fbnic_dev *fbd = bus->priv; 102 + 103 + if (devnum == MDIO_MMD_PMAPMD) 104 + return fbnic_mdio_read_pmd(fbd, addr, regnum); 105 + 106 + if (devnum == MDIO_MMD_PCS) 107 + return fbnic_mdio_read_pcs(fbd, addr, regnum); 108 + 109 + return 0; 110 + } 111 + 112 + static void 113 + fbnic_mdio_write_pmd(struct fbnic_dev *fbd, int addr, int regnum, u16 val) 114 + { 115 + dev_dbg(fbd->dev, 116 + "SWMII PMD Wr: Addr: %d RegNum: %d Value: 0x%04x\n", 117 + addr, regnum, val); 118 + } 119 + 120 + static void 121 + fbnic_mdio_write_pcs(struct fbnic_dev *fbd, int addr, int regnum, u16 val) 122 + { 123 + dev_dbg(fbd->dev, 124 + "SWMII PCS Wr: Addr: %d RegNum: %d Value: 0x%04x\n", 125 + addr, regnum, val); 126 + 127 + /* Allow access to both halves of PCS for 50R2 config */ 128 + if (addr > 2) 129 + return; 130 + 131 + /* Skip write for reserved registers */ 132 + if (regnum & FBNIC_PCS_ZERO_MASK) 133 + return; 134 + 135 + /* Swap vendor page bit for FBNIC PCS vendor page bit */ 136 + if (regnum & DW_VENDOR) 137 + regnum ^= DW_VENDOR | FBNIC_PCS_VENDOR; 138 + 139 + fbnic_wr32(fbd, FBNIC_PCS_PAGE(addr) + regnum, val); 140 + } 141 + 142 + static int 143 + fbnic_mdio_write_c45(struct mii_bus *bus, int addr, int devnum, 144 + int regnum, u16 val) 145 + { 146 + struct fbnic_dev *fbd = bus->priv; 147 + 148 + if (devnum == MDIO_MMD_PMAPMD) 149 + fbnic_mdio_write_pmd(fbd, addr, regnum, val); 150 + 151 + if (devnum == MDIO_MMD_PCS) 152 + fbnic_mdio_write_pcs(fbd, addr, regnum, val); 153 + 154 + return 0; 155 + } 156 + 157 + /** 158 + * fbnic_mdiobus_create - Create an MDIO bus to allow interfacing w/ PHYs 159 + * @fbd: Pointer to FBNIC device structure to populate bus on 160 + * 161 + * Initialize an MDIO bus and place a pointer to it on the fbd struct. This bus 162 + * will be used to interface with the PMA/PMD and PCS. 163 + * 164 + * Return: 0 on success, negative on failure 165 + **/ 166 + int fbnic_mdiobus_create(struct fbnic_dev *fbd) 167 + { 168 + struct mii_bus *bus; 169 + int err; 170 + 171 + bus = devm_mdiobus_alloc(fbd->dev); 172 + if (!bus) 173 + return -ENOMEM; 174 + 175 + bus->name = "fbnic_mii_bus"; 176 + bus->read_c45 = &fbnic_mdio_read_c45; 177 + bus->write_c45 = &fbnic_mdio_write_c45; 178 + 179 + /* Disable PHY auto probing. We will add PCS manually */ 180 + bus->phy_mask = ~0; 181 + 182 + bus->parent = fbd->dev; 183 + bus->priv = fbd; 184 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(fbd->dev)); 185 + 186 + err = devm_mdiobus_register(fbd->dev, bus); 187 + if (err) { 188 + dev_err(fbd->dev, "Failed to create MDIO bus: %d\n", err); 189 + return err; 190 + } 191 + 192 + fbd->mdio_bus = bus; 193 + 194 + return 0; 195 + }
+4 -7
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
··· 44 44 if (err) 45 45 goto time_stop; 46 46 47 - err = fbnic_pcs_request_irq(fbd); 47 + err = fbnic_mac_request_irq(fbd); 48 48 if (err) 49 49 goto time_stop; 50 50 ··· 86 86 { 87 87 struct fbnic_net *fbn = netdev_priv(netdev); 88 88 89 + fbnic_mac_free_irq(fbn->fbd); 89 90 phylink_suspend(fbn->phylink, fbnic_bmc_present(fbn->fbd)); 90 91 91 92 fbnic_down(fbn); 92 - fbnic_pcs_free_irq(fbn->fbd); 93 93 94 94 fbnic_time_stop(fbn); 95 95 fbnic_fw_xmit_ownership_msg(fbn->fbd, false); ··· 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 }
+4 -2
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, 114 116 unsigned int mtu, u32 hds_threshold); 115 117 #endif /* _FBNIC_NETDEV_H_ */
+8 -1
drivers/net/ethernet/meta/fbnic/fbnic_pci.c
··· 207 207 { 208 208 struct fbnic_dev *fbd = container_of(to_delayed_work(work), 209 209 struct fbnic_dev, service_task); 210 + struct net_device *netdev = fbd->netdev; 211 + 212 + if (netif_running(netdev)) 213 + fbnic_phylink_pmd_training_complete_notify(netdev); 210 214 211 215 rtnl_lock(); 212 216 ··· 228 224 netdev_unlock(fbd->netdev); 229 225 } 230 226 231 - if (netif_running(fbd->netdev)) 227 + if (netif_running(netdev)) 232 228 schedule_delayed_work(&fbd->service_task, HZ); 233 229 234 230 rtnl_unlock(); ··· 338 334 dev_warn(&pdev->dev, "Reading serial number failed\n"); 339 335 goto init_failure_mode; 340 336 } 337 + 338 + if (fbnic_mdiobus_create(fbd)) 339 + goto init_failure_mode; 341 340 342 341 netdev = fbnic_netdev_alloc(fbd); 343 342 if (!netdev) {
+125 -73
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->mac->pcs_get_link(fbd); 137 - } 138 - 139 - static int 140 - fbnic_phylink_pcs_enable(struct phylink_pcs *pcs) 141 - { 142 - struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 143 - struct fbnic_dev *fbd = fbn->fbd; 144 - 145 - return fbd->mac->pcs_enable(fbd); 146 - } 147 - 148 - static void 149 - fbnic_phylink_pcs_disable(struct phylink_pcs *pcs) 150 - { 151 - struct fbnic_net *fbn = fbnic_pcs_to_net(pcs); 152 - struct fbnic_dev *fbd = fbn->fbd; 153 - 154 - return fbd->mac->pcs_disable(fbd); 155 - } 156 - 157 - static int 158 - fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, 159 - phy_interface_t interface, 160 - const unsigned long *advertising, 161 - bool permit_pause_to_mac) 162 - { 163 - return 0; 164 - } 165 - 166 - static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = { 167 - .pcs_config = fbnic_phylink_pcs_config, 168 - .pcs_enable = fbnic_phylink_pcs_enable, 169 - .pcs_disable = fbnic_phylink_pcs_disable, 170 - .pcs_get_state = fbnic_phylink_pcs_get_state, 171 - }; 172 - 173 104 static struct phylink_pcs * 174 105 fbnic_phylink_mac_select_pcs(struct phylink_config *config, 175 106 phy_interface_t interface) ··· 109 176 struct net_device *netdev = to_net_dev(config->dev); 110 177 struct fbnic_net *fbn = netdev_priv(netdev); 111 178 112 - return &fbn->phylink_pcs; 179 + return fbn->pcs; 180 + } 181 + 182 + static int 183 + fbnic_phylink_mac_prepare(struct phylink_config *config, unsigned int mode, 184 + phy_interface_t iface) 185 + { 186 + struct net_device *netdev = to_net_dev(config->dev); 187 + struct fbnic_net *fbn = netdev_priv(netdev); 188 + struct fbnic_dev *fbd = fbn->fbd; 189 + 190 + fbd->mac->prepare(fbd, fbn->aui, fbn->fec); 191 + 192 + return 0; 113 193 } 114 194 115 195 static void 116 196 fbnic_phylink_mac_config(struct phylink_config *config, unsigned int mode, 117 197 const struct phylink_link_state *state) 118 198 { 199 + } 200 + 201 + static int 202 + fbnic_phylink_mac_finish(struct phylink_config *config, unsigned int mode, 203 + phy_interface_t iface) 204 + { 205 + struct net_device *netdev = to_net_dev(config->dev); 206 + struct fbnic_net *fbn = netdev_priv(netdev); 207 + struct fbnic_dev *fbd = fbn->fbd; 208 + 209 + /* Retest the link state and restart interrupts */ 210 + fbd->mac->get_link(fbd, fbn->aui, fbn->fec); 211 + 212 + return 0; 119 213 } 120 214 121 215 static void ··· 176 216 177 217 static const struct phylink_mac_ops fbnic_phylink_mac_ops = { 178 218 .mac_select_pcs = fbnic_phylink_mac_select_pcs, 219 + .mac_prepare = fbnic_phylink_mac_prepare, 179 220 .mac_config = fbnic_phylink_mac_config, 221 + .mac_finish = fbnic_phylink_mac_finish, 180 222 .mac_link_down = fbnic_phylink_mac_link_down, 181 223 .mac_link_up = fbnic_phylink_mac_link_up, 182 224 }; 183 225 184 - int fbnic_phylink_init(struct net_device *netdev) 226 + /** 227 + * fbnic_phylink_create - Phylink device creation 228 + * @netdev: Network Device struct to attach phylink device 229 + * 230 + * Initialize and attach a phylink instance to the device. The phylink 231 + * device will make use of the netdev struct to track carrier and will 232 + * eventually be used to expose the current state of the MAC and PCS 233 + * setup. 234 + * 235 + * Return: 0 on success, negative on failure 236 + **/ 237 + int fbnic_phylink_create(struct net_device *netdev) 185 238 { 186 239 struct fbnic_net *fbn = netdev_priv(netdev); 187 240 struct fbnic_dev *fbd = fbn->fbd; 241 + struct phylink_pcs *pcs; 188 242 struct phylink *phylink; 243 + int err; 189 244 190 - fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops; 245 + pcs = xpcs_create_pcs_mdiodev(fbd->mdio_bus, 0); 246 + if (IS_ERR(pcs)) { 247 + err = PTR_ERR(pcs); 248 + dev_err(fbd->dev, "Failed to create PCS device: %d\n", err); 249 + return err; 250 + } 251 + 252 + fbn->pcs = pcs; 191 253 192 254 fbn->phylink_config.dev = &netdev->dev; 193 255 fbn->phylink_config.type = PHYLINK_NETDEV; ··· 232 250 phylink = phylink_create(&fbn->phylink_config, NULL, 233 251 fbnic_phylink_select_interface(fbn->aui), 234 252 &fbnic_phylink_mac_ops); 235 - if (IS_ERR(phylink)) 236 - return PTR_ERR(phylink); 253 + if (IS_ERR(phylink)) { 254 + err = PTR_ERR(phylink); 255 + dev_err(netdev->dev.parent, 256 + "Failed to create Phylink interface, err: %d\n", err); 257 + xpcs_destroy_pcs(pcs); 258 + return err; 259 + } 237 260 238 261 fbn->phylink = phylink; 239 262 240 263 return 0; 264 + } 265 + 266 + /** 267 + * fbnic_phylink_destroy - Teardown phylink related interfaces 268 + * @netdev: Network Device struct containing phylink device 269 + * 270 + * Detach and free resources related to phylink interface. 271 + **/ 272 + void fbnic_phylink_destroy(struct net_device *netdev) 273 + { 274 + struct fbnic_net *fbn = netdev_priv(netdev); 275 + 276 + if (fbn->phylink) 277 + phylink_destroy(fbn->phylink); 278 + if (fbn->pcs) 279 + xpcs_destroy_pcs(fbn->pcs); 280 + } 281 + 282 + /** 283 + * fbnic_phylink_pmd_training_complete_notify - PMD training complete notifier 284 + * @netdev: Netdev struct phylink device attached to 285 + * 286 + * When the link first comes up the PMD will have a period of 2 to 3 seconds 287 + * where the link will flutter due to link training. To avoid spamming the 288 + * kernel log with messages about this we add a delay of 4 seconds from the 289 + * time of the last PCS report of link so that we can guarantee we are unlikely 290 + * to see any further link loss events due to link training. 291 + **/ 292 + void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev) 293 + { 294 + struct fbnic_net *fbn = netdev_priv(netdev); 295 + struct fbnic_dev *fbd = fbn->fbd; 296 + 297 + if (fbd->pmd_state != FBNIC_PMD_TRAINING) 298 + return; 299 + 300 + /* Prevent reading end_of_pmd_training until we verified state */ 301 + smp_rmb(); 302 + 303 + if (!time_before(READ_ONCE(fbd->end_of_pmd_training), jiffies)) 304 + return; 305 + 306 + /* At this point we have verified that the link has been up for 307 + * the full training duration. As a first step we will try 308 + * transitioning to link ready. 309 + */ 310 + if (cmpxchg(&fbd->pmd_state, FBNIC_PMD_TRAINING, 311 + FBNIC_PMD_LINK_READY) != FBNIC_PMD_TRAINING) 312 + return; 313 + 314 + /* Perform a follow-up check to verify that the link didn't flap 315 + * just before our transition by rechecking the training timer. 316 + */ 317 + if (!time_before(READ_ONCE(fbd->end_of_pmd_training), jiffies)) 318 + return; 319 + 320 + /* The training timeout has been completed. We are good to swap out 321 + * link_ready for send_data assuming no other events have occurred 322 + * that would have pulled us back into initialization or training. 323 + */ 324 + if (cmpxchg(&fbd->pmd_state, FBNIC_PMD_LINK_READY, 325 + FBNIC_PMD_SEND_DATA) != FBNIC_PMD_LINK_READY) 326 + return; 327 + 328 + phylink_pcs_change(fbn->pcs, false); 241 329 }
+126 -10
drivers/net/pcs/pcs-xpcs.c
··· 37 37 __ETHTOOL_LINK_MODE_MASK_NBITS, 38 38 }; 39 39 40 + static const int xpcs_25gbaser_features[] = { 41 + ETHTOOL_LINK_MODE_MII_BIT, 42 + ETHTOOL_LINK_MODE_Pause_BIT, 43 + ETHTOOL_LINK_MODE_Asym_Pause_BIT, 44 + ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, 45 + ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, 46 + ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, 47 + __ETHTOOL_LINK_MODE_MASK_NBITS, 48 + }; 49 + 40 50 static const int xpcs_xlgmii_features[] = { 41 51 ETHTOOL_LINK_MODE_Pause_BIT, 42 52 ETHTOOL_LINK_MODE_Asym_Pause_BIT, ··· 69 59 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, 70 60 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, 71 61 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, 62 + ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 63 + ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 64 + ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, 65 + ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, 66 + ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, 67 + __ETHTOOL_LINK_MODE_MASK_NBITS, 68 + }; 69 + 70 + static const int xpcs_50gbaser_features[] = { 71 + ETHTOOL_LINK_MODE_MII_BIT, 72 + ETHTOOL_LINK_MODE_Pause_BIT, 73 + ETHTOOL_LINK_MODE_Asym_Pause_BIT, 74 + ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, 75 + ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, 76 + ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, 77 + ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, 78 + ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, 79 + __ETHTOOL_LINK_MODE_MASK_NBITS, 80 + }; 81 + 82 + static const int xpcs_50gbaser2_features[] = { 83 + ETHTOOL_LINK_MODE_MII_BIT, 84 + ETHTOOL_LINK_MODE_Pause_BIT, 85 + ETHTOOL_LINK_MODE_Asym_Pause_BIT, 86 + ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, 87 + ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, 88 + ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, 89 + __ETHTOOL_LINK_MODE_MASK_NBITS, 90 + }; 91 + 92 + static const int xpcs_100gbasep_features[] = { 93 + ETHTOOL_LINK_MODE_MII_BIT, 94 + ETHTOOL_LINK_MODE_Pause_BIT, 95 + ETHTOOL_LINK_MODE_Asym_Pause_BIT, 72 96 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, 73 97 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, 74 98 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, ··· 567 523 return speed; 568 524 } 569 525 570 - static void xpcs_resolve_pma(struct dw_xpcs *xpcs, 571 - struct phylink_link_state *state) 526 + static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs, 527 + struct phylink_link_state *state) 572 528 { 529 + int pcs_ctrl1; 530 + 531 + pcs_ctrl1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL1); 532 + if (pcs_ctrl1 < 0) 533 + return pcs_ctrl1; 534 + 535 + switch (pcs_ctrl1 & MDIO_CTRL1_SPEEDSEL) { 536 + case MDIO_PCS_CTRL1_SPEED25G: 537 + state->speed = SPEED_25000; 538 + break; 539 + case MDIO_PCS_CTRL1_SPEED50G: 540 + state->speed = SPEED_50000; 541 + break; 542 + case MDIO_PCS_CTRL1_SPEED100G: 543 + state->speed = SPEED_100000; 544 + break; 545 + default: 546 + state->speed = SPEED_UNKNOWN; 547 + break; 548 + } 549 + 550 + return 0; 551 + } 552 + 553 + static int xpcs_resolve_pma(struct dw_xpcs *xpcs, 554 + struct phylink_link_state *state) 555 + { 556 + int pmd_rxdet, err = 0; 557 + 558 + /* The Meta Platforms FBNIC PMD will go into a training state for 559 + * about 4 seconds when the link first comes up. During this time the 560 + * PCS link will bounce. To avoid reporting link up too soon we include 561 + * the PMD state provided by the driver. 562 + */ 563 + if (xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) { 564 + pmd_rxdet = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_PMA_RXDET); 565 + if (pmd_rxdet < 0) { 566 + state->link = false; 567 + return pmd_rxdet; 568 + } 569 + 570 + /* Verify Rx lanes are trained before reporting link up */ 571 + if (!(pmd_rxdet & MDIO_PMD_RXDET_GLOBAL)) { 572 + state->link = false; 573 + return 0; 574 + } 575 + } 576 + 573 577 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; 574 578 state->duplex = DUPLEX_FULL; 575 579 ··· 628 536 case PHY_INTERFACE_MODE_XLGMII: 629 537 state->speed = xpcs_get_max_xlgmii_speed(xpcs, state); 630 538 break; 539 + case PHY_INTERFACE_MODE_100GBASEP: 540 + case PHY_INTERFACE_MODE_LAUI: 541 + case PHY_INTERFACE_MODE_50GBASER: 542 + case PHY_INTERFACE_MODE_25GBASER: 543 + err = xpcs_c45_read_pcs_speed(xpcs, state); 544 + break; 631 545 default: 632 546 state->speed = SPEED_UNKNOWN; 633 547 break; 634 548 } 549 + 550 + return err; 635 551 } 636 552 637 553 static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, ··· 1045 945 1046 946 phylink_resolve_c73(state); 1047 947 } else { 1048 - xpcs_resolve_pma(xpcs, state); 948 + ret = xpcs_resolve_pma(xpcs, state); 1049 949 } 1050 950 1051 - return 0; 951 + return ret; 1052 952 } 1053 953 1054 954 static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, ··· 1384 1284 if (ret < 0) 1385 1285 return ret; 1386 1286 1387 - id = ret; 1287 + id = ret << 16; 1388 1288 1389 1289 ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2); 1390 1290 if (ret < 0) 1391 1291 return ret; 1392 1292 1393 - /* Note the inverted dword order and masked out Model/Revision numbers 1394 - * with respect to what is done with the PCS ID... 1293 + /* For now we only record the OUI for the PMAPMD, we may want to 1294 + * add the model number at some point in the future. 1395 1295 */ 1396 - ret = (ret >> 10) & 0x3F; 1397 - id |= ret << 16; 1296 + id |= ret & MDIO_DEVID2_OUI; 1398 1297 1399 1298 /* Set the PMA ID if it hasn't been pre-initialized */ 1400 1299 if (xpcs->info.pma == DW_XPCS_PMA_ID_NATIVE) ··· 1412 1313 .supported = xpcs_10gkr_features, 1413 1314 .an_mode = DW_AN_C73, 1414 1315 }, { 1316 + .interface = PHY_INTERFACE_MODE_25GBASER, 1317 + .supported = xpcs_25gbaser_features, 1318 + .an_mode = DW_AN_C73, 1319 + }, { 1415 1320 .interface = PHY_INTERFACE_MODE_XLGMII, 1416 1321 .supported = xpcs_xlgmii_features, 1322 + .an_mode = DW_AN_C73, 1323 + }, { 1324 + .interface = PHY_INTERFACE_MODE_50GBASER, 1325 + .supported = xpcs_50gbaser_features, 1326 + .an_mode = DW_AN_C73, 1327 + }, { 1328 + .interface = PHY_INTERFACE_MODE_LAUI, 1329 + .supported = xpcs_50gbaser2_features, 1330 + .an_mode = DW_AN_C73, 1331 + }, { 1332 + .interface = PHY_INTERFACE_MODE_100GBASEP, 1333 + .supported = xpcs_100gbasep_features, 1417 1334 .an_mode = DW_AN_C73, 1418 1335 }, { 1419 1336 .interface = PHY_INTERFACE_MODE_10GBASER, ··· 1610 1495 1611 1496 xpcs_get_interfaces(xpcs, xpcs->pcs.supported_interfaces); 1612 1497 1613 - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) 1498 + if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID || 1499 + xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) 1614 1500 xpcs->pcs.poll = false; 1615 1501 else 1616 1502 xpcs->need_reset = true;
+4 -4
drivers/net/phy/phy-c45.c
··· 148 148 ctrl2 |= MDIO_PMA_CTRL2_1000BT; 149 149 break; 150 150 case SPEED_2500: 151 - ctrl1 |= MDIO_CTRL1_SPEED2_5G; 151 + ctrl1 |= MDIO_PMA_CTRL1_SPEED2_5G; 152 152 /* Assume 2.5Gbase-T */ 153 153 ctrl2 |= MDIO_PMA_CTRL2_2_5GBT; 154 154 break; 155 155 case SPEED_5000: 156 - ctrl1 |= MDIO_CTRL1_SPEED5G; 156 + ctrl1 |= MDIO_PMA_CTRL1_SPEED5G; 157 157 /* Assume 5Gbase-T */ 158 158 ctrl2 |= MDIO_PMA_CTRL2_5GBT; 159 159 break; ··· 618 618 case MDIO_PMA_CTRL1_SPEED1000: 619 619 phydev->speed = SPEED_1000; 620 620 break; 621 - case MDIO_CTRL1_SPEED2_5G: 621 + case MDIO_PMA_CTRL1_SPEED2_5G: 622 622 phydev->speed = SPEED_2500; 623 623 break; 624 - case MDIO_CTRL1_SPEED5G: 624 + case MDIO_PMA_CTRL1_SPEED5G: 625 625 phydev->speed = SPEED_5000; 626 626 break; 627 627 case MDIO_CTRL1_SPEED10G:
+3 -1
include/linux/pcs/pcs-xpcs.h
··· 38 38 DW_XPCS_PMA_GEN4_6G_ID, 39 39 DW_XPCS_PMA_GEN5_10G_ID, 40 40 DW_XPCS_PMA_GEN5_12G_ID, 41 - WX_TXGBE_XPCS_PMA_10G_ID = 0x0018fc80, 41 + WX_TXGBE_XPCS_PMA_10G_ID = 0xfc806000, 42 + /* Meta Platforms OUI 88:25:08, model 0, revision 0 */ 43 + MP_FBNIC_XPCS_PMA_100G_ID = 0x46904000, 42 44 }; 43 45 44 46 struct dw_xpcs_info {
+21 -2
include/uapi/linux/mdio.h
··· 116 116 #define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) 117 117 /* 10PASS-TS/2BASE-TL */ 118 118 #define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04) 119 + /* Note: the MDIO_CTRL1_SPEED_XXX values for everything past 10PASS-TS/2BASE-TL 120 + * do not match between the PCS and PMA values. Any additions past this point 121 + * should be PMA or PCS specific. The following 2 defines are workarounds for 122 + * values added before this was caught. They should be considered deprecated. 123 + */ 124 + #define MDIO_CTRL1_SPEED2_5G MDIO_PMA_CTRL1_SPEED2_5G 125 + #define MDIO_CTRL1_SPEED5G MDIO_PMA_CTRL1_SPEED5G 126 + /* 100 Gb/s */ 127 + #define MDIO_PCS_CTRL1_SPEED100G (MDIO_CTRL1_SPEEDSELEXT | 0x10) 128 + /* 25 Gb/s */ 129 + #define MDIO_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) 130 + /* 50 Gb/s */ 131 + #define MDIO_PCS_CTRL1_SPEED50G (MDIO_CTRL1_SPEEDSELEXT | 0x18) 119 132 /* 2.5 Gb/s */ 120 - #define MDIO_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18) 133 + #define MDIO_PMA_CTRL1_SPEED2_5G (MDIO_CTRL1_SPEEDSELEXT | 0x18) 121 134 /* 5 Gb/s */ 122 - #define MDIO_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c) 135 + #define MDIO_PMA_CTRL1_SPEED5G (MDIO_CTRL1_SPEEDSELEXT | 0x1c) 136 + 123 137 124 138 /* Status register 1. */ 125 139 #define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */ ··· 146 132 #define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE 147 133 #define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */ 148 134 #define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */ 135 + 136 + /* Device Identifier 2 */ 137 + #define MDIO_DEVID2_OUI 0xfc00 /* OUI Portion of PHY ID */ 138 + #define MDIO_DEVID2_MODEL_NUM 0x03f0 /* Manufacturer's Model Number */ 139 + #define MDIO_DEVID2_REV_NUM 0x000f /* Revision Number */ 149 140 150 141 /* Speed register. */ 151 142 #define MDIO_SPEED_10G 0x0001 /* 10G capable */