217d181626
Coverity issue: 302872
Fixes: 3f2c1e209c
("net/cxgbe: add Compressed Local IP region")
Signed-off-by: Shagun Agrawal <shaguna@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
194 lines
4.4 KiB
C
194 lines
4.4 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2018 Chelsio Communications.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "clip_tbl.h"
|
|
|
|
/**
|
|
* Allocate clip entry in HW with associated IPV4/IPv6 address
|
|
*/
|
|
static int clip6_get_mbox(const struct rte_eth_dev *dev, const u32 *lip)
|
|
{
|
|
struct adapter *adap = ethdev2adap(dev);
|
|
struct fw_clip_cmd c;
|
|
u64 hi = ((u64)lip[1]) << 32 | lip[0];
|
|
u64 lo = ((u64)lip[3]) << 32 | lip[2];
|
|
|
|
memset(&c, 0, sizeof(c));
|
|
c.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CLIP_CMD) |
|
|
F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
|
|
c.alloc_to_len16 = cpu_to_be32(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
|
|
c.ip_hi = hi;
|
|
c.ip_lo = lo;
|
|
return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
|
|
}
|
|
|
|
/**
|
|
* Delete clip entry in HW having the associated IPV4/IPV6 address
|
|
*/
|
|
static int clip6_release_mbox(const struct rte_eth_dev *dev, const u32 *lip)
|
|
{
|
|
struct adapter *adap = ethdev2adap(dev);
|
|
struct fw_clip_cmd c;
|
|
u64 hi = ((u64)lip[1]) << 32 | lip[0];
|
|
u64 lo = ((u64)lip[3]) << 32 | lip[2];
|
|
|
|
memset(&c, 0, sizeof(c));
|
|
c.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CLIP_CMD) |
|
|
F_FW_CMD_REQUEST | F_FW_CMD_READ);
|
|
c.alloc_to_len16 = cpu_to_be32(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
|
|
c.ip_hi = hi;
|
|
c.ip_lo = lo;
|
|
return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
|
|
}
|
|
|
|
/**
|
|
* cxgbe_clip_release - Release associated CLIP entry
|
|
* @ce: clip entry to release
|
|
*
|
|
* Releases ref count and frees up a clip entry from CLIP table
|
|
*/
|
|
void cxgbe_clip_release(struct rte_eth_dev *dev, struct clip_entry *ce)
|
|
{
|
|
int ret;
|
|
|
|
t4_os_lock(&ce->lock);
|
|
if (rte_atomic32_dec_and_test(&ce->refcnt)) {
|
|
ret = clip6_release_mbox(dev, ce->addr);
|
|
if (ret)
|
|
dev_debug(adap, "CLIP FW DEL CMD failed: %d", ret);
|
|
}
|
|
t4_os_unlock(&ce->lock);
|
|
}
|
|
|
|
/**
|
|
* find_or_alloc_clipe - Find/Allocate a free CLIP entry
|
|
* @c: CLIP table
|
|
* @lip: IPV4/IPV6 address to compare/add
|
|
* Returns pointer to the IPV4/IPV6 entry found/created
|
|
*
|
|
* Finds/Allocates an CLIP entry to be used for a filter rule.
|
|
*/
|
|
static struct clip_entry *find_or_alloc_clipe(struct clip_tbl *c,
|
|
const u32 *lip)
|
|
{
|
|
struct clip_entry *end, *e;
|
|
struct clip_entry *first_free = NULL;
|
|
unsigned int clipt_size = c->clipt_size;
|
|
|
|
for (e = &c->cl_list[0], end = &c->cl_list[clipt_size]; e != end; ++e) {
|
|
if (rte_atomic32_read(&e->refcnt) == 0) {
|
|
if (!first_free)
|
|
first_free = e;
|
|
} else {
|
|
if (memcmp(lip, e->addr, sizeof(e->addr)) == 0)
|
|
goto exists;
|
|
}
|
|
}
|
|
|
|
if (first_free) {
|
|
e = first_free;
|
|
goto exists;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
exists:
|
|
return e;
|
|
}
|
|
|
|
static struct clip_entry *t4_clip_alloc(struct rte_eth_dev *dev,
|
|
u32 *lip, u8 v6)
|
|
{
|
|
struct adapter *adap = ethdev2adap(dev);
|
|
struct clip_tbl *ctbl = adap->clipt;
|
|
struct clip_entry *ce;
|
|
int ret = 0;
|
|
|
|
if (!ctbl)
|
|
return NULL;
|
|
|
|
t4_os_write_lock(&ctbl->lock);
|
|
ce = find_or_alloc_clipe(ctbl, lip);
|
|
if (ce) {
|
|
t4_os_lock(&ce->lock);
|
|
if (!rte_atomic32_read(&ce->refcnt)) {
|
|
rte_memcpy(ce->addr, lip, sizeof(ce->addr));
|
|
if (v6) {
|
|
ce->type = FILTER_TYPE_IPV6;
|
|
rte_atomic32_set(&ce->refcnt, 1);
|
|
ret = clip6_get_mbox(dev, lip);
|
|
if (ret)
|
|
dev_debug(adap,
|
|
"CLIP FW ADD CMD failed: %d",
|
|
ret);
|
|
} else {
|
|
ce->type = FILTER_TYPE_IPV4;
|
|
}
|
|
} else {
|
|
rte_atomic32_inc(&ce->refcnt);
|
|
}
|
|
t4_os_unlock(&ce->lock);
|
|
}
|
|
t4_os_write_unlock(&ctbl->lock);
|
|
|
|
return ret ? NULL : ce;
|
|
}
|
|
|
|
/**
|
|
* cxgbe_clip_alloc - Allocate a IPV6 CLIP entry
|
|
* @dev: rte_eth_dev pointer
|
|
* @lip: IPV6 address to add
|
|
* Returns pointer to the CLIP entry created
|
|
*
|
|
* Allocates a IPV6 CLIP entry to be used for a filter rule.
|
|
*/
|
|
struct clip_entry *cxgbe_clip_alloc(struct rte_eth_dev *dev, u32 *lip)
|
|
{
|
|
return t4_clip_alloc(dev, lip, FILTER_TYPE_IPV6);
|
|
}
|
|
|
|
/**
|
|
* Initialize CLIP Table
|
|
*/
|
|
struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
|
|
unsigned int clipt_end)
|
|
{
|
|
unsigned int clipt_size;
|
|
struct clip_tbl *ctbl;
|
|
unsigned int i;
|
|
|
|
if (clipt_start >= clipt_end)
|
|
return NULL;
|
|
|
|
clipt_size = clipt_end - clipt_start + 1;
|
|
|
|
ctbl = t4_os_alloc(sizeof(*ctbl) +
|
|
clipt_size * sizeof(struct clip_entry));
|
|
if (!ctbl)
|
|
return NULL;
|
|
|
|
ctbl->clipt_start = clipt_start;
|
|
ctbl->clipt_size = clipt_size;
|
|
|
|
t4_os_rwlock_init(&ctbl->lock);
|
|
|
|
for (i = 0; i < ctbl->clipt_size; i++) {
|
|
t4_os_lock_init(&ctbl->cl_list[i].lock);
|
|
rte_atomic32_set(&ctbl->cl_list[i].refcnt, 0);
|
|
}
|
|
|
|
return ctbl;
|
|
}
|
|
|
|
/**
|
|
* Cleanup CLIP Table
|
|
*/
|
|
void t4_cleanup_clip_tbl(struct adapter *adap)
|
|
{
|
|
if (adap->clipt)
|
|
t4_os_free(adap->clipt);
|
|
}
|