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 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 int 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 */ 212 int 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 } 229