1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (C) 2019 Chelsio Communications. All rights reserved. */
5 #include "cxgb4_tc_matchall.h"
8 static int cxgb4_matchall_egress_validate(struct net_device *dev,
9 struct tc_cls_matchall_offload *cls)
11 struct netlink_ext_ack *extack = cls->common.extack;
12 struct flow_action *actions = &cls->rule->action;
13 struct port_info *pi = netdev2pinfo(dev);
14 struct flow_action_entry *entry;
19 if (!flow_action_has_entries(actions)) {
20 NL_SET_ERR_MSG_MOD(extack,
21 "Egress MATCHALL offload needs at least 1 policing action");
23 } else if (!flow_offload_has_one_action(actions)) {
24 NL_SET_ERR_MSG_MOD(extack,
25 "Egress MATCHALL offload only supports 1 policing action");
27 } else if (pi->tc_block_shared) {
28 NL_SET_ERR_MSG_MOD(extack,
29 "Egress MATCHALL offload not supported with shared blocks");
33 ret = t4_get_link_params(pi, NULL, &speed, NULL);
35 NL_SET_ERR_MSG_MOD(extack,
36 "Failed to get max speed supported by the link");
40 /* Convert from Mbps to bps */
41 max_link_rate = (u64)speed * 1000 * 1000;
43 flow_action_for_each(i, entry, actions) {
45 case FLOW_ACTION_POLICE:
46 /* Convert bytes per second to bits per second */
47 if (entry->police.rate_bytes_ps * 8 > max_link_rate) {
48 NL_SET_ERR_MSG_MOD(extack,
49 "Specified policing max rate is larger than underlying link speed");
54 NL_SET_ERR_MSG_MOD(extack,
55 "Only policing action supported with Egress MATCHALL offload");
63 static int cxgb4_matchall_alloc_tc(struct net_device *dev,
64 struct tc_cls_matchall_offload *cls)
66 struct ch_sched_params p = {
67 .type = SCHED_CLASS_TYPE_PACKET,
68 .u.params.level = SCHED_CLASS_LEVEL_CH_RL,
69 .u.params.mode = SCHED_CLASS_MODE_CLASS,
70 .u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS,
71 .u.params.ratemode = SCHED_CLASS_RATEMODE_ABS,
72 .u.params.class = SCHED_CLS_NONE,
73 .u.params.minrate = 0,
75 .u.params.pktsize = dev->mtu,
77 struct netlink_ext_ack *extack = cls->common.extack;
78 struct cxgb4_tc_port_matchall *tc_port_matchall;
79 struct port_info *pi = netdev2pinfo(dev);
80 struct adapter *adap = netdev2adap(dev);
81 struct flow_action_entry *entry;
82 struct sched_class *e;
85 tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
87 flow_action_for_each(i, entry, &cls->rule->action)
88 if (entry->id == FLOW_ACTION_POLICE)
91 /* Convert from bytes per second to Kbps */
92 p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000);
93 p.u.params.channel = pi->tx_chan;
94 e = cxgb4_sched_class_alloc(dev, &p);
96 NL_SET_ERR_MSG_MOD(extack,
97 "No free traffic class available for policing action");
101 tc_port_matchall->egress.hwtc = e->idx;
102 tc_port_matchall->egress.cookie = cls->cookie;
103 tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_ENABLED;
107 static void cxgb4_matchall_free_tc(struct net_device *dev)
109 struct cxgb4_tc_port_matchall *tc_port_matchall;
110 struct port_info *pi = netdev2pinfo(dev);
111 struct adapter *adap = netdev2adap(dev);
113 tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
114 cxgb4_sched_class_free(dev, tc_port_matchall->egress.hwtc);
116 tc_port_matchall->egress.hwtc = SCHED_CLS_NONE;
117 tc_port_matchall->egress.cookie = 0;
118 tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_DISABLED;
121 int cxgb4_tc_matchall_replace(struct net_device *dev,
122 struct tc_cls_matchall_offload *cls_matchall)
124 struct netlink_ext_ack *extack = cls_matchall->common.extack;
125 struct cxgb4_tc_port_matchall *tc_port_matchall;
126 struct port_info *pi = netdev2pinfo(dev);
127 struct adapter *adap = netdev2adap(dev);
130 tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
131 if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) {
132 NL_SET_ERR_MSG_MOD(extack,
133 "Only 1 Egress MATCHALL can be offloaded");
137 ret = cxgb4_matchall_egress_validate(dev, cls_matchall);
141 return cxgb4_matchall_alloc_tc(dev, cls_matchall);
144 int cxgb4_tc_matchall_destroy(struct net_device *dev,
145 struct tc_cls_matchall_offload *cls_matchall)
147 struct cxgb4_tc_port_matchall *tc_port_matchall;
148 struct port_info *pi = netdev2pinfo(dev);
149 struct adapter *adap = netdev2adap(dev);
151 tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
152 if (cls_matchall->cookie != tc_port_matchall->egress.cookie)
155 cxgb4_matchall_free_tc(dev);
159 static void cxgb4_matchall_disable_offload(struct net_device *dev)
161 struct cxgb4_tc_port_matchall *tc_port_matchall;
162 struct port_info *pi = netdev2pinfo(dev);
163 struct adapter *adap = netdev2adap(dev);
165 tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];
166 if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED)
167 cxgb4_matchall_free_tc(dev);
170 int cxgb4_init_tc_matchall(struct adapter *adap)
172 struct cxgb4_tc_port_matchall *tc_port_matchall;
173 struct cxgb4_tc_matchall *tc_matchall;
176 tc_matchall = kzalloc(sizeof(*tc_matchall), GFP_KERNEL);
180 tc_port_matchall = kcalloc(adap->params.nports,
181 sizeof(*tc_port_matchall),
183 if (!tc_port_matchall) {
185 goto out_free_matchall;
188 tc_matchall->port_matchall = tc_port_matchall;
189 adap->tc_matchall = tc_matchall;
197 void cxgb4_cleanup_tc_matchall(struct adapter *adap)
201 if (adap->tc_matchall) {
202 if (adap->tc_matchall->port_matchall) {
203 for (i = 0; i < adap->params.nports; i++) {
204 struct net_device *dev = adap->port[i];
207 cxgb4_matchall_disable_offload(dev);
209 kfree(adap->tc_matchall->port_matchall);
211 kfree(adap->tc_matchall);