Linux Audio

Check our new training course

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