summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c
blob: cf0cc7562d0423fc09f284eb8e52168dd635eb7b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: GPL-2.0+

#include <net/pkt_cls.h>
#include <net/pkt_sched.h>

#include "lan966x_main.h"

static LIST_HEAD(lan966x_tc_block_cb_list);

static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port,
					 struct tc_mqprio_qopt_offload *mqprio)
{
	u8 num_tc = mqprio->qopt.num_tc;

	mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;

	return num_tc ? lan966x_mqprio_add(port, num_tc) :
			lan966x_mqprio_del(port);
}

static int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port,
					 struct tc_taprio_qopt_offload *taprio)
{
	return taprio->enable ? lan966x_taprio_add(port, taprio) :
				lan966x_taprio_del(port);
}

static int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port,
				      struct tc_tbf_qopt_offload *qopt)
{
	switch (qopt->command) {
	case TC_TBF_REPLACE:
		return lan966x_tbf_add(port, qopt);
	case TC_TBF_DESTROY:
		return lan966x_tbf_del(port, qopt);
	default:
		return -EOPNOTSUPP;
	}

	return -EOPNOTSUPP;
}

static int lan966x_tc_setup_qdisc_cbs(struct lan966x_port *port,
				      struct tc_cbs_qopt_offload *qopt)
{
	return qopt->enable ? lan966x_cbs_add(port, qopt) :
			      lan966x_cbs_del(port, qopt);
}

static int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port,
				      struct tc_ets_qopt_offload *qopt)
{
	switch (qopt->command) {
	case TC_ETS_REPLACE:
		return lan966x_ets_add(port, qopt);
	case TC_ETS_DESTROY:
		return lan966x_ets_del(port, qopt);
	default:
		return -EOPNOTSUPP;
	};

	return -EOPNOTSUPP;
}

static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
			       void *cb_priv, bool ingress)
{
	struct lan966x_port *port = cb_priv;

	switch (type) {
	case TC_SETUP_CLSMATCHALL:
		return lan966x_tc_matchall(port, type_data, ingress);
	case TC_SETUP_CLSFLOWER:
		return lan966x_tc_flower(port, type_data, ingress);
	default:
		return -EOPNOTSUPP;
	}
}

static int lan966x_tc_block_cb_ingress(enum tc_setup_type type,
				       void *type_data, void *cb_priv)
{
	return lan966x_tc_block_cb(type, type_data, cb_priv, true);
}

static int lan966x_tc_block_cb_egress(enum tc_setup_type type,
				      void *type_data, void *cb_priv)
{
	return lan966x_tc_block_cb(type, type_data, cb_priv, false);
}

static int lan966x_tc_setup_block(struct lan966x_port *port,
				  struct flow_block_offload *f)
{
	flow_setup_cb_t *cb;
	bool ingress;

	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
		cb = lan966x_tc_block_cb_ingress;
		port->tc.ingress_shared_block = f->block_shared;
		ingress = true;
	} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
		cb = lan966x_tc_block_cb_egress;
		ingress = false;
	} else {
		return -EOPNOTSUPP;
	}

	return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list,
					  cb, port, port, ingress);
}

int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
		     void *type_data)
{
	struct lan966x_port *port = netdev_priv(dev);

	switch (type) {
	case TC_SETUP_QDISC_MQPRIO:
		return lan966x_tc_setup_qdisc_mqprio(port, type_data);
	case TC_SETUP_QDISC_TAPRIO:
		return lan966x_tc_setup_qdisc_taprio(port, type_data);
	case TC_SETUP_QDISC_TBF:
		return lan966x_tc_setup_qdisc_tbf(port, type_data);
	case TC_SETUP_QDISC_CBS:
		return lan966x_tc_setup_qdisc_cbs(port, type_data);
	case TC_SETUP_QDISC_ETS:
		return lan966x_tc_setup_qdisc_ets(port, type_data);
	case TC_SETUP_BLOCK:
		return lan966x_tc_setup_block(port, type_data);
	default:
		return -EOPNOTSUPP;
	}

	return 0;
}