brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · 1672d3a Raw
572 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (C) 2019 Chelsio Communications.  All rights reserved. */3 4#include "cxgb4.h"5#include "cxgb4_tc_matchall.h"6#include "sched.h"7#include "cxgb4_uld.h"8#include "cxgb4_filter.h"9#include "cxgb4_tc_flower.h"10 11static int cxgb4_policer_validate(const struct flow_action *action,12				  const struct flow_action_entry *act,13				  struct netlink_ext_ack *extack)14{15	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {16		NL_SET_ERR_MSG_MOD(extack,17				   "Offload not supported when exceed action is not drop");18		return -EOPNOTSUPP;19	}20 21	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&22	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {23		NL_SET_ERR_MSG_MOD(extack,24				   "Offload not supported when conform action is not pipe or ok");25		return -EOPNOTSUPP;26	}27 28	if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&29	    !flow_action_is_last_entry(action, act)) {30		NL_SET_ERR_MSG_MOD(extack,31				   "Offload not supported when conform action is ok, but action is not last");32		return -EOPNOTSUPP;33	}34 35	if (act->police.peakrate_bytes_ps ||36	    act->police.avrate || act->police.overhead) {37		NL_SET_ERR_MSG_MOD(extack,38				   "Offload not supported when peakrate/avrate/overhead is configured");39		return -EOPNOTSUPP;40	}41 42	if (act->police.rate_pkt_ps) {43		NL_SET_ERR_MSG_MOD(extack,44				   "QoS offload not support packets per second");45		return -EOPNOTSUPP;46	}47 48	return 0;49}50 51static int cxgb4_matchall_egress_validate(struct net_device *dev,52					  struct tc_cls_matchall_offload *cls)53{54	struct netlink_ext_ack *extack = cls->common.extack;55	struct flow_action *actions = &cls->rule->action;56	struct port_info *pi = netdev2pinfo(dev);57	struct flow_action_entry *entry;58	struct ch_sched_queue qe;59	struct sched_class *e;60	u64 max_link_rate;61	u32 i, speed;62	int ret;63 64	if (!flow_action_has_entries(actions)) {65		NL_SET_ERR_MSG_MOD(extack,66				   "Egress MATCHALL offload needs at least 1 policing action");67		return -EINVAL;68	} else if (!flow_offload_has_one_action(actions)) {69		NL_SET_ERR_MSG_MOD(extack,70				   "Egress MATCHALL offload only supports 1 policing action");71		return -EINVAL;72	} else if (pi->tc_block_shared) {73		NL_SET_ERR_MSG_MOD(extack,74				   "Egress MATCHALL offload not supported with shared blocks");75		return -EINVAL;76	}77 78	ret = t4_get_link_params(pi, NULL, &speed, NULL);79	if (ret) {80		NL_SET_ERR_MSG_MOD(extack,81				   "Failed to get max speed supported by the link");82		return -EINVAL;83	}84 85	/* Convert from Mbps to bps */86	max_link_rate = (u64)speed * 1000 * 1000;87 88	flow_action_for_each(i, entry, actions) {89		switch (entry->id) {90		case FLOW_ACTION_POLICE:91			ret = cxgb4_policer_validate(actions, entry, extack);92			if (ret)93				return ret;94 95			/* Convert bytes per second to bits per second */96			if (entry->police.rate_bytes_ps * 8 > max_link_rate) {97				NL_SET_ERR_MSG_MOD(extack,98						   "Specified policing max rate is larger than underlying link speed");99				return -ERANGE;100			}101			break;102		default:103			NL_SET_ERR_MSG_MOD(extack,104					   "Only policing action supported with Egress MATCHALL offload");105			return -EOPNOTSUPP;106		}107	}108 109	for (i = 0; i < pi->nqsets; i++) {110		memset(&qe, 0, sizeof(qe));111		qe.queue = i;112 113		e = cxgb4_sched_queue_lookup(dev, &qe);114		if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CH_RL) {115			NL_SET_ERR_MSG_MOD(extack,116					   "Some queues are already bound to different class");117			return -EBUSY;118		}119	}120 121	return 0;122}123 124static int cxgb4_matchall_tc_bind_queues(struct net_device *dev, u32 tc)125{126	struct port_info *pi = netdev2pinfo(dev);127	struct ch_sched_queue qe;128	int ret;129	u32 i;130 131	for (i = 0; i < pi->nqsets; i++) {132		qe.queue = i;133		qe.class = tc;134		ret = cxgb4_sched_class_bind(dev, &qe, SCHED_QUEUE);135		if (ret)136			goto out_free;137	}138 139	return 0;140 141out_free:142	while (i--) {143		qe.queue = i;144		qe.class = SCHED_CLS_NONE;145		cxgb4_sched_class_unbind(dev, &qe, SCHED_QUEUE);146	}147 148	return ret;149}150 151static void cxgb4_matchall_tc_unbind_queues(struct net_device *dev)152{153	struct port_info *pi = netdev2pinfo(dev);154	struct ch_sched_queue qe;155	u32 i;156 157	for (i = 0; i < pi->nqsets; i++) {158		qe.queue = i;159		qe.class = SCHED_CLS_NONE;160		cxgb4_sched_class_unbind(dev, &qe, SCHED_QUEUE);161	}162}163 164static int cxgb4_matchall_alloc_tc(struct net_device *dev,165				   struct tc_cls_matchall_offload *cls)166{167	struct ch_sched_params p = {168		.type = SCHED_CLASS_TYPE_PACKET,169		.u.params.level = SCHED_CLASS_LEVEL_CH_RL,170		.u.params.mode = SCHED_CLASS_MODE_CLASS,171		.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS,172		.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS,173		.u.params.class = SCHED_CLS_NONE,174		.u.params.minrate = 0,175		.u.params.weight = 0,176		.u.params.pktsize = dev->mtu,177	};178	struct netlink_ext_ack *extack = cls->common.extack;179	struct cxgb4_tc_port_matchall *tc_port_matchall;180	struct port_info *pi = netdev2pinfo(dev);181	struct adapter *adap = netdev2adap(dev);182	struct flow_action_entry *entry;183	struct sched_class *e;184	int ret;185	u32 i;186 187	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];188 189	flow_action_for_each(i, entry, &cls->rule->action)190		if (entry->id == FLOW_ACTION_POLICE)191			break;192 193	ret = cxgb4_policer_validate(&cls->rule->action, entry, extack);194	if (ret)195		return ret;196 197	/* Convert from bytes per second to Kbps */198	p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000);199	p.u.params.channel = pi->tx_chan;200	e = cxgb4_sched_class_alloc(dev, &p);201	if (!e) {202		NL_SET_ERR_MSG_MOD(extack,203				   "No free traffic class available for policing action");204		return -ENOMEM;205	}206 207	ret = cxgb4_matchall_tc_bind_queues(dev, e->idx);208	if (ret) {209		NL_SET_ERR_MSG_MOD(extack,210				   "Could not bind queues to traffic class");211		goto out_free;212	}213 214	tc_port_matchall->egress.hwtc = e->idx;215	tc_port_matchall->egress.cookie = cls->cookie;216	tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_ENABLED;217	return 0;218 219out_free:220	cxgb4_sched_class_free(dev, e->idx);221	return ret;222}223 224static void cxgb4_matchall_free_tc(struct net_device *dev)225{226	struct cxgb4_tc_port_matchall *tc_port_matchall;227	struct port_info *pi = netdev2pinfo(dev);228	struct adapter *adap = netdev2adap(dev);229 230	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];231	cxgb4_matchall_tc_unbind_queues(dev);232	cxgb4_sched_class_free(dev, tc_port_matchall->egress.hwtc);233 234	tc_port_matchall->egress.hwtc = SCHED_CLS_NONE;235	tc_port_matchall->egress.cookie = 0;236	tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_DISABLED;237}238 239static int cxgb4_matchall_mirror_alloc(struct net_device *dev,240				       struct tc_cls_matchall_offload *cls)241{242	struct netlink_ext_ack *extack = cls->common.extack;243	struct cxgb4_tc_port_matchall *tc_port_matchall;244	struct port_info *pi = netdev2pinfo(dev);245	struct adapter *adap = netdev2adap(dev);246	struct flow_action_entry *act;247	int ret;248	u32 i;249 250	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];251	flow_action_for_each(i, act, &cls->rule->action) {252		if (act->id == FLOW_ACTION_MIRRED) {253			ret = cxgb4_port_mirror_alloc(dev);254			if (ret) {255				NL_SET_ERR_MSG_MOD(extack,256						   "Couldn't allocate mirror");257				return ret;258			}259 260			tc_port_matchall->ingress.viid_mirror = pi->viid_mirror;261			break;262		}263	}264 265	return 0;266}267 268static void cxgb4_matchall_mirror_free(struct net_device *dev)269{270	struct cxgb4_tc_port_matchall *tc_port_matchall;271	struct port_info *pi = netdev2pinfo(dev);272	struct adapter *adap = netdev2adap(dev);273 274	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];275	if (!tc_port_matchall->ingress.viid_mirror)276		return;277 278	cxgb4_port_mirror_free(dev);279	tc_port_matchall->ingress.viid_mirror = 0;280}281 282static int cxgb4_matchall_del_filter(struct net_device *dev, u8 filter_type)283{284	struct cxgb4_tc_port_matchall *tc_port_matchall;285	struct port_info *pi = netdev2pinfo(dev);286	struct adapter *adap = netdev2adap(dev);287	int ret;288 289	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];290	ret = cxgb4_del_filter(dev, tc_port_matchall->ingress.tid[filter_type],291			       &tc_port_matchall->ingress.fs[filter_type]);292	if (ret)293		return ret;294 295	tc_port_matchall->ingress.tid[filter_type] = 0;296	return 0;297}298 299static int cxgb4_matchall_add_filter(struct net_device *dev,300				     struct tc_cls_matchall_offload *cls,301				     u8 filter_type)302{303	struct netlink_ext_ack *extack = cls->common.extack;304	struct cxgb4_tc_port_matchall *tc_port_matchall;305	struct port_info *pi = netdev2pinfo(dev);306	struct adapter *adap = netdev2adap(dev);307	struct ch_filter_specification *fs;308	int ret, fidx;309 310	/* Get a free filter entry TID, where we can insert this new311	 * rule. Only insert rule if its prio doesn't conflict with312	 * existing rules.313	 */314	fidx = cxgb4_get_free_ftid(dev, filter_type ? PF_INET6 : PF_INET,315				   false, cls->common.prio);316	if (fidx < 0) {317		NL_SET_ERR_MSG_MOD(extack,318				   "No free LETCAM index available");319		return -ENOMEM;320	}321 322	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];323	fs = &tc_port_matchall->ingress.fs[filter_type];324	memset(fs, 0, sizeof(*fs));325 326	if (fidx < adap->tids.nhpftids)327		fs->prio = 1;328	fs->tc_prio = cls->common.prio;329	fs->tc_cookie = cls->cookie;330	fs->type = filter_type;331	fs->hitcnts = 1;332 333	fs->val.pfvf_vld = 1;334	fs->val.pf = adap->pf;335	fs->val.vf = pi->vin;336 337	cxgb4_process_flow_actions(dev, &cls->rule->action, fs);338 339	ret = cxgb4_set_filter(dev, fidx, fs);340	if (ret)341		return ret;342 343	tc_port_matchall->ingress.tid[filter_type] = fidx;344	return 0;345}346 347static int cxgb4_matchall_alloc_filter(struct net_device *dev,348				       struct tc_cls_matchall_offload *cls)349{350	struct cxgb4_tc_port_matchall *tc_port_matchall;351	struct port_info *pi = netdev2pinfo(dev);352	struct adapter *adap = netdev2adap(dev);353	int ret, i;354 355	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];356 357	ret = cxgb4_matchall_mirror_alloc(dev, cls);358	if (ret)359		return ret;360 361	for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {362		ret = cxgb4_matchall_add_filter(dev, cls, i);363		if (ret)364			goto out_free;365	}366 367	tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_ENABLED;368	return 0;369 370out_free:371	while (i-- > 0)372		cxgb4_matchall_del_filter(dev, i);373 374	cxgb4_matchall_mirror_free(dev);375	return ret;376}377 378static int cxgb4_matchall_free_filter(struct net_device *dev)379{380	struct cxgb4_tc_port_matchall *tc_port_matchall;381	struct port_info *pi = netdev2pinfo(dev);382	struct adapter *adap = netdev2adap(dev);383	int ret;384	u8 i;385 386	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];387 388	for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {389		ret = cxgb4_matchall_del_filter(dev, i);390		if (ret)391			return ret;392	}393 394	cxgb4_matchall_mirror_free(dev);395 396	tc_port_matchall->ingress.packets = 0;397	tc_port_matchall->ingress.bytes = 0;398	tc_port_matchall->ingress.last_used = 0;399	tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_DISABLED;400	return 0;401}402 403int cxgb4_tc_matchall_replace(struct net_device *dev,404			      struct tc_cls_matchall_offload *cls_matchall,405			      bool ingress)406{407	struct netlink_ext_ack *extack = cls_matchall->common.extack;408	struct cxgb4_tc_port_matchall *tc_port_matchall;409	struct port_info *pi = netdev2pinfo(dev);410	struct adapter *adap = netdev2adap(dev);411	int ret;412 413	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];414	if (ingress) {415		if (tc_port_matchall->ingress.state ==416		    CXGB4_MATCHALL_STATE_ENABLED) {417			NL_SET_ERR_MSG_MOD(extack,418					   "Only 1 Ingress MATCHALL can be offloaded");419			return -ENOMEM;420		}421 422		ret = cxgb4_validate_flow_actions(dev,423						  &cls_matchall->rule->action,424						  extack, 1);425		if (ret)426			return ret;427 428		return cxgb4_matchall_alloc_filter(dev, cls_matchall);429	}430 431	if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) {432		NL_SET_ERR_MSG_MOD(extack,433				   "Only 1 Egress MATCHALL can be offloaded");434		return -ENOMEM;435	}436 437	ret = cxgb4_matchall_egress_validate(dev, cls_matchall);438	if (ret)439		return ret;440 441	return cxgb4_matchall_alloc_tc(dev, cls_matchall);442}443 444int cxgb4_tc_matchall_destroy(struct net_device *dev,445			      struct tc_cls_matchall_offload *cls_matchall,446			      bool ingress)447{448	struct cxgb4_tc_port_matchall *tc_port_matchall;449	struct port_info *pi = netdev2pinfo(dev);450	struct adapter *adap = netdev2adap(dev);451 452	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];453	if (ingress) {454		/* All the filter types of this matchall rule save the455		 * same cookie. So, checking for the first one is456		 * enough.457		 */458		if (cls_matchall->cookie !=459		    tc_port_matchall->ingress.fs[0].tc_cookie)460			return -ENOENT;461 462		return cxgb4_matchall_free_filter(dev);463	}464 465	if (cls_matchall->cookie != tc_port_matchall->egress.cookie)466		return -ENOENT;467 468	cxgb4_matchall_free_tc(dev);469	return 0;470}471 472int cxgb4_tc_matchall_stats(struct net_device *dev,473			    struct tc_cls_matchall_offload *cls_matchall)474{475	u64 tmp_packets, tmp_bytes, packets = 0, bytes = 0;476	struct cxgb4_tc_port_matchall *tc_port_matchall;477	struct cxgb4_matchall_ingress_entry *ingress;478	struct port_info *pi = netdev2pinfo(dev);479	struct adapter *adap = netdev2adap(dev);480	int ret;481	u8 i;482 483	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];484	if (tc_port_matchall->ingress.state == CXGB4_MATCHALL_STATE_DISABLED)485		return -ENOENT;486 487	ingress = &tc_port_matchall->ingress;488	for (i = 0; i < CXGB4_FILTER_TYPE_MAX; i++) {489		ret = cxgb4_get_filter_counters(dev, ingress->tid[i],490						&tmp_packets, &tmp_bytes,491						ingress->fs[i].hash);492		if (ret)493			return ret;494 495		packets += tmp_packets;496		bytes += tmp_bytes;497	}498 499	if (tc_port_matchall->ingress.packets != packets) {500		flow_stats_update(&cls_matchall->stats,501				  bytes - tc_port_matchall->ingress.bytes,502				  packets - tc_port_matchall->ingress.packets,503				  0, tc_port_matchall->ingress.last_used,504				  FLOW_ACTION_HW_STATS_IMMEDIATE);505 506		tc_port_matchall->ingress.packets = packets;507		tc_port_matchall->ingress.bytes = bytes;508		tc_port_matchall->ingress.last_used = jiffies;509	}510 511	return 0;512}513 514static void cxgb4_matchall_disable_offload(struct net_device *dev)515{516	struct cxgb4_tc_port_matchall *tc_port_matchall;517	struct port_info *pi = netdev2pinfo(dev);518	struct adapter *adap = netdev2adap(dev);519 520	tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id];521	if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED)522		cxgb4_matchall_free_tc(dev);523 524	if (tc_port_matchall->ingress.state == CXGB4_MATCHALL_STATE_ENABLED)525		cxgb4_matchall_free_filter(dev);526}527 528int cxgb4_init_tc_matchall(struct adapter *adap)529{530	struct cxgb4_tc_port_matchall *tc_port_matchall;531	struct cxgb4_tc_matchall *tc_matchall;532	int ret;533 534	tc_matchall = kzalloc(sizeof(*tc_matchall), GFP_KERNEL);535	if (!tc_matchall)536		return -ENOMEM;537 538	tc_port_matchall = kcalloc(adap->params.nports,539				   sizeof(*tc_port_matchall),540				   GFP_KERNEL);541	if (!tc_port_matchall) {542		ret = -ENOMEM;543		goto out_free_matchall;544	}545 546	tc_matchall->port_matchall = tc_port_matchall;547	adap->tc_matchall = tc_matchall;548	return 0;549 550out_free_matchall:551	kfree(tc_matchall);552	return ret;553}554 555void cxgb4_cleanup_tc_matchall(struct adapter *adap)556{557	u8 i;558 559	if (adap->tc_matchall) {560		if (adap->tc_matchall->port_matchall) {561			for (i = 0; i < adap->params.nports; i++) {562				struct net_device *dev = adap->port[i];563 564				if (dev)565					cxgb4_matchall_disable_offload(dev);566			}567			kfree(adap->tc_matchall->port_matchall);568		}569		kfree(adap->tc_matchall);570	}571}572