drivers/net/dsa/microchip/ksz9477.c

Source file repositories/reference/linux-study-clean/drivers/net/dsa/microchip/ksz9477.c

File Facts

System
Linux kernel
Corpus path
drivers/net/dsa/microchip/ksz9477.c
Extension
.c
Size
55682 bytes
Lines
2128
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

if (reg == MMD_SR_MII_AUTO_NEG_STATUS) {
			int duplex, speed;

			if (val & SR_MII_STAT_LINK_UP) {
				speed = (val >> SR_MII_STAT_S) & SR_MII_STAT_M;
				if (speed == SR_MII_STAT_1000_MBPS)
					speed = SPEED_1000;
				else if (speed == SR_MII_STAT_100_MBPS)
					speed = SPEED_100;
				else
					speed = SPEED_10;

				if (val & SR_MII_STAT_FULL_DUPLEX)
					duplex = DUPLEX_FULL;
				else
					duplex = DUPLEX_HALF;

				if (!p->link || p->speed != speed ||
				    p->duplex != duplex) {
					u16 ctrl;

					p->link = true;
					p->speed = speed;
					p->duplex = duplex;
					port_sgmii_r(dev, port, mmd, MII_BMCR,
						     &ctrl);
					ctrl &= BMCR_ANENABLE;
					ctrl |= mii_bmcr_encode_fixed(speed,
								      duplex);
					port_sgmii_w(dev, port, mmd, MII_BMCR,
						     ctrl);
				}
			} else {
				p->link = false;
			}
		} else if (reg == MII_BMSR) {
			p->link = !!(val & BMSR_LSTATUS);
		}
	}

	return val;
}

static int ksz9477_pcs_write(struct mii_bus *bus, int phy, int mmd, int reg,
			     u16 val)
{
	struct ksz_device *dev = bus->priv;
	int port = ksz_get_sgmii_port(dev);

	if (mmd == MDIO_MMD_VEND2) {
		struct ksz_port *p = &dev->ports[port];

		if (reg == MMD_SR_MII_AUTO_NEG_CTRL) {
			u16 sgmii_mode = SR_MII_PCS_SGMII << SR_MII_PCS_MODE_S;

			/* Need these bits for 1000BASE-X mode to work with
			 * AN on.
			 */
			if (!(val & sgmii_mode))
				val |= SR_MII_SGMII_LINK_UP |
				       SR_MII_TX_CFG_PHY_MASTER;

			/* SGMII interrupt in the port cannot be masked, so
			 * make sure interrupt is not enabled as it is not
			 * handled.
			 */
			val &= ~SR_MII_AUTO_NEG_COMPLETE_INTR;
		} else if (reg == MII_BMCR) {
			/* The MII_ADVERTISE register needs to write once
			 * before doing auto-negotiation for the correct
			 * config_word to be sent out after reset.
			 */
			if ((val & BMCR_ANENABLE) && !p->sgmii_adv_write) {
				u16 adv;

				/* The SGMII port cannot disable flow control
				 * so it is better to just advertise symmetric
				 * pause.
				 */
				port_sgmii_r(dev, port, mmd, MII_ADVERTISE,
					     &adv);
				adv |= ADVERTISE_1000XPAUSE;
				adv &= ~ADVERTISE_1000XPSE_ASYM;
				port_sgmii_w(dev, port, mmd, MII_ADVERTISE,
					     adv);
				p->sgmii_adv_write = 1;
			} else if (val & BMCR_RESET) {
				p->sgmii_adv_write = 0;
			}
		} else if (reg == MII_ADVERTISE) {

Annotation

Implementation Notes