mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	sfc: bind indirect blocks for TC offload on EF100
Bind indirect blocks for recognised tunnel netdevices. Currently these connect to a stub efx_tc_flower() that only returns -EOPNOTSUPP; subsequent patches will implement flower offloads to the Match-Action Engine. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									9dc0cad203
								
							
						
					
					
						commit
						5b2e12d51b
					
				
					 3 changed files with 84 additions and 1 deletions
				
			
		| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "tc.h"
 | 
					#include "tc.h"
 | 
				
			||||||
 | 
					#include "tc_bindings.h"
 | 
				
			||||||
#include "mae.h"
 | 
					#include "mae.h"
 | 
				
			||||||
#include "ef100_rep.h"
 | 
					#include "ef100_rep.h"
 | 
				
			||||||
#include "efx.h"
 | 
					#include "efx.h"
 | 
				
			||||||
| 
						 | 
					@ -217,6 +218,9 @@ int efx_init_tc(struct efx_nic *efx)
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	efx->tc->up = true;
 | 
						efx->tc->up = true;
 | 
				
			||||||
 | 
						rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -225,6 +229,8 @@ void efx_fini_tc(struct efx_nic *efx)
 | 
				
			||||||
	/* We can get called even if efx_init_struct_tc() failed */
 | 
						/* We can get called even if efx_init_struct_tc() failed */
 | 
				
			||||||
	if (!efx->tc)
 | 
						if (!efx->tc)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						if (efx->tc->up)
 | 
				
			||||||
 | 
							flow_indr_dev_unregister(efx_tc_indr_setup_cb, efx, efx_tc_block_unbind);
 | 
				
			||||||
	efx_tc_deconfigure_rep_mport(efx);
 | 
						efx_tc_deconfigure_rep_mport(efx);
 | 
				
			||||||
	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
 | 
						efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
 | 
				
			||||||
	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
 | 
						efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ static int efx_tc_block_cb(enum tc_setup_type type, void *type_data,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void efx_tc_block_unbind(void *cb_priv)
 | 
					void efx_tc_block_unbind(void *cb_priv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct efx_tc_block_binding *binding = cb_priv;
 | 
						struct efx_tc_block_binding *binding = cb_priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,77 @@ int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
 | 
				
			||||||
 | 
								 void *cb_priv, enum tc_setup_type type,
 | 
				
			||||||
 | 
								 void *type_data, void *data,
 | 
				
			||||||
 | 
								 void (*cleanup)(struct flow_block_cb *block_cb))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct flow_block_offload *tcb = type_data;
 | 
				
			||||||
 | 
						struct efx_tc_block_binding *binding;
 | 
				
			||||||
 | 
						struct flow_block_cb *block_cb;
 | 
				
			||||||
 | 
						struct efx_nic *efx = cb_priv;
 | 
				
			||||||
 | 
						bool is_ovs_int_port;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!net_dev)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
 | 
				
			||||||
 | 
						    tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is_ovs_int_port = netif_is_ovs_master(net_dev);
 | 
				
			||||||
 | 
						if (tcb->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
 | 
				
			||||||
 | 
						    !is_ovs_int_port)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_ovs_int_port)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
						case TC_SETUP_BLOCK:
 | 
				
			||||||
 | 
							switch (tcb->command) {
 | 
				
			||||||
 | 
							case FLOW_BLOCK_BIND:
 | 
				
			||||||
 | 
								binding = efx_tc_create_binding(efx, NULL, net_dev, tcb->block);
 | 
				
			||||||
 | 
								if (IS_ERR(binding))
 | 
				
			||||||
 | 
									return PTR_ERR(binding);
 | 
				
			||||||
 | 
								block_cb = flow_indr_block_cb_alloc(efx_tc_block_cb, binding,
 | 
				
			||||||
 | 
												    binding, efx_tc_block_unbind,
 | 
				
			||||||
 | 
												    tcb, net_dev, sch, data, binding,
 | 
				
			||||||
 | 
												    cleanup);
 | 
				
			||||||
 | 
								rc = PTR_ERR_OR_ZERO(block_cb);
 | 
				
			||||||
 | 
								netif_dbg(efx, drv, efx->net_dev,
 | 
				
			||||||
 | 
									  "bind indr block for device %s, rc %d\n",
 | 
				
			||||||
 | 
									  net_dev ? net_dev->name : NULL, rc);
 | 
				
			||||||
 | 
								if (rc) {
 | 
				
			||||||
 | 
									list_del(&binding->list);
 | 
				
			||||||
 | 
									kfree(binding);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									flow_block_cb_add(block_cb, tcb);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							case FLOW_BLOCK_UNBIND:
 | 
				
			||||||
 | 
								binding = efx_tc_find_binding(efx, net_dev);
 | 
				
			||||||
 | 
								if (!binding)
 | 
				
			||||||
 | 
									return -ENOENT;
 | 
				
			||||||
 | 
								block_cb = flow_block_cb_lookup(tcb->block,
 | 
				
			||||||
 | 
												efx_tc_block_cb,
 | 
				
			||||||
 | 
												binding);
 | 
				
			||||||
 | 
								if (!block_cb)
 | 
				
			||||||
 | 
									return -ENOENT;
 | 
				
			||||||
 | 
								flow_indr_block_cb_remove(block_cb, tcb);
 | 
				
			||||||
 | 
								netif_dbg(efx, drv, efx->net_dev,
 | 
				
			||||||
 | 
									  "unbind indr block for device %s\n",
 | 
				
			||||||
 | 
									  net_dev ? net_dev->name : NULL);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* .ndo_setup_tc implementation
 | 
					/* .ndo_setup_tc implementation
 | 
				
			||||||
 * Entry point for flower block and filter management.
 | 
					 * Entry point for flower block and filter management.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,14 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct efx_rep;
 | 
					struct efx_rep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void efx_tc_block_unbind(void *cb_priv);
 | 
				
			||||||
int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
 | 
					int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
 | 
				
			||||||
		       struct flow_block_offload *tcb, struct efx_rep *efv);
 | 
							       struct flow_block_offload *tcb, struct efx_rep *efv);
 | 
				
			||||||
int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
 | 
					int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
 | 
				
			||||||
		 void *type_data);
 | 
							 void *type_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
 | 
				
			||||||
 | 
								 void *cb_priv, enum tc_setup_type type,
 | 
				
			||||||
 | 
								 void *type_data, void *data,
 | 
				
			||||||
 | 
								 void (*cleanup)(struct flow_block_cb *block_cb));
 | 
				
			||||||
#endif /* EFX_TC_BINDINGS_H */
 | 
					#endif /* EFX_TC_BINDINGS_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue