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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
Extension
.c
Size
14362 bytes
Lines
536
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 sparx5_mact_entry {
	struct list_head list;
	unsigned char mac[ETH_ALEN];
	u32 flags;
#define MAC_ENT_ALIVE	BIT(0)
#define MAC_ENT_MOVED	BIT(1)
#define MAC_ENT_LOCK	BIT(2)
	u16 vid;
	u16 port;
};

static int sparx5_mact_get_status(struct sparx5 *sparx5)
{
	return spx5_rd(sparx5, LRN_COMMON_ACCESS_CTRL);
}

static int sparx5_mact_wait_for_completion(struct sparx5 *sparx5)
{
	u32 val;

	return readx_poll_timeout(sparx5_mact_get_status,
		sparx5, val,
		LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_GET(val) == 0,
		TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
}

static void sparx5_mact_select(struct sparx5 *sparx5,
			       const unsigned char mac[ETH_ALEN],
			       u16 vid)
{
	u32 macl = 0, mach = 0;

	/* Set the MAC address to handle and the vlan associated in a format
	 * understood by the hardware.
	 */
	mach |= vid    << 16;
	mach |= mac[0] << 8;
	mach |= mac[1] << 0;
	macl |= mac[2] << 24;
	macl |= mac[3] << 16;
	macl |= mac[4] << 8;
	macl |= mac[5] << 0;

	spx5_wr(mach, sparx5, LRN_MAC_ACCESS_CFG_0);
	spx5_wr(macl, sparx5, LRN_MAC_ACCESS_CFG_1);
}

int sparx5_mact_learn(struct sparx5 *sparx5, int pgid,
		      const unsigned char mac[ETH_ALEN], u16 vid)
{
	const struct sparx5_consts *consts = sparx5->data->consts;
	int addr, type, ret;

	if (pgid < consts->n_ports) {
		type = MAC_ENTRY_ADDR_TYPE_UPSID_PN;
		addr = pgid % 32;
		addr += (pgid / 32) << 5; /* Add upsid */
	} else {
		type = MAC_ENTRY_ADDR_TYPE_MC_IDX;
		addr = pgid - consts->n_ports;
	}

	mutex_lock(&sparx5->lock);

	sparx5_mact_select(sparx5, mac, vid);

	/* MAC entry properties */
	spx5_wr(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_SET(addr) |
		LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_TYPE_SET(type) |
		LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_VLD_SET(1) |
		LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_LOCKED_SET(1),
		sparx5, LRN_MAC_ACCESS_CFG_2);
	spx5_wr(0, sparx5, LRN_MAC_ACCESS_CFG_3);

	/*  Insert/learn new entry */
	spx5_wr(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(MAC_CMD_LEARN) |
		LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_SET(1),
		sparx5, LRN_COMMON_ACCESS_CTRL);

	ret = sparx5_mact_wait_for_completion(sparx5);

	mutex_unlock(&sparx5->lock);

	return ret;
}

int sparx5_mc_unsync(struct net_device *dev, const unsigned char *addr)
{
	struct sparx5_port *port = netdev_priv(dev);
	struct sparx5 *sparx5 = port->sparx5;

Annotation

Implementation Notes