Commit c6142e19 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch '10g-qxgmii-for-aqr412c-felix-dsa-and-lynx-pcs-driver'

Vladimir Oltean says:

====================
10G-QXGMII for AQR412C, Felix DSA and Lynx PCS driver

Introduce the first user of the "10g-qxgmii" phy-mode, since its
introduction from commit 5dfabcdd ("dt-bindings: net:
ethernet-controller: add 10g-qxgmii mode").

The arch/arm64/boot/dts/freescale/fsl-ls1028a-qds-13bb.dtso already
exists upstream, but has phy-mode = "usxgmii", which comes from the fact
that the AQR412(C) PHY does not distinguish between the two modes.
Yet, the distinction is crucial for the upcoming SerDes driver for the
LS1028A platform.

The series is comprised of:
- preliminary patches to the Lynx PCS and Felix DSA driver which accept
  the phy-mode and treat it like "usxgmii"
- an ad-hoc whitelisting mechanism in the Aquantia PHY driver based on
  firmware version, which was agreed upon with Marvell, and which serves
  as "detection"
- in-band auto-negotiation capability reporting and configuration. This
  makes sure this feature is enabled in the PHY, because the Lynx PCS
  only works with USXGMII/10G-QXGMII in-band autoneg enabled.

Notably, it lacks a device tree update, which will come later, but
should not be strictly necessary. The expectation is for the Aquantia
PHY driver to pick up "10g-qxgmii" with existing device trees as well,
which it does, except for the slightly confusing "configuring for
inband/usxgmii link mode" initial message. This changes to "configuring
for inband/10g-qxgmii link mode" once phylink gets a chance to pick up
the phydev->interface in its pl->link_config.interface.

$ ip link set swp3 up
mscc_felix 0000:00:00.5 swp3: configuring for inband/usxgmii link mode
mscc_felix 0000:00:00.5 swp3: phylink_mac_config: mode=inband/usxgmii/none adv=0000000,00000000,00008000,0002606c pause=04
mscc_felix 0000:00:00.5 swp3: phylink_phy_change: phy interface 10g-qxgmii link 0
mscc_felix 0000:00:00.5 swp3: phylink_phy_change: phy interface 10g-qxgmii link 1
mscc_felix 0000:00:00.5 swp3: phylink_mac_config: mode=inband/10g-qxgmii/none adv=0000000,00000000,00008000,0002606c pause=00
mscc_felix 0000:00:00.5 swp3: Link is Up - 2.5Gbps/Full - flow control off

$ ip link set swp3 down
mscc_felix 0000:00:00.5 swp3: phylink_phy_change: phy interface 10g-qxgmii link 0
mscc_felix 0000:00:00.5 swp3: Link is Down

$ ip link set swp3 up
mscc_felix 0000:00:00.5 swp3: configuring for inband/10g-qxgmii link mode
mscc_felix 0000:00:00.5 swp3: phylink_mac_config: mode=inband/10g-qxgmii/none adv=0000000,00000000,00008000,0002606c pause=04
mscc_felix 0000:00:00.5 swp3: phylink_phy_change: phy interface 10g-qxgmii link 0
mscc_felix 0000:00:00.5 swp3: phylink_phy_change: phy interface 10g-qxgmii link 1
mscc_felix 0000:00:00.5 swp3: Link is Up - 2.5Gbps/Full - flow control off
====================

Link: https://patch.msgid.link/20250903130730.2836022-1-vladimir.oltean@nxp.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 377373d6 a76f26f7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1153,6 +1153,9 @@ static void felix_phylink_get_caps(struct dsa_switch *ds, int port,

	__set_bit(ocelot->ports[port]->phy_mode,
		  config->supported_interfaces);
	if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_USXGMII)
		__set_bit(PHY_INTERFACE_MODE_10G_QXGMII,
			  config->supported_interfaces);
}

static void felix_phylink_mac_config(struct phylink_config *config,
@@ -1359,6 +1362,7 @@ static const u32 felix_phy_match_table[PHY_INTERFACE_MODE_MAX] = {
	[PHY_INTERFACE_MODE_SGMII] = OCELOT_PORT_MODE_SGMII,
	[PHY_INTERFACE_MODE_QSGMII] = OCELOT_PORT_MODE_QSGMII,
	[PHY_INTERFACE_MODE_USXGMII] = OCELOT_PORT_MODE_USXGMII,
	[PHY_INTERFACE_MODE_10G_QXGMII] = OCELOT_PORT_MODE_10G_QXGMII,
	[PHY_INTERFACE_MODE_1000BASEX] = OCELOT_PORT_MODE_1000BASEX,
	[PHY_INTERFACE_MODE_2500BASEX] = OCELOT_PORT_MODE_2500BASEX,
};
+2 −1
Original line number Diff line number Diff line
@@ -12,8 +12,9 @@
#define OCELOT_PORT_MODE_SGMII		BIT(1)
#define OCELOT_PORT_MODE_QSGMII		BIT(2)
#define OCELOT_PORT_MODE_2500BASEX	BIT(3)
#define OCELOT_PORT_MODE_USXGMII	BIT(4)
#define OCELOT_PORT_MODE_USXGMII	BIT(4) /* compatibility */
#define OCELOT_PORT_MODE_1000BASEX	BIT(5)
#define OCELOT_PORT_MODE_10G_QXGMII	BIT(6)

struct device_node;

+2 −1
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@
					 OCELOT_PORT_MODE_QSGMII | \
					 OCELOT_PORT_MODE_1000BASEX | \
					 OCELOT_PORT_MODE_2500BASEX | \
					 OCELOT_PORT_MODE_USXGMII)
					 OCELOT_PORT_MODE_USXGMII | \
					 OCELOT_PORT_MODE_10G_QXGMII)

