Skip to content

Commit 07def46

Browse files
committed
Merge branch 'cxgb4-add-TC-MATCHALL-classifier-offload'
Rahul Lakkireddy says: ==================== cxgb4: add TC-MATCHALL classifier offload This series of patches add support to offload TC-MATCHALL classifier to hardware to classify all outgoing and incoming traffic on the underlying port. Only 1 egress and 1 ingress rule each can be offloaded on the underlying port. Patch 1 adds support for TC-MATCHALL classifier offload on the egress side. TC-POLICE is the only action that can be offloaded on the egress side and is used to rate limit all outgoing traffic to specified max rate. Patch 2 adds logic to reject the current rule offload if its priority conflicts with existing rules in the TCAM. Patch 3 adds support for TC-MATCHALL classifier offload on the ingress side. The same set of actions supported by existing TC-FLOWER classifier offload can be applied on all the incoming traffic. v5: - Fixed commit message and comment to include comparison for equal priority in patch 2. v4: - Removed check in patch 1 to reject police offload if prio is not 1. - Moved TC_SETUP_BLOCK code to separate function in patch 1. - Added logic to ensure the prio passed by TC doesn't conflict with other rules in TCAM in patch 2. - Higher index has lower priority than lower index in TCAM. So, rework cxgb4_get_free_ftid() to search free index from end of TCAM in descending order in patch 2. - Added check to ensure the matchall rule's prio doesn't conflict with other rules in TCAM in patch 3. - Added logic to fill default mask for VIID, if none has been provided, to prevent conflict with duplicate VIID rules in patch 3. - Used existing variables in private structure to fill VIID info, instead of extracting the info manually in patch 3. v3: - Added check in patch 1 to reject police offload if prio is not 1. - Assign block_shared variable only for TC_SETUP_BLOCK in patch 1. v2: - Added check to reject flow block sharing for policers in patch 1. - Removed logic to fetch free index from end of TCAM in patch 2. Must maintain the same ordering as in kernel. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 77c05d2 + 21c4c60 commit 07def46

File tree

14 files changed

+708
-88
lines changed

14 files changed

+708
-88
lines changed

drivers/net/ethernet/chelsio/cxgb4/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
88
cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \
99
cxgb4_uld.o srq.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \
1010
cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o cxgb4_mps.o \
11-
cudbg_common.o cudbg_lib.o cudbg_zlib.o cxgb4_tc_mqprio.o
11+
cudbg_common.o cudbg_lib.o cudbg_zlib.o cxgb4_tc_mqprio.o \
12+
cxgb4_tc_matchall.o
1213
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
1314
cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
1415
cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o

drivers/net/ethernet/chelsio/cxgb4/cxgb4.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ struct port_info {
603603
u8 vivld;
604604
u8 smt_idx;
605605
u8 rx_cchan;
606+
607+
bool tc_block_shared;
606608
};
607609

608610
struct dentry;
@@ -1101,6 +1103,9 @@ struct adapter {
11011103

11021104
/* TC MQPRIO offload */
11031105
struct cxgb4_tc_mqprio *tc_mqprio;
1106+
1107+
/* TC MATCHALL classifier offload */
1108+
struct cxgb4_tc_matchall *tc_matchall;
11041109
};
11051110

11061111
/* Support for "sched-class" command to allow a TX Scheduling Class to be
@@ -1130,6 +1135,7 @@ enum {
11301135

11311136
enum {
11321137
SCHED_CLASS_LEVEL_CL_RL = 0, /* class rate limiter */
1138+
SCHED_CLASS_LEVEL_CH_RL = 2, /* channel rate limiter */
11331139
};
11341140

