.. | .. |
---|
36 | 36 | #include <net/tc_act/tc_mirred.h> |
---|
37 | 37 | |
---|
38 | 38 | #include "cxgb4.h" |
---|
| 39 | +#include "cxgb4_filter.h" |
---|
39 | 40 | #include "cxgb4_tc_u32_parse.h" |
---|
40 | 41 | #include "cxgb4_tc_u32.h" |
---|
41 | 42 | |
---|
.. | .. |
---|
148 | 149 | int cxgb4_config_knode(struct net_device *dev, struct tc_cls_u32_offload *cls) |
---|
149 | 150 | { |
---|
150 | 151 | const struct cxgb4_match_field *start, *link_start = NULL; |
---|
| 152 | + struct netlink_ext_ack *extack = cls->common.extack; |
---|
151 | 153 | struct adapter *adapter = netdev2adap(dev); |
---|
152 | 154 | __be16 protocol = cls->common.protocol; |
---|
153 | 155 | struct ch_filter_specification fs; |
---|
154 | 156 | struct cxgb4_tc_u32_table *t; |
---|
155 | 157 | struct cxgb4_link *link; |
---|
156 | | - unsigned int filter_id; |
---|
157 | 158 | u32 uhtid, link_uhtid; |
---|
158 | 159 | bool is_ipv6 = false; |
---|
| 160 | + u8 inet_family; |
---|
| 161 | + int filter_id; |
---|
159 | 162 | int ret; |
---|
160 | 163 | |
---|
161 | 164 | if (!can_tc_u32_offload(dev)) |
---|
.. | .. |
---|
164 | 167 | if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6)) |
---|
165 | 168 | return -EOPNOTSUPP; |
---|
166 | 169 | |
---|
167 | | - /* Fetch the location to insert the filter. */ |
---|
168 | | - filter_id = cls->knode.handle & 0xFFFFF; |
---|
| 170 | + inet_family = (protocol == htons(ETH_P_IPV6)) ? PF_INET6 : PF_INET; |
---|
169 | 171 | |
---|
170 | | - if (filter_id > adapter->tids.nftids) { |
---|
171 | | - dev_err(adapter->pdev_dev, |
---|
172 | | - "Location %d out of range for insertion. Max: %d\n", |
---|
173 | | - filter_id, adapter->tids.nftids); |
---|
174 | | - return -ERANGE; |
---|
| 172 | + /* Get a free filter entry TID, where we can insert this new |
---|
| 173 | + * rule. Only insert rule if its prio doesn't conflict with |
---|
| 174 | + * existing rules. |
---|
| 175 | + */ |
---|
| 176 | + filter_id = cxgb4_get_free_ftid(dev, inet_family, false, |
---|
| 177 | + TC_U32_NODE(cls->knode.handle)); |
---|
| 178 | + if (filter_id < 0) { |
---|
| 179 | + NL_SET_ERR_MSG_MOD(extack, |
---|
| 180 | + "No free LETCAM index available"); |
---|
| 181 | + return -ENOMEM; |
---|
175 | 182 | } |
---|
176 | 183 | |
---|
177 | 184 | t = adapter->tc_u32; |
---|
.. | .. |
---|
189 | 196 | return -EINVAL; |
---|
190 | 197 | |
---|
191 | 198 | memset(&fs, 0, sizeof(fs)); |
---|
| 199 | + |
---|
| 200 | + if (filter_id < adapter->tids.nhpftids) |
---|
| 201 | + fs.prio = 1; |
---|
| 202 | + fs.tc_prio = cls->common.prio; |
---|
| 203 | + fs.tc_cookie = cls->knode.handle; |
---|
192 | 204 | |
---|
193 | 205 | if (protocol == htons(ETH_P_IPV6)) { |
---|
194 | 206 | start = cxgb4_ipv6_fields; |
---|
.. | .. |
---|
343 | 355 | unsigned int filter_id, max_tids, i, j; |
---|
344 | 356 | struct cxgb4_link *link = NULL; |
---|
345 | 357 | struct cxgb4_tc_u32_table *t; |
---|
| 358 | + struct filter_entry *f; |
---|
| 359 | + bool found = false; |
---|
346 | 360 | u32 handle, uhtid; |
---|
| 361 | + u8 nslots; |
---|
347 | 362 | int ret; |
---|
348 | 363 | |
---|
349 | 364 | if (!can_tc_u32_offload(dev)) |
---|
350 | 365 | return -EOPNOTSUPP; |
---|
351 | 366 | |
---|
352 | 367 | /* Fetch the location to delete the filter. */ |
---|
353 | | - filter_id = cls->knode.handle & 0xFFFFF; |
---|
| 368 | + max_tids = adapter->tids.nhpftids + adapter->tids.nftids; |
---|
354 | 369 | |
---|
355 | | - if (filter_id > adapter->tids.nftids) { |
---|
356 | | - dev_err(adapter->pdev_dev, |
---|
357 | | - "Location %d out of range for deletion. Max: %d\n", |
---|
358 | | - filter_id, adapter->tids.nftids); |
---|
359 | | - return -ERANGE; |
---|
| 370 | + spin_lock_bh(&adapter->tids.ftid_lock); |
---|
| 371 | + filter_id = 0; |
---|
| 372 | + while (filter_id < max_tids) { |
---|
| 373 | + if (filter_id < adapter->tids.nhpftids) { |
---|
| 374 | + i = filter_id; |
---|
| 375 | + f = &adapter->tids.hpftid_tab[i]; |
---|
| 376 | + if (f->valid && f->fs.tc_cookie == cls->knode.handle) { |
---|
| 377 | + found = true; |
---|
| 378 | + break; |
---|
| 379 | + } |
---|
| 380 | + |
---|
| 381 | + i = find_next_bit(adapter->tids.hpftid_bmap, |
---|
| 382 | + adapter->tids.nhpftids, i + 1); |
---|
| 383 | + if (i >= adapter->tids.nhpftids) { |
---|
| 384 | + filter_id = adapter->tids.nhpftids; |
---|
| 385 | + continue; |
---|
| 386 | + } |
---|
| 387 | + |
---|
| 388 | + filter_id = i; |
---|
| 389 | + } else { |
---|
| 390 | + i = filter_id - adapter->tids.nhpftids; |
---|
| 391 | + f = &adapter->tids.ftid_tab[i]; |
---|
| 392 | + if (f->valid && f->fs.tc_cookie == cls->knode.handle) { |
---|
| 393 | + found = true; |
---|
| 394 | + break; |
---|
| 395 | + } |
---|
| 396 | + |
---|
| 397 | + i = find_next_bit(adapter->tids.ftid_bmap, |
---|
| 398 | + adapter->tids.nftids, i + 1); |
---|
| 399 | + if (i >= adapter->tids.nftids) |
---|
| 400 | + break; |
---|
| 401 | + |
---|
| 402 | + filter_id = i + adapter->tids.nhpftids; |
---|
| 403 | + } |
---|
| 404 | + |
---|
| 405 | + nslots = 0; |
---|
| 406 | + if (f->fs.type) { |
---|
| 407 | + nslots++; |
---|
| 408 | + if (CHELSIO_CHIP_VERSION(adapter->params.chip) < |
---|
| 409 | + CHELSIO_T6) |
---|
| 410 | + nslots += 2; |
---|
| 411 | + } |
---|
| 412 | + |
---|
| 413 | + filter_id += nslots; |
---|
360 | 414 | } |
---|
| 415 | + spin_unlock_bh(&adapter->tids.ftid_lock); |
---|
| 416 | + |
---|
| 417 | + if (!found) |
---|
| 418 | + return -ERANGE; |
---|
361 | 419 | |
---|
362 | 420 | t = adapter->tc_u32; |
---|
363 | 421 | handle = cls->knode.handle; |
---|
.. | .. |
---|
389 | 447 | /* If a link is being deleted, then delete all filters |
---|
390 | 448 | * associated with the link. |
---|
391 | 449 | */ |
---|
392 | | - max_tids = adapter->tids.nftids; |
---|
393 | 450 | for (i = 0; i < t->size; i++) { |
---|
394 | 451 | link = &t->table[i]; |
---|
395 | 452 | |
---|
.. | .. |
---|
437 | 494 | |
---|
438 | 495 | struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap) |
---|
439 | 496 | { |
---|
440 | | - unsigned int max_tids = adap->tids.nftids; |
---|
| 497 | + unsigned int max_tids = adap->tids.nftids + adap->tids.nhpftids; |
---|
441 | 498 | struct cxgb4_tc_u32_table *t; |
---|
442 | 499 | unsigned int i; |
---|
443 | 500 | |
---|
444 | 501 | if (!max_tids) |
---|
445 | 502 | return NULL; |
---|
446 | 503 | |
---|
447 | | - t = kvzalloc(sizeof(*t) + |
---|
448 | | - (max_tids * sizeof(struct cxgb4_link)), GFP_KERNEL); |
---|
| 504 | + t = kvzalloc(struct_size(t, table, max_tids), GFP_KERNEL); |
---|
449 | 505 | if (!t) |
---|
450 | 506 | return NULL; |
---|
451 | 507 | |
---|