static const u32 vsc9959_port_modes[VSC9959_NUM_PORTS] = {
	VSC9959_PORT_MODE_SERDES,
+9 −2
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs,
		return LINK_INBAND_DISABLE;

	case PHY_INTERFACE_MODE_USXGMII:
	case PHY_INTERFACE_MODE_10G_QXGMII:
		return LINK_INBAND_ENABLE;

	default:
@@ -115,6 +116,7 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
		lynx_pcs_get_state_2500basex(lynx->mdio, state);
		break;
	case PHY_INTERFACE_MODE_USXGMII:
	case PHY_INTERFACE_MODE_10G_QXGMII:
		lynx_pcs_get_state_usxgmii(lynx->mdio, state);
		break;
	case PHY_INTERFACE_MODE_10GBASER:
@@ -170,6 +172,7 @@ static int lynx_pcs_config_giga(struct mdio_device *pcs,
}

static int lynx_pcs_config_usxgmii(struct mdio_device *pcs,
				   phy_interface_t interface,
				   const unsigned long *advertising,
				   unsigned int neg_mode)
{
@@ -177,7 +180,8 @@ static int lynx_pcs_config_usxgmii(struct mdio_device *pcs,
	int addr = pcs->addr;

	if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) {
		dev_err(&pcs->dev, "USXGMII only supports in-band AN for now\n");
		dev_err(&pcs->dev, "%s only supports in-band AN for now\n",
			phy_modes(interface));
		return -EOPNOTSUPP;
	}

@@ -208,7 +212,8 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
		}
		break;
	case PHY_INTERFACE_MODE_USXGMII:
		return lynx_pcs_config_usxgmii(lynx->mdio, advertising,
	case PHY_INTERFACE_MODE_10G_QXGMII:
		return lynx_pcs_config_usxgmii(lynx->mdio, ifmode, advertising,
					       neg_mode);
	case PHY_INTERFACE_MODE_10GBASER:
		/* Nothing to do here for 10GBASER */
@@ -317,6 +322,7 @@ static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
		lynx_pcs_link_up_2500basex(lynx->mdio, neg_mode, speed, duplex);
		break;
	case PHY_INTERFACE_MODE_USXGMII:
	case PHY_INTERFACE_MODE_10G_QXGMII:
		/* At the moment, only in-band AN is supported for USXGMII
		 * so nothing to do in link_up
		 */
@@ -341,6 +347,7 @@ static const phy_interface_t lynx_interfaces[] = {
	PHY_INTERFACE_MODE_2500BASEX,
	PHY_INTERFACE_MODE_10GBASER,
	PHY_INTERFACE_MODE_USXGMII,
	PHY_INTERFACE_MODE_10G_QXGMII,
};

static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio)
+25 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#define VEND1_GLOBAL_CFG_SERDES_MODE_SGMII	3
#define VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII	4
#define VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G	6
#define VEND1_GLOBAL_CFG_AUTONEG_ENA		BIT(3)
#define VEND1_GLOBAL_CFG_RATE_ADAPT		GENMASK(8, 7)
#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE	0
#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX		1
@@ -152,6 +153,28 @@

#define AQR_MAX_LEDS				3

/* Custom driver definitions for constructing a single variable out of
 * aggregate firmware build information. These do not represent hardware
 * fields.
 */
#define AQR_FW_FINGERPRINT_MAJOR		GENMASK_ULL(63, 56)
#define AQR_FW_FINGERPRINT_MINOR		GENMASK_ULL(55, 48)
#define AQR_FW_FINGERPRINT_BUILD_ID		GENMASK_ULL(47, 40)
#define AQR_FW_FINGERPRINT_PROV_ID		GENMASK_ULL(39, 32)
#define AQR_FW_FINGERPRINT_MISC_ID		GENMASK_ULL(31, 16)
#define AQR_FW_FINGERPRINT_MISC_VER		GENMASK_ULL(15, 0)
#define AQR_FW_FINGERPRINT(major, minor, build_id, prov_id, misc_id, misc_ver) \
	(FIELD_PREP(AQR_FW_FINGERPRINT_MAJOR, major) | \
	 FIELD_PREP(AQR_FW_FINGERPRINT_MINOR, minor) | \
	 FIELD_PREP(AQR_FW_FINGERPRINT_BUILD_ID, build_id) | \
	 FIELD_PREP(AQR_FW_FINGERPRINT_PROV_ID, prov_id) | \
	 FIELD_PREP(AQR_FW_FINGERPRINT_MISC_ID, misc_id) | \
	 FIELD_PREP(AQR_FW_FINGERPRINT_MISC_VER, misc_ver))

/* 10G-QXGMII firmware for NXP SPF-30841 riser board (AQR412C) */
#define AQR_G3_V4_3_C_AQR_NXP_SPF_30841_MUSX_ID40019_VER1198 \
	AQR_FW_FINGERPRINT(4, 3, 0xc, 1, 40019, 1198)

struct aqr107_hw_stat {
	const char *name;
	int reg;
@@ -202,6 +225,7 @@ struct aqr_global_syscfg {

struct aqr107_priv {
	u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
	u64 fingerprint;
	unsigned long leds_active_low;
	unsigned long leds_active_high;
	bool wait_on_global_cfg;
@@ -215,6 +239,7 @@ static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
#endif

int aqr_firmware_load(struct phy_device *phydev);
int aqr_firmware_read_fingerprint(struct phy_device *phydev);

int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
			  unsigned long *delay_on,
Loading