drivers/net/ethernet/ti/am65-cpsw-qos.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/ti/am65-cpsw-qos.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/ti/am65-cpsw-qos.c
Extension
.c
Size
36441 bytes
Lines
1344
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 (mqprio->max_rate[tc]) {
			rate_mbps = mqprio->max_rate[tc] - mqprio->min_rate[tc];
			rate_mbps = TO_MBPS(rate_mbps);
			rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps,
							       common->bus_freq);
		}

		writel(rate_mbps,
		       port->port_base + AM65_CPSW_PN_REG_PRI_EIR(prio));
	}
}

static int am65_cpsw_mqprio_verify_shaper(struct am65_cpsw_port *port,
					  struct tc_mqprio_qopt_offload *mqprio)
{
	struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
	struct netlink_ext_ack *extack = mqprio->extack;
	u64 min_rate_total = 0, max_rate_total = 0;
	u32 min_rate_msk = 0, max_rate_msk = 0;
	bool has_min_rate, has_max_rate;
	int num_tc, i;

	if (!(mqprio->flags & TC_MQPRIO_F_SHAPER))
		return 0;

	if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE)
		return 0;

	has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
	has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);

	if (!has_min_rate && has_max_rate) {
		NL_SET_ERR_MSG_MOD(extack, "min_rate is required with max_rate");
		return -EOPNOTSUPP;
	}

	if (!has_min_rate)
		return 0;

	num_tc = mqprio->qopt.num_tc;

	for (i = num_tc - 1; i >= 0; i--) {
		u32 ch_msk;

		if (mqprio->min_rate[i])
			min_rate_msk |= BIT(i);
		min_rate_total +=  mqprio->min_rate[i];

		if (has_max_rate) {
			if (mqprio->max_rate[i])
				max_rate_msk |= BIT(i);
			max_rate_total +=  mqprio->max_rate[i];

			if (!mqprio->min_rate[i] && mqprio->max_rate[i]) {
				NL_SET_ERR_MSG_FMT_MOD(extack,
						       "TX tc%d rate max>0 but min=0",
						       i);
				return -EINVAL;
			}

			if (mqprio->max_rate[i] &&
			    mqprio->max_rate[i] < mqprio->min_rate[i]) {
				NL_SET_ERR_MSG_FMT_MOD(extack,
						       "TX tc%d rate min(%llu)>max(%llu)",
						       i, mqprio->min_rate[i],
						       mqprio->max_rate[i]);
				return -EINVAL;
			}
		}

		ch_msk = GENMASK(num_tc - 1, i);
		if ((min_rate_msk & BIT(i)) && (min_rate_msk ^ ch_msk)) {
			NL_SET_ERR_MSG_FMT_MOD(extack,
					       "Min rate must be set sequentially hi->lo tx_rate_msk%x",
					       min_rate_msk);
			return -EINVAL;
		}

		if ((max_rate_msk & BIT(i)) && (max_rate_msk ^ ch_msk)) {
			NL_SET_ERR_MSG_FMT_MOD(extack,
					       "Max rate must be set sequentially hi->lo tx_rate_msk%x",
					       max_rate_msk);
			return -EINVAL;
		}
	}

	min_rate_total = TO_MBPS(min_rate_total);
	max_rate_total = TO_MBPS(max_rate_total);

	p_mqprio->shaper_en = true;

Annotation

Implementation Notes