From: Rahul Lakkireddy Date: Fri, 27 Sep 2019 20:30:03 +0000 (+0530) Subject: net/cxgbe: fix slot allocation for IPv6 flows X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=31d4d2334672fe9d96a0d23cdf914c1f219f932f;p=dpdk.git net/cxgbe: fix slot allocation for IPv6 flows IPv6 flows occupy only 2 slots on Chelsio T6 NICs. Fix the slot calculation logic to return correct number of slots. Fixes: ee61f5113b17 ("net/cxgbe: parse and validate flows") Fixes: 9eb2c9a48072 ("net/cxgbe: implement flow create operation") Fixes: 3f2c1e209cfc ("net/cxgbe: add Compressed Local IP region") Cc: stable@dpdk.org Signed-off-by: Rahul Lakkireddy --- diff --git a/drivers/net/cxgbe/cxgbe_filter.c b/drivers/net/cxgbe/cxgbe_filter.c index 3b7966d045..33b95a69ab 100644 --- a/drivers/net/cxgbe/cxgbe_filter.c +++ b/drivers/net/cxgbe/cxgbe_filter.c @@ -213,20 +213,32 @@ static inline void mk_set_tcb_field_ulp(struct filter_entry *f, } /** - * Check if entry already filled. + * IPv6 requires 2 slots on T6 and 4 slots for cards below T6. + * IPv4 requires only 1 slot on all cards. */ -bool cxgbe_is_filter_set(struct tid_info *t, int fidx, int family) +u8 cxgbe_filter_slots(struct adapter *adap, u8 family) { - bool result = FALSE; - int i, max; + if (family == FILTER_TYPE_IPV6) { + if (CHELSIO_CHIP_VERSION(adap->params.chip) < CHELSIO_T6) + return 4; - /* IPv6 requires four slots and IPv4 requires only 1 slot. - * Ensure, there's enough slots available. - */ - max = family == FILTER_TYPE_IPV6 ? fidx + 3 : fidx; + return 2; + } + + return 1; +} + +/** + * Check if entries are already filled. + */ +bool cxgbe_is_filter_set(struct tid_info *t, u32 fidx, u8 nentries) +{ + bool result = FALSE; + u32 i; + /* Ensure there's enough slots available. */ t4_os_lock(&t->ftid_lock); - for (i = fidx; i <= max; i++) { + for (i = fidx; i < fidx + nentries; i++) { if (rte_bitmap_get(t->ftid_bmap, i)) { result = TRUE; break; @@ -237,17 +249,18 @@ bool cxgbe_is_filter_set(struct tid_info *t, int fidx, int family) } /** - * Allocate a available free entry + * Allocate available free entries. */ -int cxgbe_alloc_ftid(struct adapter *adap, unsigned int family) +int cxgbe_alloc_ftid(struct adapter *adap, u8 nentries) { struct tid_info *t = &adap->tids; int pos; int size = t->nftids; t4_os_lock(&t->ftid_lock); - if (family == FILTER_TYPE_IPV6) - pos = cxgbe_bitmap_find_free_region(t->ftid_bmap, size, 4); + if (nentries > 1) + pos = cxgbe_bitmap_find_free_region(t->ftid_bmap, size, + nentries); else pos = cxgbe_find_first_zero_bit(t->ftid_bmap, size); t4_os_unlock(&t->ftid_lock); @@ -565,7 +578,7 @@ static int cxgbe_set_hash_filter(struct rte_eth_dev *dev, if (atid < 0) goto out_err; - if (f->fs.type) { + if (f->fs.type == FILTER_TYPE_IPV6) { /* IPv6 hash filter */ f->clipt = cxgbe_clip_alloc(f->dev, (u32 *)&f->fs.val.lip); if (!f->clipt) @@ -804,44 +817,34 @@ out: } /** - * Set the corresponding entry in the bitmap. 4 slots are - * marked for IPv6, whereas only 1 slot is marked for IPv4. + * Set the corresponding entries in the bitmap. */ -static int cxgbe_set_ftid(struct tid_info *t, int fidx, int family) +static int cxgbe_set_ftid(struct tid_info *t, u32 fidx, u8 nentries) { + u32 i; + t4_os_lock(&t->ftid_lock); if (rte_bitmap_get(t->ftid_bmap, fidx)) { t4_os_unlock(&t->ftid_lock); return -EBUSY; } - if (family == FILTER_TYPE_IPV4) { - rte_bitmap_set(t->ftid_bmap, fidx); - } else { - rte_bitmap_set(t->ftid_bmap, fidx); - rte_bitmap_set(t->ftid_bmap, fidx + 1); - rte_bitmap_set(t->ftid_bmap, fidx + 2); - rte_bitmap_set(t->ftid_bmap, fidx + 3); - } + for (i = fidx; i < fidx + nentries; i++) + rte_bitmap_set(t->ftid_bmap, i); t4_os_unlock(&t->ftid_lock); return 0; } /** - * Clear the corresponding entry in the bitmap. 4 slots are - * cleared for IPv6, whereas only 1 slot is cleared for IPv4. + * Clear the corresponding entries in the bitmap. */ -static void cxgbe_clear_ftid(struct tid_info *t, int fidx, int family) +static void cxgbe_clear_ftid(struct tid_info *t, u32 fidx, u8 nentries) { + u32 i; + t4_os_lock(&t->ftid_lock); - if (family == FILTER_TYPE_IPV4) { - rte_bitmap_clear(t->ftid_bmap, fidx); - } else { - rte_bitmap_clear(t->ftid_bmap, fidx); - rte_bitmap_clear(t->ftid_bmap, fidx + 1); - rte_bitmap_clear(t->ftid_bmap, fidx + 2); - rte_bitmap_clear(t->ftid_bmap, fidx + 3); - } + for (i = fidx; i < fidx + nentries; i++) + rte_bitmap_clear(t->ftid_bmap, i); t4_os_unlock(&t->ftid_lock); } @@ -859,6 +862,7 @@ int cxgbe_del_filter(struct rte_eth_dev *dev, unsigned int filter_id, struct adapter *adapter = pi->adapter; struct filter_entry *f; unsigned int chip_ver; + u8 nentries; int ret; if (is_hashfilter(adapter) && fs->cap) @@ -869,24 +873,25 @@ int cxgbe_del_filter(struct rte_eth_dev *dev, unsigned int filter_id, chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip); - ret = cxgbe_is_filter_set(&adapter->tids, filter_id, fs->type); - if (!ret) { - dev_warn(adap, "%s: could not find filter entry: %u\n", - __func__, filter_id); - return -EINVAL; - } - /* - * Ensure filter id is aligned on the 2 slot boundary for T6, + * Ensure IPv6 filter id is aligned on the 2 slot boundary for T6, * and 4 slot boundary for cards below T6. */ - if (fs->type) { + if (fs->type == FILTER_TYPE_IPV6) { if (chip_ver < CHELSIO_T6) filter_id &= ~(0x3); else filter_id &= ~(0x1); } + nentries = cxgbe_filter_slots(adapter, fs->type); + ret = cxgbe_is_filter_set(&adapter->tids, filter_id, nentries); + if (!ret) { + dev_warn(adap, "%s: could not find filter entry: %u\n", + __func__, filter_id); + return -EINVAL; + } + f = &adapter->tids.ftid_tab[filter_id]; ret = writable_filter(f); if (ret) @@ -896,8 +901,7 @@ int cxgbe_del_filter(struct rte_eth_dev *dev, unsigned int filter_id, f->ctx = ctx; cxgbe_clear_ftid(&adapter->tids, f->tid - adapter->tids.ftid_base, - f->fs.type ? FILTER_TYPE_IPV6 : - FILTER_TYPE_IPV4); + nentries); return del_filter_wr(dev, filter_id); } @@ -927,10 +931,10 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, { struct port_info *pi = ethdev2pinfo(dev); struct adapter *adapter = pi->adapter; - unsigned int fidx, iq, fid_bit = 0; + unsigned int fidx, iq; struct filter_entry *f; unsigned int chip_ver; - uint8_t bitoff[16] = {0}; + u8 nentries, bitoff[16] = {0}; int ret; if (is_hashfilter(adapter) && fs->cap) @@ -945,80 +949,31 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, if (ret) return ret; - /* - * Ensure filter id is aligned on the 4 slot boundary for IPv6 - * maskfull filters. - */ - if (fs->type) - filter_id &= ~(0x3); - - ret = cxgbe_is_filter_set(&adapter->tids, filter_id, fs->type); - if (ret) - return -EBUSY; - - iq = get_filter_steerq(dev, fs); - /* * IPv6 filters occupy four slots and must be aligned on four-slot * boundaries for T5. On T6, IPv6 filters occupy two-slots and * must be aligned on two-slot boundaries. * * IPv4 filters only occupy a single slot and have no alignment - * requirements but writing a new IPv4 filter into the middle - * of an existing IPv6 filter requires clearing the old IPv6 - * filter. + * requirements. */ - if (fs->type == FILTER_TYPE_IPV4) { /* IPv4 */ - /* - * For T6, If our IPv4 filter isn't being written to a - * multiple of two filter index and there's an IPv6 - * filter at the multiple of 2 base slot, then we need - * to delete that IPv6 filter ... - * For adapters below T6, IPv6 filter occupies 4 entries. - */ + fidx = filter_id; + if (fs->type == FILTER_TYPE_IPV6) { if (chip_ver < CHELSIO_T6) - fidx = filter_id & ~0x3; + fidx &= ~(0x3); else - fidx = filter_id & ~0x1; - - if (fidx != filter_id && adapter->tids.ftid_tab[fidx].fs.type) { - f = &adapter->tids.ftid_tab[fidx]; - if (f->valid) - return -EBUSY; - } - } else { /* IPv6 */ - unsigned int max_filter_id; - - if (chip_ver < CHELSIO_T6) { - /* - * Ensure that the IPv6 filter is aligned on a - * multiple of 4 boundary. - */ - if (filter_id & 0x3) - return -EINVAL; + fidx &= ~(0x1); + } - max_filter_id = filter_id + 4; - } else { - /* - * For T6, CLIP being enabled, IPv6 filter would occupy - * 2 entries. - */ - if (filter_id & 0x1) - return -EINVAL; + if (fidx != filter_id) + return -EINVAL; - max_filter_id = filter_id + 2; - } + nentries = cxgbe_filter_slots(adapter, fs->type); + ret = cxgbe_is_filter_set(&adapter->tids, filter_id, nentries); + if (ret) + return -EBUSY; - /* - * Check all except the base overlapping IPv4 filter - * slots. - */ - for (fidx = filter_id + 1; fidx < max_filter_id; fidx++) { - f = &adapter->tids.ftid_tab[fidx]; - if (f->valid) - return -EBUSY; - } - } + iq = get_filter_steerq(dev, fs); /* * Check to make sure that provided filter index is not @@ -1029,9 +984,7 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, return -EBUSY; fidx = adapter->tids.ftid_base + filter_id; - fid_bit = filter_id; - ret = cxgbe_set_ftid(&adapter->tids, fid_bit, - fs->type ? FILTER_TYPE_IPV6 : FILTER_TYPE_IPV4); + ret = cxgbe_set_ftid(&adapter->tids, filter_id, nentries); if (ret) return ret; @@ -1041,9 +994,7 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, ret = writable_filter(f); if (ret) { /* Clear the bits we have set above */ - cxgbe_clear_ftid(&adapter->tids, fid_bit, - fs->type ? FILTER_TYPE_IPV6 : - FILTER_TYPE_IPV4); + cxgbe_clear_ftid(&adapter->tids, filter_id, nentries); return ret; } @@ -1074,17 +1025,13 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, f->ctx = ctx; f->tid = fidx; /* Save the actual tid */ ret = set_filter_wr(dev, filter_id); - if (ret) { - fid_bit = f->tid - adapter->tids.ftid_base; + if (ret) goto free_tid; - } return ret; free_tid: - cxgbe_clear_ftid(&adapter->tids, fid_bit, - fs->type ? FILTER_TYPE_IPV6 : - FILTER_TYPE_IPV4); + cxgbe_clear_ftid(&adapter->tids, filter_id, nentries); clear_filter(f); return ret; } diff --git a/drivers/net/cxgbe/cxgbe_filter.h b/drivers/net/cxgbe/cxgbe_filter.h index 1964730ba3..06021c8544 100644 --- a/drivers/net/cxgbe/cxgbe_filter.h +++ b/drivers/net/cxgbe/cxgbe_filter.h @@ -248,7 +248,8 @@ cxgbe_bitmap_find_free_region(struct rte_bitmap *bmap, unsigned int size, return idx; } -bool cxgbe_is_filter_set(struct tid_info *, int fidx, int family); +u8 cxgbe_filter_slots(struct adapter *adap, u8 family); +bool cxgbe_is_filter_set(struct tid_info *t, u32 fidx, u8 nentries); void cxgbe_filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl); int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, struct ch_filter_specification *fs, @@ -256,7 +257,7 @@ int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id, int cxgbe_del_filter(struct rte_eth_dev *dev, unsigned int filter_id, struct ch_filter_specification *fs, struct filter_ctx *ctx); -int cxgbe_alloc_ftid(struct adapter *adap, unsigned int family); +int cxgbe_alloc_ftid(struct adapter *adap, u8 nentries); int cxgbe_init_hash_filter(struct adapter *adap); void cxgbe_hash_filter_rpl(struct adapter *adap, const struct cpl_act_open_rpl *rpl); diff --git a/drivers/net/cxgbe/cxgbe_flow.c b/drivers/net/cxgbe/cxgbe_flow.c index 848c61f02a..8a5d06ff3d 100644 --- a/drivers/net/cxgbe/cxgbe_flow.c +++ b/drivers/net/cxgbe/cxgbe_flow.c @@ -304,12 +304,15 @@ static int cxgbe_validate_fidxondel(struct filter_entry *f, unsigned int fidx) { struct adapter *adap = ethdev2adap(f->dev); struct ch_filter_specification fs = f->fs; + u8 nentries; if (fidx >= adap->tids.nftids) { dev_err(adap, "invalid flow index %d.\n", fidx); return -EINVAL; } - if (!cxgbe_is_filter_set(&adap->tids, fidx, fs.type)) { + + nentries = cxgbe_filter_slots(adap, fs.type); + if (!cxgbe_is_filter_set(&adap->tids, fidx, nentries)) { dev_err(adap, "Already free fidx:%d f:%p\n", fidx, f); return -EINVAL; } @@ -321,10 +324,14 @@ static int cxgbe_validate_fidxonadd(struct ch_filter_specification *fs, struct adapter *adap, unsigned int fidx) { - if (cxgbe_is_filter_set(&adap->tids, fidx, fs->type)) { + u8 nentries; + + nentries = cxgbe_filter_slots(adap, fs->type); + if (cxgbe_is_filter_set(&adap->tids, fidx, nentries)) { dev_err(adap, "filter index: %d is busy.\n", fidx); return -EBUSY; } + if (fidx >= adap->tids.nftids) { dev_err(adap, "filter index (%u) >= max(%u)\n", fidx, adap->tids.nftids); @@ -351,9 +358,11 @@ static int cxgbe_get_fidx(struct rte_flow *flow, unsigned int *fidx) /* For tcam get the next available slot, if default value specified */ if (flow->fidx == FILTER_ID_MAX) { + u8 nentries; int idx; - idx = cxgbe_alloc_ftid(adap, fs->type); + nentries = cxgbe_filter_slots(adap, fs->type); + idx = cxgbe_alloc_ftid(adap, nentries); if (idx < 0) { dev_err(adap, "unable to get a filter index in tcam\n"); return -ENOMEM;