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 14 struct 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 22 static 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 34 static 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 49 static void 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 57 static 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 73 int 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 138 /* .ndo_setup_tc implementation 139 * Entry point for flower block and filter management. 140 */ 141 int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type, 142 void *type_data) 143 { 144 struct efx_nic *efx = efx_netdev_priv(net_dev); 145 146 if (efx->type->is_vf) 147 return -EOPNOTSUPP; 148 if (!efx->tc) 149 return -EOPNOTSUPP; 150 151 if (type == TC_SETUP_CLSFLOWER) 152 return efx_tc_flower(efx, net_dev, type_data, NULL); 153 if (type == TC_SETUP_BLOCK) 154 return efx_tc_setup_block(net_dev, efx, type_data, NULL); 155 156 return -EOPNOTSUPP; 157 } 158