11351141
enum {
@@ -1280,8 +1286,11 @@ struct ch_filter_specification {
12801286
u16 nat_lport; /* local port to use after NAT'ing */
12811287
u16 nat_fport; /* foreign port to use after NAT'ing */
12821288

1289+
u32 tc_prio; /* TC's filter priority index */
1290+
u64 tc_cookie; /* Unique cookie identifying TC rules */
1291+
12831292
/* reservation for future additions */
1284-
u8 rsvd[24];
1293+
u8 rsvd[12];
12851294

12861295
/* Filter rule value/mask pairs.
12871296
*/

drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -440,36 +440,48 @@ int cxgb4_get_free_ftid(struct net_device *dev, int family)
440440
{
441441
struct adapter *adap = netdev2adap(dev);
442442
struct tid_info *t = &adap->tids;
443+
bool found = false;
444+
u8 i, n, cnt;
443445
int ftid;
444446

445-
spin_lock_bh(&t->ftid_lock);
446-
if (family == PF_INET) {
447-
ftid = find_first_zero_bit(t->ftid_bmap, t->nftids);
448-
if (ftid >= t->nftids)
449-
ftid = -1;
450-
} else {
451-
if (is_t6(adap->params.chip)) {
452-
ftid = bitmap_find_free_region(t->ftid_bmap,
453-
t->nftids, 1);
454-
if (ftid < 0)
455-
goto out_unlock;
456-
457-
/* this is only a lookup, keep the found region
458-
* unallocated
459-
*/
460-
bitmap_release_region(t->ftid_bmap, ftid, 1);
461-
} else {
462-
ftid = bitmap_find_free_region(t->ftid_bmap,
463-
t->nftids, 2);
464-
if (ftid < 0)
465-
goto out_unlock;
447+
/* IPv4 occupy 1 slot. IPv6 occupy 2 slots on T6 and 4 slots
448+
* on T5.
449+
*/
450+
n = 1;
451+
if (family == PF_INET6) {
452+
n++;
453+
if (CHELSIO_CHIP_VERSION(adap->params.chip) < CHELSIO_T6)
454+
n += 2;
455+
}
456+
457+
if (n > t->nftids)
458+
return -ENOMEM;
466459

467-
bitmap_release_region(t->ftid_bmap, ftid, 2);
460+
/* Find free filter slots from the end of TCAM. Appropriate
461+
* checks must be done by caller later to ensure the prio
462+
* passed by TC doesn't conflict with prio saved by existing
463+
* rules in the TCAM.
464+
*/
465+
spin_lock_bh(&t->ftid_lock);
466+
ftid = t->nftids - 1;
467+
while (ftid >= n - 1) {
468+
cnt = 0;
469+
for (i = 0; i < n; i++) {
470+
if (test_bit(ftid - i, t->ftid_bmap))
471+
break;
472+
cnt++;
468473
}
474+
if (cnt == n) {
475+
ftid &= ~(n - 1);
476+
found = true;
477+
break;
478+
}
479+
480+
ftid -= n;
469481
}
470-
out_unlock:
471482
spin_unlock_bh(&t->ftid_lock);
472-
return ftid;
483+
484+
return found ? ftid : -ENOMEM;
473485
}
474486

475487
static int cxgb4_set_ftid(struct tid_info *t, int fidx, int family,
@@ -510,6 +522,60 @@ static void cxgb4_clear_ftid(struct tid_info *t, int fidx, int family,
510522
spin_unlock_bh(&t->ftid_lock);
511523
}
512524

525+
bool cxgb4_filter_prio_in_range(struct net_device *dev, u32 idx, u32 prio)
526+
{
527+
struct adapter *adap = netdev2adap(dev);
528+
struct filter_entry *prev_fe, *next_fe;
529+
struct tid_info *t = &adap->tids;
530+
u32 prev_ftid, next_ftid;
531+
bool valid = true;
532+
533+
/* Only insert the rule if both of the following conditions
534+
* are met:
535+
* 1. The immediate previous rule has priority <= @prio.
536+
* 2. The immediate next rule has priority >= @prio.
537+
*/
538+
spin_lock_bh(&t->ftid_lock);
539+
/* Don't insert if there's a rule already present at @idx. */
540+
if (test_bit(idx, t->ftid_bmap)) {
541+
valid = false;
542+
goto out_unlock;
543+
}
544+
545+
next_ftid = find_next_bit(t->ftid_bmap, t->nftids, idx);
546+
if (next_ftid >= t->nftids)
547+
next_ftid = idx;
548+
549+
next_fe = &adap->tids.ftid_tab[next_ftid];
550+
551+
prev_ftid = find_last_bit(t->ftid_bmap, idx);
552+
if (prev_ftid >= idx)
553+
prev_ftid = idx;
554+
555+
/* See if the filter entry belongs to an IPv6 rule, which
556+
* occupy 4 slots on T5 and 2 slots on T6. Adjust the
557+
* reference to the previously inserted filter entry
558+
* accordingly.
559+
*/
560+
if (CHELSIO_CHIP_VERSION(adap->params.chip) < CHELSIO_T6) {
561+
prev_fe = &adap->tids.ftid_tab[prev_ftid & ~0x3];
562+
if (!prev_fe->fs.type)
563+
prev_fe = &adap->tids.ftid_tab[prev_ftid];
564+
} else {
565+
prev_fe = &adap->tids.ftid_tab[prev_ftid & ~0x1];
566+
if (!prev_fe->fs.type)
567+
prev_fe = &adap->tids.ftid_tab[prev_ftid];
568+
}
569+
570+
if ((prev_fe->valid && prio < prev_fe->fs.tc_prio) ||
571+
(next_fe->valid && prio > next_fe->fs.tc_prio))
572+
valid = false;
573+
574+
out_unlock:
575+
spin_unlock_bh(&t->ftid_lock);
576+
return valid;
577+
}
578+
513579
/* Delete the filter at a specified index. */
514580
static int del_filter_wr(struct adapter *adapter, int fidx)
515581
{
@@ -806,6 +872,12 @@ static void fill_default_mask(struct ch_filter_specification *fs)
806872
fs->mask.tos |= ~0;
807873
if (fs->val.proto && !fs->mask.proto)
808874
fs->mask.proto |= ~0;
875+
if (fs->val.pfvf_vld && !fs->mask.pfvf_vld)
876+
fs->mask.pfvf_vld |= ~0;
877+
if (fs->val.pf && !fs->mask.pf)
878+
fs->mask.pf |= ~0;
879+
if (fs->val.vf && !fs->mask.vf)
880+
fs->mask.vf |= ~0;
809881

810882
for (i = 0; i < ARRAY_SIZE(fs->val.lip); i++) {
811883
lip |= fs->val.lip[i];

drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ void clear_all_filters(struct adapter *adapter);
5353
void init_hash_filter(struct adapter *adap);
5454
bool is_filter_exact_match(struct adapter *adap,
5555
struct ch_filter_specification *fs);
56+
bool cxgb4_filter_prio_in_range(struct net_device *dev, u32 idx, u32 prio);
5657
#endif /* __CXGB4_FILTER_H */

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "cxgb4_tc_u32.h"
8585
#include "cxgb4_tc_flower.h"
8686
#include "cxgb4_tc_mqprio.h"
87+
#include "cxgb4_tc_matchall.h"
8788
#include "cxgb4_ptp.h"
8889
#include "cxgb4_cudbg.h"
8990

@@ -3234,8 +3235,33 @@ static int cxgb_setup_tc_cls_u32(struct net_device *dev,
32343235
}
32353236
}
32363237

3237-
static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
3238-
void *cb_priv)
3238+
static int cxgb_setup_tc_matchall(struct net_device *dev,
3239+
struct tc_cls_matchall_offload *cls_matchall,
3240+
bool ingress)
3241+
{
3242+
struct adapter *adap = netdev2adap(dev);
3243+
3244+
if (!adap->tc_matchall)
3245+
return -ENOMEM;
3246+
3247+
switch (cls_matchall->command) {
3248+
case TC_CLSMATCHALL_REPLACE:
3249+
return cxgb4_tc_matchall_replace(dev, cls_matchall, ingress);
3250+
case TC_CLSMATCHALL_DESTROY:
3251+
return cxgb4_tc_matchall_destroy(dev, cls_matchall, ingress);
3252+
case TC_CLSMATCHALL_STATS:
3253+
if (ingress)
3254+
return cxgb4_tc_matchall_stats(dev, cls_matchall);
3255+
break;
3256+
default:
3257+
break;
3258+
}
3259+
3260+
return -EOPNOTSUPP;
3261+
}
3262+
3263+
static int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type,
3264+
void *type_data, void *cb_priv)
32393265
{
32403266
struct net_device *dev = cb_priv;
32413267
struct port_info *pi = netdev2pinfo(dev);
@@ -3256,11 +3282,40 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
32563282
return cxgb_setup_tc_cls_u32(dev, type_data);
32573283
case TC_SETUP_CLSFLOWER:
32583284
return cxgb_setup_tc_flower(dev, type_data);
3285+
case TC_SETUP_CLSMATCHALL:
3286+
return cxgb_setup_tc_matchall(dev, type_data, true);
32593287
default:
32603288
return -EOPNOTSUPP;
32613289
}
32623290
}
32633291

3292+
static int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type,
3293+
void *type_data, void *cb_priv)
3294+
{
3295+
struct net_device *dev = cb_priv;
3296+
struct port_info *pi = netdev2pinfo(dev);
3297+
struct adapter *adap = netdev2adap(dev);
3298+
3299+
if (!(adap->flags & CXGB4_FULL_INIT_DONE)) {
3300+
dev_err(adap->pdev_dev,
3301+
"Failed to setup tc on port %d. Link Down?\n",
3302+
pi->port_id);
3303+
return -EINVAL;
3304+
}
3305+
3306+
if (!tc_cls_can_offload_and_chain0(dev, type_data))
3307+
return -EOPNOTSUPP;
3308+
3309+
switch (type) {
3310+
case TC_SETUP_CLSMATCHALL:
3311+
return cxgb_setup_tc_matchall(dev, type_data, false);
3312+
default:
3313+
break;
3314+
}
3315+
3316+
return -EOPNOTSUPP;
3317+
}
3318+
32643319
static int cxgb_setup_tc_mqprio(struct net_device *dev,
32653320
struct tc_mqprio_qopt_offload *mqprio)
32663321
{
@@ -3274,19 +3329,34 @@ static int cxgb_setup_tc_mqprio(struct net_device *dev,
32743329

32753330
static LIST_HEAD(cxgb_block_cb_list);
32763331

3332+
static int cxgb_setup_tc_block(struct net_device *dev,
3333+
struct flow_block_offload *f)
3334+
{
3335+
struct port_info *pi = netdev_priv(dev);
3336+
flow_setup_cb_t *cb;
3337+
bool ingress_only;
3338+
3339+
pi->tc_block_shared = f->block_shared;
3340+
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
3341+
cb = cxgb_setup_tc_block_egress_cb;
3342+
ingress_only = false;
3343+
} else {
3344+
cb = cxgb_setup_tc_block_ingress_cb;
3345+
ingress_only = true;
3346+
}
3347+
3348+
return flow_block_cb_setup_simple(f, &cxgb_block_cb_list,
3349+
cb, pi, dev, ingress_only);
3350+
}
3351+
32773352
static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
32783353
void *type_data)
32793354
{
3280-
struct port_info *pi = netdev2pinfo(dev);
3281-
32823355
switch (type) {
32833356
case TC_SETUP_QDISC_MQPRIO:
32843357
return cxgb_setup_tc_mqprio(dev, type_data);
32853358
case TC_SETUP_BLOCK:
3286-
return flow_block_cb_setup_simple(type_data,
3287-
&cxgb_block_cb_list,
3288-
cxgb_setup_tc_block_cb,
3289-
pi, dev, true);
3359+
return cxgb_setup_tc_block(dev, type_data);
32903360
default:
32913361
return -EOPNOTSUPP;
32923362
}
@@ -5741,6 +5811,7 @@ static void free_some_resources(struct adapter *adapter)
57415811
kvfree(adapter->srq);
57425812
t4_cleanup_sched(adapter);
57435813
kvfree(adapter->tids.tid_tab);
5814+
cxgb4_cleanup_tc_matchall(adapter);
57445815
cxgb4_cleanup_tc_mqprio(adapter);
57455816
cxgb4_cleanup_tc_flower(adapter);
57465817
cxgb4_cleanup_tc_u32(adapter);
@@ -6315,6 +6386,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
63156386
if (cxgb4_init_tc_mqprio(adapter))
63166387
dev_warn(&pdev->dev,
63176388
"could not offload tc mqprio, continuing\n");
6389+
6390+
if (cxgb4_init_tc_matchall(adapter))
6391+
dev_warn(&pdev->dev,
6392+
"could not offload tc matchall, continuing\n");
63186393
}
63196394

63206395
if (is_offload(adapter) || is_hashfilter(adapter)) {

0 commit comments

Comments
 (0)