brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · e27824e Raw
492 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2007-2011 Solarflare Communications Inc.5 */6 7#include <linux/delay.h>8#include <linux/rtnetlink.h>9#include <linux/seq_file.h>10#include <linux/slab.h>11#include "efx.h"12#include "mdio_10g.h"13#include "nic.h"14#include "phy.h"15#include "workarounds.h"16 17/* We expect these MMDs to be in the package. */18#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD	| \19				 MDIO_DEVS_PCS		| \20				 MDIO_DEVS_PHYXS	| \21				 MDIO_DEVS_AN)22 23#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\24			   (1 << LOOPBACK_PCS) |	\25			   (1 << LOOPBACK_PMAPMD) |	\26			   (1 << LOOPBACK_PHYXS_WS))27 28/* We complain if we fail to see the link partner as 10G capable this many29 * times in a row (must be > 1 as sampling the autoneg. registers is racy)30 */31#define MAX_BAD_LP_TRIES	(5)32 33/* Extended control register */34#define PMA_PMD_XCONTROL_REG	4915235#define PMA_PMD_EXT_GMII_EN_LBN	136#define PMA_PMD_EXT_GMII_EN_WIDTH 137#define PMA_PMD_EXT_CLK_OUT_LBN	238#define PMA_PMD_EXT_CLK_OUT_WIDTH 139#define PMA_PMD_LNPGA_POWERDOWN_LBN 840#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 141#define PMA_PMD_EXT_CLK312_WIDTH 142#define PMA_PMD_EXT_LPOWER_LBN  1243#define PMA_PMD_EXT_LPOWER_WIDTH 144#define PMA_PMD_EXT_ROBUST_LBN	1445#define PMA_PMD_EXT_ROBUST_WIDTH 146#define PMA_PMD_EXT_SSR_LBN	1547#define PMA_PMD_EXT_SSR_WIDTH	148 49/* extended status register */50#define PMA_PMD_XSTATUS_REG	4915351#define PMA_PMD_XSTAT_MDIX_LBN	1452#define PMA_PMD_XSTAT_FLP_LBN   (12)53 54/* LED control register */55#define PMA_PMD_LED_CTRL_REG	4915956#define PMA_PMA_LED_ACTIVITY_LBN	(3)57 58/* LED function override register */59#define PMA_PMD_LED_OVERR_REG	4916160/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/61#define PMA_PMD_LED_LINK_LBN	(0)62#define PMA_PMD_LED_SPEED_LBN	(2)63#define PMA_PMD_LED_TX_LBN	(4)64#define PMA_PMD_LED_RX_LBN	(6)65/* Override settings */66#define	PMA_PMD_LED_AUTO	(0)	/* H/W control */67#define	PMA_PMD_LED_ON		(1)68#define	PMA_PMD_LED_OFF		(2)69#define PMA_PMD_LED_FLASH	(3)70#define PMA_PMD_LED_MASK	371/* All LEDs under hardware control */72/* Green and Amber under hardware control, Red off */73#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)74 75#define PMA_PMD_SPEED_ENABLE_REG 4919276#define PMA_PMD_100TX_ADV_LBN    177#define PMA_PMD_100TX_ADV_WIDTH  178#define PMA_PMD_1000T_ADV_LBN    279#define PMA_PMD_1000T_ADV_WIDTH  180#define PMA_PMD_10000T_ADV_LBN   381#define PMA_PMD_10000T_ADV_WIDTH 182#define PMA_PMD_SPEED_LBN        483#define PMA_PMD_SPEED_WIDTH      484 85/* Misc register defines */86#define PCS_CLOCK_CTRL_REG	5529787#define PLL312_RST_N_LBN 288 89#define PCS_SOFT_RST2_REG	5530290#define SERDES_RST_N_LBN 1391#define XGXS_RST_N_LBN 1292 93#define	PCS_TEST_SELECT_REG	55303	/* PRM 10.5.8 */94#define	CLK312_EN_LBN 395 96/* PHYXS registers */97#define PHYXS_XCONTROL_REG	4915298#define PHYXS_RESET_LBN		1599#define PHYXS_RESET_WIDTH	1100 101#define PHYXS_TEST1         (49162)102#define LOOPBACK_NEAR_LBN   (8)103#define LOOPBACK_NEAR_WIDTH (1)104 105/* Boot status register */106#define PCS_BOOT_STATUS_REG		53248107#define PCS_BOOT_FATAL_ERROR_LBN	0108#define PCS_BOOT_PROGRESS_LBN		1109#define PCS_BOOT_PROGRESS_WIDTH		2110#define PCS_BOOT_PROGRESS_INIT		0111#define PCS_BOOT_PROGRESS_WAIT_MDIO	1112#define PCS_BOOT_PROGRESS_CHECKSUM	2113#define PCS_BOOT_PROGRESS_JUMP		3114#define PCS_BOOT_DOWNLOAD_WAIT_LBN	3115#define PCS_BOOT_CODE_STARTED_LBN	4116 117/* 100M/1G PHY registers */118#define GPHY_XCONTROL_REG	49152119#define GPHY_ISOLATE_LBN	10120#define GPHY_ISOLATE_WIDTH	1121#define GPHY_DUPLEX_LBN		8122#define GPHY_DUPLEX_WIDTH	1123#define GPHY_LOOPBACK_NEAR_LBN	14124#define GPHY_LOOPBACK_NEAR_WIDTH 1125 126#define C22EXT_STATUS_REG       49153127#define C22EXT_STATUS_LINK_LBN  2128#define C22EXT_STATUS_LINK_WIDTH 1129 130#define C22EXT_MSTSLV_CTRL			49161131#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN	8132#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN	9133 134#define C22EXT_MSTSLV_STATUS			49162135#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN	10136#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN	11137 138/* Time to wait between powering down the LNPGA and turning off the power139 * rails */140#define LNPGA_PDOWN_WAIT	(HZ / 5)141 142struct tenxpress_phy_data {143	enum ef4_loopback_mode loopback_mode;144	enum ef4_phy_mode phy_mode;145	int bad_lp_tries;146};147 148static int tenxpress_init(struct ef4_nic *efx)149{150	/* Enable 312.5 MHz clock */151	ef4_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,152		       1 << CLK312_EN_LBN);153 154	/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */155	ef4_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,156			  1 << PMA_PMA_LED_ACTIVITY_LBN, true);157	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,158		       SFX7101_PMA_PMD_LED_DEFAULT);159 160	return 0;161}162 163static int tenxpress_phy_probe(struct ef4_nic *efx)164{165	struct tenxpress_phy_data *phy_data;166 167	/* Allocate phy private storage */168	phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);169	if (!phy_data)170		return -ENOMEM;171	efx->phy_data = phy_data;172	phy_data->phy_mode = efx->phy_mode;173 174	efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;175	efx->mdio.mode_support = MDIO_SUPPORTS_C45;176 177	efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;178 179	efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |180				 ADVERTISED_10000baseT_Full);181 182	return 0;183}184 185static int tenxpress_phy_init(struct ef4_nic *efx)186{187	int rc;188 189	falcon_board(efx)->type->init_phy(efx);190 191	if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {192		rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);193		if (rc < 0)194			return rc;195 196		rc = ef4_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS);197		if (rc < 0)198			return rc;199	}200 201	rc = tenxpress_init(efx);202	if (rc < 0)203		return rc;204 205	/* Reinitialise flow control settings */206	ef4_link_set_wanted_fc(efx, efx->wanted_fc);207	ef4_mdio_an_reconfigure(efx);208 209	schedule_timeout_uninterruptible(HZ / 5); /* 200ms */210 211	/* Let XGXS and SerDes out of reset */212	falcon_reset_xaui(efx);213 214	return 0;215}216 217/* Perform a "special software reset" on the PHY. The caller is218 * responsible for saving and restoring the PHY hardware registers219 * properly, and masking/unmasking LASI */220static int tenxpress_special_reset(struct ef4_nic *efx)221{222	int rc, reg;223 224	/* The XGMAC clock is driven from the SFX7101 312MHz clock, so225	 * a special software reset can glitch the XGMAC sufficiently for stats226	 * requests to fail. */227	falcon_stop_nic_stats(efx);228 229	/* Initiate reset */230	reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);231	reg |= (1 << PMA_PMD_EXT_SSR_LBN);232	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);233 234	mdelay(200);235 236	/* Wait for the blocks to come out of reset */237	rc = ef4_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);238	if (rc < 0)239		goto out;240 241	/* Try and reconfigure the device */242	rc = tenxpress_init(efx);243	if (rc < 0)244		goto out;245 246	/* Wait for the XGXS state machine to churn */247	mdelay(10);248out:249	falcon_start_nic_stats(efx);250	return rc;251}252 253static void sfx7101_check_bad_lp(struct ef4_nic *efx, bool link_ok)254{255	struct tenxpress_phy_data *pd = efx->phy_data;256	bool bad_lp;257	int reg;258 259	if (link_ok) {260		bad_lp = false;261	} else {262		/* Check that AN has started but not completed. */263		reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);264		if (!(reg & MDIO_AN_STAT1_LPABLE))265			return; /* LP status is unknown */266		bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);267		if (bad_lp)268			pd->bad_lp_tries++;269	}270 271	/* Nothing to do if all is well and was previously so. */272	if (!pd->bad_lp_tries)273		return;274 275	/* Use the RX (red) LED as an error indicator once we've seen AN276	 * failure several times in a row, and also log a message. */277	if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {278		reg = ef4_mdio_read(efx, MDIO_MMD_PMAPMD,279				    PMA_PMD_LED_OVERR_REG);280		reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);281		if (!bad_lp) {282			reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;283		} else {284			reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;285			netif_err(efx, link, efx->net_dev,286				  "appears to be plugged into a port"287				  " that is not 10GBASE-T capable. The PHY"288				  " supports 10GBASE-T ONLY, so no link can"289				  " be established\n");290		}291		ef4_mdio_write(efx, MDIO_MMD_PMAPMD,292			       PMA_PMD_LED_OVERR_REG, reg);293		pd->bad_lp_tries = bad_lp;294	}295}296 297static bool sfx7101_link_ok(struct ef4_nic *efx)298{299	return ef4_mdio_links_ok(efx,300				 MDIO_DEVS_PMAPMD |301				 MDIO_DEVS_PCS |302				 MDIO_DEVS_PHYXS);303}304 305static void tenxpress_ext_loopback(struct ef4_nic *efx)306{307	ef4_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,308			  1 << LOOPBACK_NEAR_LBN,309			  efx->loopback_mode == LOOPBACK_PHYXS);310}311 312static void tenxpress_low_power(struct ef4_nic *efx)313{314	ef4_mdio_set_mmds_lpower(315		efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),316		TENXPRESS_REQUIRED_DEVS);317}318 319static int tenxpress_phy_reconfigure(struct ef4_nic *efx)320{321	struct tenxpress_phy_data *phy_data = efx->phy_data;322	bool phy_mode_change, loop_reset;323 324	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {325		phy_data->phy_mode = efx->phy_mode;326		return 0;327	}328 329	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&330			   phy_data->phy_mode != PHY_MODE_NORMAL);331	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||332		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));333 334	if (loop_reset || phy_mode_change) {335		tenxpress_special_reset(efx);336		falcon_reset_xaui(efx);337	}338 339	tenxpress_low_power(efx);340	ef4_mdio_transmit_disable(efx);341	ef4_mdio_phy_reconfigure(efx);342	tenxpress_ext_loopback(efx);343	ef4_mdio_an_reconfigure(efx);344 345	phy_data->loopback_mode = efx->loopback_mode;346	phy_data->phy_mode = efx->phy_mode;347 348	return 0;349}350 351/* Poll for link state changes */352static bool tenxpress_phy_poll(struct ef4_nic *efx)353{354	struct ef4_link_state old_state = efx->link_state;355 356	efx->link_state.up = sfx7101_link_ok(efx);357	efx->link_state.speed = 10000;358	efx->link_state.fd = true;359	efx->link_state.fc = ef4_mdio_get_pause(efx);360 361	sfx7101_check_bad_lp(efx, efx->link_state.up);362 363	return !ef4_link_state_equal(&efx->link_state, &old_state);364}365 366static void sfx7101_phy_fini(struct ef4_nic *efx)367{368	int reg;369 370	/* Power down the LNPGA */371	reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);372	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);373 374	/* Waiting here ensures that the board fini, which can turn375	 * off the power to the PHY, won't get run until the LNPGA376	 * powerdown has been given long enough to complete. */377	schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */378}379 380static void tenxpress_phy_remove(struct ef4_nic *efx)381{382	kfree(efx->phy_data);383	efx->phy_data = NULL;384}385 386 387/* Override the RX, TX and link LEDs */388void tenxpress_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)389{390	int reg;391 392	switch (mode) {393	case EF4_LED_OFF:394		reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) |395			(PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) |396			(PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN);397		break;398	case EF4_LED_ON:399		reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) |400			(PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) |401			(PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN);402		break;403	default:404		reg = SFX7101_PMA_PMD_LED_DEFAULT;405		break;406	}407 408	ef4_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);409}410 411static const char *const sfx7101_test_names[] = {412	"bist"413};414 415static const char *sfx7101_test_name(struct ef4_nic *efx, unsigned int index)416{417	if (index < ARRAY_SIZE(sfx7101_test_names))418		return sfx7101_test_names[index];419	return NULL;420}421 422static int423sfx7101_run_tests(struct ef4_nic *efx, int *results, unsigned flags)424{425	int rc;426 427	if (!(flags & ETH_TEST_FL_OFFLINE))428		return 0;429 430	/* BIST is automatically run after a special software reset */431	rc = tenxpress_special_reset(efx);432	results[0] = rc ? -1 : 1;433 434	ef4_mdio_an_reconfigure(efx);435 436	return rc;437}438 439static void440tenxpress_get_link_ksettings(struct ef4_nic *efx,441			     struct ethtool_link_ksettings *cmd)442{443	u32 adv = 0, lpa = 0;444	int reg;445 446	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);447	if (reg & MDIO_AN_10GBT_CTRL_ADV10G)448		adv |= ADVERTISED_10000baseT_Full;449	reg = ef4_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);450	if (reg & MDIO_AN_10GBT_STAT_LP10G)451		lpa |= ADVERTISED_10000baseT_Full;452 453	mdio45_ethtool_ksettings_get_npage(&efx->mdio, cmd, adv, lpa);454 455	/* In loopback, the PHY automatically brings up the correct interface,456	 * but doesn't advertise the correct speed. So override it */457	if (LOOPBACK_EXTERNAL(efx))458		cmd->base.speed = SPEED_10000;459}460 461static int462tenxpress_set_link_ksettings(struct ef4_nic *efx,463			     const struct ethtool_link_ksettings *cmd)464{465	if (!cmd->base.autoneg)466		return -EINVAL;467 468	return ef4_mdio_set_link_ksettings(efx, cmd);469}470 471static void sfx7101_set_npage_adv(struct ef4_nic *efx, u32 advertising)472{473	ef4_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,474			  MDIO_AN_10GBT_CTRL_ADV10G,475			  advertising & ADVERTISED_10000baseT_Full);476}477 478const struct ef4_phy_operations falcon_sfx7101_phy_ops = {479	.probe		  = tenxpress_phy_probe,480	.init             = tenxpress_phy_init,481	.reconfigure      = tenxpress_phy_reconfigure,482	.poll             = tenxpress_phy_poll,483	.fini             = sfx7101_phy_fini,484	.remove		  = tenxpress_phy_remove,485	.get_link_ksettings = tenxpress_get_link_ksettings,486	.set_link_ksettings = tenxpress_set_link_ksettings,487	.set_npage_adv    = sfx7101_set_npage_adv,488	.test_alive	  = ef4_mdio_test_alive,489	.test_name	  = sfx7101_test_name,490	.run_tests	  = sfx7101_run_tests,491};492