drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c
Extension
.c
Size
6358 bytes
Lines
244
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 (port->vid) {
			netdev_err(port->ndev,
				   "Port already has a native VLAN: %d\n",
				   port->vid);
			return -EBUSY;
		}
		port->vid = vid;
	}

	/* Make the port a member of the VLAN */
	set_bit(port->portno, sparx5->vlan_mask[vid]);
	ret = sparx5_vlant_set_mask(sparx5, vid);
	if (ret)
		return ret;

	/* Default ingress vlan classification */
	if (pvid)
		port->pvid = vid;

	sparx5_vlan_port_apply(sparx5, port);

	return 0;
}

int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
{
	struct sparx5 *sparx5 = port->sparx5;
	int ret;

	/* 8021q removes VID 0 on module unload for all interfaces
	 * with VLAN filtering feature. We need to keep it to receive
	 * untagged traffic.
	 */
	if (vid == 0)
		return 0;

	/* Stop the port from being a member of the vlan */
	clear_bit(port->portno, sparx5->vlan_mask[vid]);
	ret = sparx5_vlant_set_mask(sparx5, vid);
	if (ret)
		return ret;

	/* Ingress */
	if (port->pvid == vid)
		port->pvid = 0;

	/* Egress */
	if (port->vid == vid)
		port->vid = 0;

	sparx5_vlan_port_apply(sparx5, port);

	return 0;
}

void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
{
	struct sparx5 *sparx5 = port->sparx5;
	u32 val, mask;

	/* mask is spread across 3 registers x 32 bit */
	if (port->portno < 32) {
		mask = BIT(port->portno);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));
	} else if (port->portno < 64) {
		mask = BIT(port->portno - 32);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));
	} else if (port->portno < SPX5_PORTS) {
		mask = BIT(port->portno - 64);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));
	} else {
		netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
	}
}

void sparx5_pgid_clear(struct sparx5 *spx5, int pgid)
{
	spx5_wr(0, spx5, ANA_AC_PGID_CFG(pgid));
	if (is_sparx5(spx5)) {
		spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid));
		spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid));
	}
}

void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])
{
	portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));

Annotation

Implementation Notes