162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <net/pkt_cls.h>
462306a36Sopenharmony_ci#include <net/pkt_sched.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "lan966x_main.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistatic LIST_HEAD(lan966x_tc_block_cb_list);
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port,
1162306a36Sopenharmony_ci					 struct tc_mqprio_qopt_offload *mqprio)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	u8 num_tc = mqprio->qopt.num_tc;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	return num_tc ? lan966x_mqprio_add(port, num_tc) :
1862306a36Sopenharmony_ci			lan966x_mqprio_del(port);
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port,
2262306a36Sopenharmony_ci					 struct tc_taprio_qopt_offload *taprio)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	switch (taprio->cmd) {
2562306a36Sopenharmony_ci	case TAPRIO_CMD_REPLACE:
2662306a36Sopenharmony_ci		return lan966x_taprio_add(port, taprio);
2762306a36Sopenharmony_ci	case TAPRIO_CMD_DESTROY:
2862306a36Sopenharmony_ci		return lan966x_taprio_del(port);
2962306a36Sopenharmony_ci	default:
3062306a36Sopenharmony_ci		return -EOPNOTSUPP;
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port,
3562306a36Sopenharmony_ci				      struct tc_tbf_qopt_offload *qopt)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	switch (qopt->command) {
3862306a36Sopenharmony_ci	case TC_TBF_REPLACE:
3962306a36Sopenharmony_ci		return lan966x_tbf_add(port, qopt);
4062306a36Sopenharmony_ci	case TC_TBF_DESTROY:
4162306a36Sopenharmony_ci		return lan966x_tbf_del(port, qopt);
4262306a36Sopenharmony_ci	default:
4362306a36Sopenharmony_ci		return -EOPNOTSUPP;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return -EOPNOTSUPP;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int lan966x_tc_setup_qdisc_cbs(struct lan966x_port *port,
5062306a36Sopenharmony_ci				      struct tc_cbs_qopt_offload *qopt)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return qopt->enable ? lan966x_cbs_add(port, qopt) :
5362306a36Sopenharmony_ci			      lan966x_cbs_del(port, qopt);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port,
5762306a36Sopenharmony_ci				      struct tc_ets_qopt_offload *qopt)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	switch (qopt->command) {
6062306a36Sopenharmony_ci	case TC_ETS_REPLACE:
6162306a36Sopenharmony_ci		return lan966x_ets_add(port, qopt);
6262306a36Sopenharmony_ci	case TC_ETS_DESTROY:
6362306a36Sopenharmony_ci		return lan966x_ets_del(port, qopt);
6462306a36Sopenharmony_ci	default:
6562306a36Sopenharmony_ci		return -EOPNOTSUPP;
6662306a36Sopenharmony_ci	};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return -EOPNOTSUPP;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
7262306a36Sopenharmony_ci			       void *cb_priv, bool ingress)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct lan966x_port *port = cb_priv;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	switch (type) {
7762306a36Sopenharmony_ci	case TC_SETUP_CLSMATCHALL:
7862306a36Sopenharmony_ci		return lan966x_tc_matchall(port, type_data, ingress);
7962306a36Sopenharmony_ci	case TC_SETUP_CLSFLOWER:
8062306a36Sopenharmony_ci		return lan966x_tc_flower(port, type_data, ingress);
8162306a36Sopenharmony_ci	default:
8262306a36Sopenharmony_ci		return -EOPNOTSUPP;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int lan966x_tc_block_cb_ingress(enum tc_setup_type type,
8762306a36Sopenharmony_ci				       void *type_data, void *cb_priv)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return lan966x_tc_block_cb(type, type_data, cb_priv, true);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int lan966x_tc_block_cb_egress(enum tc_setup_type type,
9362306a36Sopenharmony_ci				      void *type_data, void *cb_priv)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	return lan966x_tc_block_cb(type, type_data, cb_priv, false);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int lan966x_tc_setup_block(struct lan966x_port *port,
9962306a36Sopenharmony_ci				  struct flow_block_offload *f)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	flow_setup_cb_t *cb;
10262306a36Sopenharmony_ci	bool ingress;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
10562306a36Sopenharmony_ci		cb = lan966x_tc_block_cb_ingress;
10662306a36Sopenharmony_ci		port->tc.ingress_shared_block = f->block_shared;
10762306a36Sopenharmony_ci		ingress = true;
10862306a36Sopenharmony_ci	} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
10962306a36Sopenharmony_ci		cb = lan966x_tc_block_cb_egress;
11062306a36Sopenharmony_ci		ingress = false;
11162306a36Sopenharmony_ci	} else {
11262306a36Sopenharmony_ci		return -EOPNOTSUPP;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list,
11662306a36Sopenharmony_ci					  cb, port, port, ingress);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ciint lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
12062306a36Sopenharmony_ci		     void *type_data)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct lan966x_port *port = netdev_priv(dev);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	switch (type) {
12562306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
12662306a36Sopenharmony_ci		return lan966x_tc_setup_qdisc_mqprio(port, type_data);
12762306a36Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO:
12862306a36Sopenharmony_ci		return lan966x_tc_setup_qdisc_taprio(port, type_data);
12962306a36Sopenharmony_ci	case TC_SETUP_QDISC_TBF:
13062306a36Sopenharmony_ci		return lan966x_tc_setup_qdisc_tbf(port, type_data);
13162306a36Sopenharmony_ci	case TC_SETUP_QDISC_CBS:
13262306a36Sopenharmony_ci		return lan966x_tc_setup_qdisc_cbs(port, type_data);
13362306a36Sopenharmony_ci	case TC_SETUP_QDISC_ETS:
13462306a36Sopenharmony_ci		return lan966x_tc_setup_qdisc_ets(port, type_data);
13562306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
13662306a36Sopenharmony_ci		return lan966x_tc_setup_block(port, type_data);
13762306a36Sopenharmony_ci	default:
13862306a36Sopenharmony_ci		return -EOPNOTSUPP;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return 0;
14262306a36Sopenharmony_ci}
143