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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c
Extension
.c
Size
6338 bytes
Lines
241
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

sparx5_mirror_has_monitor(sparx5, i, mport->portno)) {
			*idx = i;
			return 0;
		}
	}

	/* Return free mirror */
	for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) {
		if (sparx5_mirror_is_empty(sparx5, i)) {
			*idx = i;
			return 0;
		}
	}

	return -ENOENT;
}

int sparx5_mirror_add(struct sparx5_mall_entry *entry)
{
	u32 mirror_idx, dir = sparx5_mirror_to_dir(entry->ingress);
	struct sparx5_port *sport, *mport;
	struct sparx5 *sparx5;
	int err;

	/* Source port */
	sport = entry->port;
	/* monitor port */
	mport = entry->mirror.port;
	sparx5 = sport->sparx5;

	if (sport->portno == mport->portno)
		return -EINVAL;

	err = sparx5_mirror_get(sport, mport, dir, &mirror_idx);
	if (err)
		return err;

	if (sparx5_mirror_contains(sparx5, mirror_idx, sport->portno))
		return -EEXIST;

	/* Add port to mirror */
	sparx5_mirror_port_add(sparx5, mirror_idx, sport->portno);

	/* Set direction of mirror */
	sparx5_mirror_dir_set(sparx5, mirror_idx, dir);

	/* Set monitor port for mirror */
	sparx5_mirror_monitor_set(sparx5, mirror_idx, mport->portno);

	entry->mirror.idx = mirror_idx;

	return 0;
}

void sparx5_mirror_del(struct sparx5_mall_entry *entry)
{
	struct sparx5_port *port = entry->port;
	struct sparx5 *sparx5 = port->sparx5;
	u32 mirror_idx = entry->mirror.idx;

	sparx5_mirror_port_del(sparx5, mirror_idx, port->portno);
	if (!sparx5_mirror_is_empty(sparx5, mirror_idx))
		return;

	sparx5_mirror_dir_set(sparx5, mirror_idx, SPX5_MIRROR_DISABLED);

	sparx5_mirror_monitor_set(sparx5,
				  mirror_idx,
				  sparx5->data->consts->n_ports);
}

void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
			 struct flow_stats *fstats)
{
	struct sparx5_port *port = entry->port;
	struct rtnl_link_stats64 new_stats;
	struct flow_stats *old_stats;

	old_stats = &entry->port->mirror_stats;
	sparx5_get_stats64(port->ndev, &new_stats);

	if (entry->ingress) {
		flow_stats_update(fstats,
				  new_stats.rx_bytes - old_stats->bytes,
				  new_stats.rx_packets - old_stats->pkts,
				  new_stats.rx_dropped - old_stats->drops,
				  old_stats->lastused,
				  FLOW_ACTION_HW_STATS_IMMEDIATE);

		old_stats->bytes = new_stats.rx_bytes;

Annotation

Implementation Notes