brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · 1b79c53 Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2022 Xilinx Inc.5 *6 * This program is free software; you can redistribute it and/or modify it7 * under the terms of the GNU General Public License version 2 as published8 * by the Free Software Foundation, incorporated herein by reference.9 */10 11#include "tc_bindings.h"12#include "tc.h"13#include "tc_encap_actions.h"14 15struct efx_tc_block_binding {16	struct list_head list;17	struct efx_nic *efx;18	struct efx_rep *efv;19	struct net_device *otherdev; /* may actually be us */20	struct flow_block *block;21};22 23static struct efx_tc_block_binding *efx_tc_find_binding(struct efx_nic *efx,24							struct net_device *otherdev)25{26	struct efx_tc_block_binding *binding;27 28	ASSERT_RTNL();29	list_for_each_entry(binding, &efx->tc->block_list, list)30		if (binding->otherdev == otherdev)31			return binding;32	return NULL;33}34 35static int efx_tc_block_cb(enum tc_setup_type type, void *type_data,36			   void *cb_priv)37{38	struct efx_tc_block_binding *binding = cb_priv;39	struct flow_cls_offload *tcf = type_data;40 41	switch (type) {42	case TC_SETUP_CLSFLOWER:43		return efx_tc_flower(binding->efx, binding->otherdev,44				     tcf, binding->efv);45	default:46		return -EOPNOTSUPP;47	}48}49 50void efx_tc_block_unbind(void *cb_priv)51{52	struct efx_tc_block_binding *binding = cb_priv;53 54	list_del(&binding->list);55	kfree(binding);56}57 58static struct efx_tc_block_binding *efx_tc_create_binding(59			struct efx_nic *efx, struct efx_rep *efv,60			struct net_device *otherdev, struct flow_block *block)61{62	struct efx_tc_block_binding *binding = kmalloc(sizeof(*binding), GFP_KERNEL);63 64	if (!binding)65		return ERR_PTR(-ENOMEM);66	binding->efx = efx;67	binding->efv = efv;68	binding->otherdev = otherdev;69	binding->block = block;70	list_add(&binding->list, &efx->tc->block_list);71	return binding;72}73 74int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,75		       struct flow_block_offload *tcb, struct efx_rep *efv)76{77	struct efx_tc_block_binding *binding;78	struct flow_block_cb *block_cb;79	int rc;80 81	if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)82		return -EOPNOTSUPP;83 84	if (WARN_ON(!efx->tc))85		return -ENETDOWN;86 87	switch (tcb->command) {88	case FLOW_BLOCK_BIND:89		binding = efx_tc_create_binding(efx, efv, net_dev, tcb->block);90		if (IS_ERR(binding))91			return PTR_ERR(binding);92		block_cb = flow_block_cb_alloc(efx_tc_block_cb, binding,93					       binding, efx_tc_block_unbind);94		rc = PTR_ERR_OR_ZERO(block_cb);95		netif_dbg(efx, drv, efx->net_dev,96			  "bind %sdirect block for device %s, rc %d\n",97			  net_dev == efx->net_dev ? "" :98			  efv ? "semi" : "in",99			  net_dev ? net_dev->name : NULL, rc);100		if (rc) {101			list_del(&binding->list);102			kfree(binding);103		} else {104			flow_block_cb_add(block_cb, tcb);105		}106		return rc;107	case FLOW_BLOCK_UNBIND:108		binding = efx_tc_find_binding(efx, net_dev);109		if (binding) {110			block_cb = flow_block_cb_lookup(tcb->block,111							efx_tc_block_cb,112							binding);113			if (block_cb) {114				flow_block_cb_remove(block_cb, tcb);115				netif_dbg(efx, drv, efx->net_dev,116					  "unbound %sdirect block for device %s\n",117					  net_dev == efx->net_dev ? "" :118					  binding->efv ? "semi" : "in",119					  net_dev ? net_dev->name : NULL);120				return 0;121			}122		}123		/* If we're in driver teardown, then we expect to have124		 * already unbound all our blocks (we did it early while125		 * we still had MCDI to remove the filters), so getting126		 * unbind callbacks now isn't a problem.127		 */128		netif_cond_dbg(efx, drv, efx->net_dev,129			       !efx->tc->up, warn,130			       "%sdirect block unbind for device %s, was never bound\n",131			       net_dev == efx->net_dev ? "" : "in",132			       net_dev ? net_dev->name : NULL);133		return -ENOENT;134	default:135		return -EOPNOTSUPP;136	}137}138 139int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,140			 void *cb_priv, enum tc_setup_type type,141			 void *type_data, void *data,142			 void (*cleanup)(struct flow_block_cb *block_cb))143{144	struct flow_block_offload *tcb = type_data;145	struct efx_tc_block_binding *binding;146	struct flow_block_cb *block_cb;147	struct efx_nic *efx = cb_priv;148	bool is_ovs_int_port;149	int rc;150 151	if (!net_dev)152		return -EOPNOTSUPP;153 154	if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&155	    tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)156		return -EOPNOTSUPP;157 158	is_ovs_int_port = netif_is_ovs_master(net_dev);159	if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&160	    !is_ovs_int_port)161		return -EOPNOTSUPP;162 163	if (is_ovs_int_port)164		return -EOPNOTSUPP;165 166	switch (type) {167	case TC_SETUP_BLOCK:168		switch (tcb->command) {169		case FLOW_BLOCK_BIND:170			binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block);171			if (IS_ERR(binding))172				return PTR_ERR(binding);173			block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding,174							    binding, efx_tc_block_unbind,175							    tcb, net_dev, sch, data, binding,176							    cleanup);177			rc = PTR_ERR_OR_ZERO(block_cb);178			netif_dbg(efx, drv, efx->net_dev,179				  "bind indr block for device %s, rc %d\n",180				  net_dev ? net_dev->name : NULL, rc);181			if (rc) {182				list_del(&binding->list);183				kfree(binding);184			} else {185				flow_block_cb_add(block_cb, tcb);186			}187			return rc;188		case FLOW_BLOCK_UNBIND:189			binding = efx_tc_find_binding(efx, net_dev);190			if (!binding)191				return -ENOENT;192			block_cb = flow_block_cb_lookup(tcb->block,193							efx_tc_block_cb,194							binding);195			if (!block_cb)196				return -ENOENT;197			flow_indr_block_cb_remove(block_cb, tcb);198			netif_dbg(efx, drv, efx->net_dev,199				  "unbind indr block for device %s\n",200				  net_dev ? net_dev->name : NULL);201			return 0;202		default:203			return -EOPNOTSUPP;204		}205	default:206		return -EOPNOTSUPP;207	}208}209 210/* .ndo_setup_tc implementation211 * Entry point for flower block and filter management.212 */213int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,214		 void *type_data)215{216	struct efx_nic *efx = efx_netdev_priv(net_dev);217 218	if (efx->type->is_vf)219		return -EOPNOTSUPP;220	if (!efx->tc)221		return -EOPNOTSUPP;222 223	if (type == TC_SETUP_CLSFLOWER)224		return efx_tc_flower(efx, net_dev, type_data, NULL);225	if (type == TC_SETUP_BLOCK)226		return efx_tc_setup_block(net_dev, efx, type_data, NULL);227 228	return -EOPNOTSUPP;229}230 231int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event,232			struct net_device *net_dev)233{234	if (efx->type->is_vf)235		return NOTIFY_DONE;236 237	if (event == NETDEV_UNREGISTER)238		efx_tc_unregister_egdev(efx, net_dev);239 240	return NOTIFY_OK;241}242