drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/amd/xgbe/xgbe-phy-v1.c
Extension
.c
Size
20131 bytes
Lines
745
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xgbe_phy_data {
	/* 1000/10000 vs 2500/10000 indicator */
	unsigned int speed_set;

	/* SerDes UEFI configurable settings.
	 *   Switching between modes/speeds requires new values for some
	 *   SerDes settings.  The values can be supplied as device
	 *   properties in array format.  The first array entry is for
	 *   1GbE, second for 2.5GbE and third for 10GbE
	 */
	u32 blwc[XGBE_SPEEDS];
	u32 cdr_rate[XGBE_SPEEDS];
	u32 pq_skew[XGBE_SPEEDS];
	u32 tx_amp[XGBE_SPEEDS];
	u32 dfe_tap_cfg[XGBE_SPEEDS];
	u32 dfe_tap_ena[XGBE_SPEEDS];
};

static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
{
		XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1);
}

static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
{
		XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0);
}

static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
{
	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
	struct xgbe_phy_data *phy_data = pdata->phy_data;
	enum xgbe_mode mode;
	unsigned int ad_reg, lp_reg;

	XGBE_SET_LP_ADV(lks, Autoneg);
	XGBE_SET_LP_ADV(lks, Backplane);

	/* Compare Advertisement and Link Partner register 1 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
	if (lp_reg & 0x400)
		XGBE_SET_LP_ADV(lks, Pause);
	if (lp_reg & 0x800)
		XGBE_SET_LP_ADV(lks, Asym_Pause);

	if (pdata->phy.pause_autoneg) {
		/* Set flow control based on auto-negotiation result */
		pdata->phy.tx_pause = 0;
		pdata->phy.rx_pause = 0;

		if (ad_reg & lp_reg & 0x400) {
			pdata->phy.tx_pause = 1;
			pdata->phy.rx_pause = 1;
		} else if (ad_reg & lp_reg & 0x800) {
			if (ad_reg & 0x400)
				pdata->phy.rx_pause = 1;
			else if (lp_reg & 0x400)
				pdata->phy.tx_pause = 1;
		}
	}

	/* Compare Advertisement and Link Partner register 2 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
	if (lp_reg & 0x80)
		XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
	if (lp_reg & 0x20) {
		if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000)
			XGBE_SET_LP_ADV(lks, 2500baseX_Full);
		else
			XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
	}

	ad_reg &= lp_reg;
	if (ad_reg & 0x80) {
		mode = XGBE_MODE_KR;
	} else if (ad_reg & 0x20) {
		if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000)
			mode = XGBE_MODE_KX_2500;
		else
			mode = XGBE_MODE_KX_1000;
	} else {
		mode = XGBE_MODE_UNKNOWN;
	}

	/* Compare Advertisement and Link Partner register 3 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
	if (lp_reg & 0xc000)

Annotation

Implementation Notes