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

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
Extension
.c
Size
16518 bytes
Lines
624
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_get_internal_port(sparx5, SPX5_PORT_CPU_1)) {
			/* Equals 1.25G */
			return SPX5_CAL_SPEED_2G5;
		} else if (portno ==
			   sparx5_get_internal_port(sparx5, SPX5_PORT_VD0)) {
			/* IPMC only idle BW */
			return SPX5_CAL_SPEED_NONE;
		} else if (portno ==
			   sparx5_get_internal_port(sparx5, SPX5_PORT_VD1)) {
			/* OAM only idle BW */
			return SPX5_CAL_SPEED_NONE;
		} else if (portno ==
			   sparx5_get_internal_port(sparx5, SPX5_PORT_VD2)) {
			/* IPinIP gets only idle BW */
			return SPX5_CAL_SPEED_NONE;
		}
		/* not in port map */
		return SPX5_CAL_SPEED_NONE;
	}
	/* Front ports - may be used */
	port = sparx5->ports[portno];
	if (!port)
		return SPX5_CAL_SPEED_NONE;
	return sparx5_bandwidth_to_calendar(port->conf.bandwidth);
}

/* Auto configure the QSYS calendar based on port configuration */
static int sparx5_config_auto_calendar(struct sparx5 *sparx5)
{
	const struct sparx5_consts *consts = sparx5->data->consts;
	u32 cal[7], value, idx, portno;
	u32 max_core_bw;
	u32 total_bw = 0, used_port_bw = 0;
	int err = 0;
	enum sparx5_cal_bw spd;

	memset(cal, 0, sizeof(cal));

	max_core_bw = sparx5_clk_to_bandwidth(sparx5->coreclock);
	if (max_core_bw == 0) {
		dev_err(sparx5->dev, "Core clock not supported");
		return -EINVAL;
	}

	/* Setup the calendar with the bandwidth to each port */
	for (portno = 0; portno < consts->n_ports_all; portno++) {
		u64 reg, offset, this_bw;

		spd = sparx5_get_port_cal_speed(sparx5, portno);
		if (spd == SPX5_CAL_SPEED_NONE)
			continue;

		this_bw = sparx5_cal_speed_to_value(spd);
		if (portno < consts->n_ports)
			used_port_bw += this_bw;
		else
			/* Internal ports are granted half the value */
			this_bw = this_bw / 2;
		total_bw += this_bw;
		reg = portno;
		offset = do_div(reg, SPX5_PORTS_PER_CALREG);
		cal[reg] |= spd << (offset * SPX5_CALBITS_PER_PORT);
	}

	if (used_port_bw > sparx5_target_bandwidth(sparx5)) {
		dev_err(sparx5->dev,
			"Port BW %u above target BW %u\n",
			used_port_bw, sparx5_target_bandwidth(sparx5));
		return -EINVAL;
	}

	if (total_bw > max_core_bw) {
		dev_err(sparx5->dev,
			"Total BW %u above switch core BW %u\n",
			total_bw, max_core_bw);
		return -EINVAL;
	}

	/* Halt the calendar while changing it */
	if (is_sparx5(sparx5))
		spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10),
			 QSYS_CAL_CTRL_CAL_MODE,
			 sparx5, QSYS_CAL_CTRL);

	/* Assign port bandwidth to auto calendar */
	for (idx = 0; idx < consts->n_auto_cals; idx++)
		spx5_wr(cal[idx], sparx5, QSYS_CAL_AUTO(idx));

	/* Increase grant rate of all ports to account for
	 * core clock ppm deviations

Annotation

Implementation Notes