18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/****************************************************************************
38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards
48c2ecf20Sopenharmony_ci * Copyright 2007-2011 Solarflare Communications Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
98c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include "efx.h"
128c2ecf20Sopenharmony_ci#include "mdio_10g.h"
138c2ecf20Sopenharmony_ci#include "nic.h"
148c2ecf20Sopenharmony_ci#include "phy.h"
158c2ecf20Sopenharmony_ci#include "workarounds.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* We expect these MMDs to be in the package. */
188c2ecf20Sopenharmony_ci#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD	| \
198c2ecf20Sopenharmony_ci				 MDIO_DEVS_PCS		| \
208c2ecf20Sopenharmony_ci				 MDIO_DEVS_PHYXS	| \
218c2ecf20Sopenharmony_ci				 MDIO_DEVS_AN)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
248c2ecf20Sopenharmony_ci			   (1 << LOOPBACK_PCS) |	\
258c2ecf20Sopenharmony_ci			   (1 << LOOPBACK_PMAPMD) |	\
268c2ecf20Sopenharmony_ci			   (1 << LOOPBACK_PHYXS_WS))
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* We complain if we fail to see the link partner as 10G capable this many
298c2ecf20Sopenharmony_ci * times in a row (must be > 1 as sampling the autoneg. registers is racy)
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci#define MAX_BAD_LP_TRIES	(5)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* Extended control register */
348c2ecf20Sopenharmony_ci#define PMA_PMD_XCONTROL_REG	49152
358c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_GMII_EN_LBN	1
368c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_GMII_EN_WIDTH 1
378c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_CLK_OUT_LBN	2
388c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_CLK_OUT_WIDTH 1
398c2ecf20Sopenharmony_ci#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
408c2ecf20Sopenharmony_ci#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
418c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_CLK312_WIDTH 1
428c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_LPOWER_LBN  12
438c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_LPOWER_WIDTH 1
448c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_ROBUST_LBN	14
458c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_ROBUST_WIDTH 1
468c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_SSR_LBN	15
478c2ecf20Sopenharmony_ci#define PMA_PMD_EXT_SSR_WIDTH	1
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* extended status register */
508c2ecf20Sopenharmony_ci#define PMA_PMD_XSTATUS_REG	49153
518c2ecf20Sopenharmony_ci#define PMA_PMD_XSTAT_MDIX_LBN	14
528c2ecf20Sopenharmony_ci#define PMA_PMD_XSTAT_FLP_LBN   (12)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* LED control register */
558c2ecf20Sopenharmony_ci#define PMA_PMD_LED_CTRL_REG	49159
568c2ecf20Sopenharmony_ci#define PMA_PMA_LED_ACTIVITY_LBN	(3)
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* LED function override register */
598c2ecf20Sopenharmony_ci#define PMA_PMD_LED_OVERR_REG	49161
608c2ecf20Sopenharmony_ci/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
618c2ecf20Sopenharmony_ci#define PMA_PMD_LED_LINK_LBN	(0)
628c2ecf20Sopenharmony_ci#define PMA_PMD_LED_SPEED_LBN	(2)
638c2ecf20Sopenharmony_ci#define PMA_PMD_LED_TX_LBN	(4)
648c2ecf20Sopenharmony_ci#define PMA_PMD_LED_RX_LBN	(6)
658c2ecf20Sopenharmony_ci/* Override settings */
668c2ecf20Sopenharmony_ci#define	PMA_PMD_LED_AUTO	(0)	/* H/W control */
678c2ecf20Sopenharmony_ci#define	PMA_PMD_LED_ON		(1)
688c2ecf20Sopenharmony_ci#define	PMA_PMD_LED_OFF		(2)
698c2ecf20Sopenharmony_ci#define PMA_PMD_LED_FLASH	(3)
708c2ecf20Sopenharmony_ci#define PMA_PMD_LED_MASK	3
718c2ecf20Sopenharmony_ci/* All LEDs under hardware control */
728c2ecf20Sopenharmony_ci/* Green and Amber under hardware control, Red off */
738c2ecf20Sopenharmony_ci#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define PMA_PMD_SPEED_ENABLE_REG 49192
768c2ecf20Sopenharmony_ci#define PMA_PMD_100TX_ADV_LBN    1
778c2ecf20Sopenharmony_ci#define PMA_PMD_100TX_ADV_WIDTH  1
788c2ecf20Sopenharmony_ci#define PMA_PMD_1000T_ADV_LBN    2
798c2ecf20Sopenharmony_ci#define PMA_PMD_1000T_ADV_WIDTH  1
808c2ecf20Sopenharmony_ci#define PMA_PMD_10000T_ADV_LBN   3
818c2ecf20Sopenharmony_ci#define PMA_PMD_10000T_ADV_WIDTH 1
828c2ecf20Sopenharmony_ci#define PMA_PMD_SPEED_LBN        4
838c2ecf20Sopenharmony_ci#define PMA_PMD_SPEED_WIDTH      4
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* Misc register defines */
868c2ecf20Sopenharmony_ci#define PCS_CLOCK_CTRL_REG	55297
878c2ecf20Sopenharmony_ci#define PLL312_RST_N_LBN 2
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define PCS_SOFT_RST2_REG	55302
908c2ecf20Sopenharmony_ci#define SERDES_RST_N_LBN 13
918c2ecf20Sopenharmony_ci#define XGXS_RST_N_LBN 12
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define	PCS_TEST_SELECT_REG	55303	/* PRM 10.5.8 */
948c2ecf20Sopenharmony_ci#define	CLK312_EN_LBN 3
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* PHYXS registers */
978c2ecf20Sopenharmony_ci#define PHYXS_XCONTROL_REG	49152
988c2ecf20Sopenharmony_ci#define PHYXS_RESET_LBN		15
998c2ecf20Sopenharmony_ci#define PHYXS_RESET_WIDTH	1
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define PHYXS_TEST1         (49162)
1028c2ecf20Sopenharmony_ci#define LOOPBACK_NEAR_LBN   (8)
1038c2ecf20Sopenharmony_ci#define LOOPBACK_NEAR_WIDTH (1)
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Boot status register */
1068c2ecf20Sopenharmony_ci#define PCS_BOOT_STATUS_REG		53248
1078c2ecf20Sopenharmony_ci#define PCS_BOOT_FATAL_ERROR_LBN	0
1088c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_LBN		1
1098c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_WIDTH		2
1108c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_INIT		0
1118c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_WAIT_MDIO	1
1128c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_CHECKSUM	2
1138c2ecf20Sopenharmony_ci#define PCS_BOOT_PROGRESS_JUMP		3
1148c2ecf20Sopenharmony_ci#define PCS_BOOT_DOWNLOAD_WAIT_LBN	3
1158c2ecf20Sopenharmony_ci#define PCS_BOOT_CODE_STARTED_LBN	4
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* 100M/1G PHY registers */
1188c2ecf20Sopenharmony_ci#define GPHY_XCONTROL_REG	49152
1198c2ecf20Sopenharmony_ci#define GPHY_ISOLATE_LBN	10
1208c2ecf20Sopenharmony_ci#define GPHY_ISOLATE_WIDTH	1
1218c2ecf20Sopenharmony_ci#define GPHY_DUPLEX_LBN		8
1228c2ecf20Sopenharmony_ci#define GPHY_DUPLEX_WIDTH	1
1238c2ecf20Sopenharmony_ci#define GPHY_LOOPBACK_NEAR_LBN	14
1248c2ecf20Sopenharmony_ci#define GPHY_LOOPBACK_NEAR_WIDTH 1
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci#define C22EXT_STATUS_REG       49153
1278c2ecf20Sopenharmony_ci#define C22EXT_STATUS_LINK_LBN  2
1288c2ecf20Sopenharmony_ci#define C22EXT_STATUS_LINK_WIDTH 1
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_CTRL			49161
1318c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN	8
1328c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN	9
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_STATUS			49162
1358c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN	10
1368c2ecf20Sopenharmony_ci#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN	11
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* Time to wait between powering down the LNPGA and turning off the power
1398c2ecf20Sopenharmony_ci * rails */
1408c2ecf20Sopenharmony_ci#define LNPGA_PDOWN_WAIT	(HZ / 5)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistruct tenxpress_phy_data {
1438c2ecf20Sopenharmony_ci	enum ef4_loopback_mode loopback_mode;
1448c2ecf20Sopenharmony_ci	enum ef4_phy_mode phy_mode;
1458c2ecf20Sopenharmony_ci	int bad_lp_tries;
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int tenxpress_init(struct ef4_nic *efx)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	/* Enable 312.5 MHz clock */
1518c2ecf20Sopenharmony_ci	ef4_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
1528c2ecf20Sopenharmony_ci		       1 << CLK312_EN_LBN);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
1558c2ecf20Sopenharmony_ci	ef4_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
1568c2ecf20Sopenharmony_ci			  1 << PMA_PMA_LED_ACTIVITY_LBN, true);
1578c2ecf20Sopenharmony_ci	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
1588c2ecf20Sopenharmony_ci		       SFX7101_PMA_PMD_LED_DEFAULT);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int tenxpress_phy_probe(struct ef4_nic *efx)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct tenxpress_phy_data *phy_data;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* Allocate phy private storage */
1688c2ecf20Sopenharmony_ci	phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
1698c2ecf20Sopenharmony_ci	if (!phy_data)
1708c2ecf20Sopenharmony_ci		return -ENOMEM;
1718c2ecf20Sopenharmony_ci	efx->phy_data = phy_data;
1728c2ecf20Sopenharmony_ci	phy_data->phy_mode = efx->phy_mode;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
1758c2ecf20Sopenharmony_ci	efx->mdio.mode_support = MDIO_SUPPORTS_C45;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
1808c2ecf20Sopenharmony_ci				 ADVERTISED_10000baseT_Full);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return 0;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int tenxpress_phy_init(struct ef4_nic *efx)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	int rc;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	falcon_board(efx)->type->init_phy(efx);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
1928c2ecf20Sopenharmony_ci		rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
1938c2ecf20Sopenharmony_ci		if (rc < 0)
1948c2ecf20Sopenharmony_ci			return rc;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		rc = ef4_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS);
1978c2ecf20Sopenharmony_ci		if (rc < 0)
1988c2ecf20Sopenharmony_ci			return rc;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	rc = tenxpress_init(efx);
2028c2ecf20Sopenharmony_ci	if (rc < 0)
2038c2ecf20Sopenharmony_ci		return rc;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* Reinitialise flow control settings */
2068c2ecf20Sopenharmony_ci	ef4_link_set_wanted_fc(efx, efx->wanted_fc);
2078c2ecf20Sopenharmony_ci	ef4_mdio_an_reconfigure(efx);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Let XGXS and SerDes out of reset */
2128c2ecf20Sopenharmony_ci	falcon_reset_xaui(efx);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/* Perform a "special software reset" on the PHY. The caller is
2188c2ecf20Sopenharmony_ci * responsible for saving and restoring the PHY hardware registers
2198c2ecf20Sopenharmony_ci * properly, and masking/unmasking LASI */
2208c2ecf20Sopenharmony_cistatic int tenxpress_special_reset(struct ef4_nic *efx)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int rc, reg;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* The XGMAC clock is driven from the SFX7101 312MHz clock, so
2258c2ecf20Sopenharmony_ci	 * a special software reset can glitch the XGMAC sufficiently for stats
2268c2ecf20Sopenharmony_ci	 * requests to fail. */
2278c2ecf20Sopenharmony_ci	falcon_stop_nic_stats(efx);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* Initiate reset */
2308c2ecf20Sopenharmony_ci	reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
2318c2ecf20Sopenharmony_ci	reg |= (1 << PMA_PMD_EXT_SSR_LBN);
2328c2ecf20Sopenharmony_ci	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	mdelay(200);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* Wait for the blocks to come out of reset */
2378c2ecf20Sopenharmony_ci	rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
2388c2ecf20Sopenharmony_ci	if (rc < 0)
2398c2ecf20Sopenharmony_ci		goto out;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Try and reconfigure the device */
2428c2ecf20Sopenharmony_ci	rc = tenxpress_init(efx);
2438c2ecf20Sopenharmony_ci	if (rc < 0)
2448c2ecf20Sopenharmony_ci		goto out;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* Wait for the XGXS state machine to churn */
2478c2ecf20Sopenharmony_ci	mdelay(10);
2488c2ecf20Sopenharmony_ciout:
2498c2ecf20Sopenharmony_ci	falcon_start_nic_stats(efx);
2508c2ecf20Sopenharmony_ci	return rc;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic void sfx7101_check_bad_lp(struct ef4_nic *efx, bool link_ok)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct tenxpress_phy_data *pd = efx->phy_data;
2568c2ecf20Sopenharmony_ci	bool bad_lp;
2578c2ecf20Sopenharmony_ci	int reg;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (link_ok) {
2608c2ecf20Sopenharmony_ci		bad_lp = false;
2618c2ecf20Sopenharmony_ci	} else {
2628c2ecf20Sopenharmony_ci		/* Check that AN has started but not completed. */
2638c2ecf20Sopenharmony_ci		reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
2648c2ecf20Sopenharmony_ci		if (!(reg & MDIO_AN_STAT1_LPABLE))
2658c2ecf20Sopenharmony_ci			return; /* LP status is unknown */
2668c2ecf20Sopenharmony_ci		bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);
2678c2ecf20Sopenharmony_ci		if (bad_lp)
2688c2ecf20Sopenharmony_ci			pd->bad_lp_tries++;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* Nothing to do if all is well and was previously so. */
2728c2ecf20Sopenharmony_ci	if (!pd->bad_lp_tries)
2738c2ecf20Sopenharmony_ci		return;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* Use the RX (red) LED as an error indicator once we've seen AN
2768c2ecf20Sopenharmony_ci	 * failure several times in a row, and also log a message. */
2778c2ecf20Sopenharmony_ci	if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
2788c2ecf20Sopenharmony_ci		reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD,
2798c2ecf20Sopenharmony_ci				    PMA_PMD_LED_OVERR_REG);
2808c2ecf20Sopenharmony_ci		reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
2818c2ecf20Sopenharmony_ci		if (!bad_lp) {
2828c2ecf20Sopenharmony_ci			reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
2838c2ecf20Sopenharmony_ci		} else {
2848c2ecf20Sopenharmony_ci			reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
2858c2ecf20Sopenharmony_ci			netif_err(efx, link, efx->net_dev,
2868c2ecf20Sopenharmony_ci				  "appears to be plugged into a port"
2878c2ecf20Sopenharmony_ci				  " that is not 10GBASE-T capable. The PHY"
2888c2ecf20Sopenharmony_ci				  " supports 10GBASE-T ONLY, so no link can"
2898c2ecf20Sopenharmony_ci				  " be established\n");
2908c2ecf20Sopenharmony_ci		}
2918c2ecf20Sopenharmony_ci		ef4_mdio_write(efx, MDIO_MMD_PMAPMD,
2928c2ecf20Sopenharmony_ci			       PMA_PMD_LED_OVERR_REG, reg);
2938c2ecf20Sopenharmony_ci		pd->bad_lp_tries = bad_lp;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic bool sfx7101_link_ok(struct ef4_nic *efx)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	return ef4_mdio_links_ok(efx,
3008c2ecf20Sopenharmony_ci				 MDIO_DEVS_PMAPMD |
3018c2ecf20Sopenharmony_ci				 MDIO_DEVS_PCS |
3028c2ecf20Sopenharmony_ci				 MDIO_DEVS_PHYXS);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void tenxpress_ext_loopback(struct ef4_nic *efx)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
3088c2ecf20Sopenharmony_ci			  1 << LOOPBACK_NEAR_LBN,
3098c2ecf20Sopenharmony_ci			  efx->loopback_mode == LOOPBACK_PHYXS);
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic void tenxpress_low_power(struct ef4_nic *efx)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	ef4_mdio_set_mmds_lpower(
3158c2ecf20Sopenharmony_ci		efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
3168c2ecf20Sopenharmony_ci		TENXPRESS_REQUIRED_DEVS);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int tenxpress_phy_reconfigure(struct ef4_nic *efx)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct tenxpress_phy_data *phy_data = efx->phy_data;
3228c2ecf20Sopenharmony_ci	bool phy_mode_change, loop_reset;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
3258c2ecf20Sopenharmony_ci		phy_data->phy_mode = efx->phy_mode;
3268c2ecf20Sopenharmony_ci		return 0;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
3308c2ecf20Sopenharmony_ci			   phy_data->phy_mode != PHY_MODE_NORMAL);
3318c2ecf20Sopenharmony_ci	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||
3328c2ecf20Sopenharmony_ci		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (loop_reset || phy_mode_change) {
3358c2ecf20Sopenharmony_ci		tenxpress_special_reset(efx);
3368c2ecf20Sopenharmony_ci		falcon_reset_xaui(efx);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	tenxpress_low_power(efx);
3408c2ecf20Sopenharmony_ci	ef4_mdio_transmit_disable(efx);
3418c2ecf20Sopenharmony_ci	ef4_mdio_phy_reconfigure(efx);
3428c2ecf20Sopenharmony_ci	tenxpress_ext_loopback(efx);
3438c2ecf20Sopenharmony_ci	ef4_mdio_an_reconfigure(efx);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	phy_data->loopback_mode = efx->loopback_mode;
3468c2ecf20Sopenharmony_ci	phy_data->phy_mode = efx->phy_mode;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return 0;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/* Poll for link state changes */
3528c2ecf20Sopenharmony_cistatic bool tenxpress_phy_poll(struct ef4_nic *efx)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct ef4_link_state old_state = efx->link_state;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	efx->link_state.up = sfx7101_link_ok(efx);
3578c2ecf20Sopenharmony_ci	efx->link_state.speed = 10000;
3588c2ecf20Sopenharmony_ci	efx->link_state.fd = true;
3598c2ecf20Sopenharmony_ci	efx->link_state.fc = ef4_mdio_get_pause(efx);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	sfx7101_check_bad_lp(efx, efx->link_state.up);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return !ef4_link_state_equal(&efx->link_state, &old_state);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic void sfx7101_phy_fini(struct ef4_nic *efx)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	int reg;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Power down the LNPGA */
3718c2ecf20Sopenharmony_ci	reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
3728c2ecf20Sopenharmony_ci	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* Waiting here ensures that the board fini, which can turn
3758c2ecf20Sopenharmony_ci	 * off the power to the PHY, won't get run until the LNPGA
3768c2ecf20Sopenharmony_ci	 * powerdown has been given long enough to complete. */
3778c2ecf20Sopenharmony_ci	schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void tenxpress_phy_remove(struct ef4_nic *efx)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	kfree(efx->phy_data);
3838c2ecf20Sopenharmony_ci	efx->phy_data = NULL;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/* Override the RX, TX and link LEDs */
3888c2ecf20Sopenharmony_civoid tenxpress_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	int reg;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	switch (mode) {
3938c2ecf20Sopenharmony_ci	case EF4_LED_OFF:
3948c2ecf20Sopenharmony_ci		reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) |
3958c2ecf20Sopenharmony_ci			(PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) |
3968c2ecf20Sopenharmony_ci			(PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN);
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci	case EF4_LED_ON:
3998c2ecf20Sopenharmony_ci		reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) |
4008c2ecf20Sopenharmony_ci			(PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) |
4018c2ecf20Sopenharmony_ci			(PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN);
4028c2ecf20Sopenharmony_ci		break;
4038c2ecf20Sopenharmony_ci	default:
4048c2ecf20Sopenharmony_ci		reg = SFX7101_PMA_PMD_LED_DEFAULT;
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic const char *const sfx7101_test_names[] = {
4128c2ecf20Sopenharmony_ci	"bist"
4138c2ecf20Sopenharmony_ci};
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic const char *sfx7101_test_name(struct ef4_nic *efx, unsigned int index)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	if (index < ARRAY_SIZE(sfx7101_test_names))
4188c2ecf20Sopenharmony_ci		return sfx7101_test_names[index];
4198c2ecf20Sopenharmony_ci	return NULL;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int
4238c2ecf20Sopenharmony_cisfx7101_run_tests(struct ef4_nic *efx, int *results, unsigned flags)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	int rc;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (!(flags & ETH_TEST_FL_OFFLINE))
4288c2ecf20Sopenharmony_ci		return 0;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* BIST is automatically run after a special software reset */
4318c2ecf20Sopenharmony_ci	rc = tenxpress_special_reset(efx);
4328c2ecf20Sopenharmony_ci	results[0] = rc ? -1 : 1;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	ef4_mdio_an_reconfigure(efx);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return rc;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic void
4408c2ecf20Sopenharmony_citenxpress_get_link_ksettings(struct ef4_nic *efx,
4418c2ecf20Sopenharmony_ci			     struct ethtool_link_ksettings *cmd)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	u32 adv = 0, lpa = 0;
4448c2ecf20Sopenharmony_ci	int reg;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
4478c2ecf20Sopenharmony_ci	if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
4488c2ecf20Sopenharmony_ci		adv |= ADVERTISED_10000baseT_Full;
4498c2ecf20Sopenharmony_ci	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
4508c2ecf20Sopenharmony_ci	if (reg & MDIO_AN_10GBT_STAT_LP10G)
4518c2ecf20Sopenharmony_ci		lpa |= ADVERTISED_10000baseT_Full;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	mdio45_ethtool_ksettings_get_npage(&efx->mdio, cmd, adv, lpa);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* In loopback, the PHY automatically brings up the correct interface,
4568c2ecf20Sopenharmony_ci	 * but doesn't advertise the correct speed. So override it */
4578c2ecf20Sopenharmony_ci	if (LOOPBACK_EXTERNAL(efx))
4588c2ecf20Sopenharmony_ci		cmd->base.speed = SPEED_10000;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic int
4628c2ecf20Sopenharmony_citenxpress_set_link_ksettings(struct ef4_nic *efx,
4638c2ecf20Sopenharmony_ci			     const struct ethtool_link_ksettings *cmd)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	if (!cmd->base.autoneg)
4668c2ecf20Sopenharmony_ci		return -EINVAL;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return ef4_mdio_set_link_ksettings(efx, cmd);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic void sfx7101_set_npage_adv(struct ef4_nic *efx, u32 advertising)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	ef4_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
4748c2ecf20Sopenharmony_ci			  MDIO_AN_10GBT_CTRL_ADV10G,
4758c2ecf20Sopenharmony_ci			  advertising & ADVERTISED_10000baseT_Full);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ciconst struct ef4_phy_operations falcon_sfx7101_phy_ops = {
4798c2ecf20Sopenharmony_ci	.probe		  = tenxpress_phy_probe,
4808c2ecf20Sopenharmony_ci	.init             = tenxpress_phy_init,
4818c2ecf20Sopenharmony_ci	.reconfigure      = tenxpress_phy_reconfigure,
4828c2ecf20Sopenharmony_ci	.poll             = tenxpress_phy_poll,
4838c2ecf20Sopenharmony_ci	.fini             = sfx7101_phy_fini,
4848c2ecf20Sopenharmony_ci	.remove		  = tenxpress_phy_remove,
4858c2ecf20Sopenharmony_ci	.get_link_ksettings = tenxpress_get_link_ksettings,
4868c2ecf20Sopenharmony_ci	.set_link_ksettings = tenxpress_set_link_ksettings,
4878c2ecf20Sopenharmony_ci	.set_npage_adv    = sfx7101_set_npage_adv,
4888c2ecf20Sopenharmony_ci	.test_alive	  = ef4_mdio_test_alive,
4898c2ecf20Sopenharmony_ci	.test_name	  = sfx7101_test_name,
4908c2ecf20Sopenharmony_ci	.run_tests	  = sfx7101_run_tests,
4918c2ecf20Sopenharmony_ci};
492