net/cxgbe: implement flow destroy operation

Add API to construct delete filter work request to remove filter
at specified index in LE-TCAM (maskfull) region.

Signed-off-by: Shagun Agrawal <shaguna@chelsio.com>
Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
This commit is contained in:
Shagun Agrawal 2018-06-08 23:28:15 +05:30 committed by Ferruh Yigit
parent 9eb2c9a480
commit da23bc9d33
3 changed files with 169 additions and 1 deletions

View File

@ -134,6 +134,60 @@ void clear_filter(struct filter_entry *f)
memset(f, 0, sizeof(*f));
}
/**
* t4_mk_filtdelwr - create a delete filter WR
* @ftid: the filter ID
* @wr: the filter work request to populate
* @qid: ingress queue to receive the delete notification
*
* Creates a filter work request to delete the supplied filter. If @qid is
* negative the delete notification is suppressed.
*/
static void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
{
memset(wr, 0, sizeof(*wr));
wr->op_pkd = cpu_to_be32(V_FW_WR_OP(FW_FILTER_WR));
wr->len16_pkd = cpu_to_be32(V_FW_WR_LEN16(sizeof(*wr) / 16));
wr->tid_to_iq = cpu_to_be32(V_FW_FILTER_WR_TID(ftid) |
V_FW_FILTER_WR_NOREPLY(qid < 0));
wr->del_filter_to_l2tix = cpu_to_be32(F_FW_FILTER_WR_DEL_FILTER);
if (qid >= 0)
wr->rx_chan_rx_rpl_iq =
cpu_to_be16(V_FW_FILTER_WR_RX_RPL_IQ(qid));
}
/**
* Create FW work request to delete the filter at a specified index
*/
static int del_filter_wr(struct rte_eth_dev *dev, unsigned int fidx)
{
struct adapter *adapter = ethdev2adap(dev);
struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
struct rte_mbuf *mbuf;
struct fw_filter_wr *fwr;
struct sge_ctrl_txq *ctrlq;
unsigned int port_id = ethdev2pinfo(dev)->port_id;
ctrlq = &adapter->sge.ctrlq[port_id];
mbuf = rte_pktmbuf_alloc(ctrlq->mb_pool);
if (!mbuf)
return -ENOMEM;
mbuf->data_len = sizeof(*fwr);
mbuf->pkt_len = mbuf->data_len;
fwr = rte_pktmbuf_mtod(mbuf, struct fw_filter_wr *);
t4_mk_filtdelwr(f->tid, fwr, adapter->sge.fw_evtq.abs_id);
/*
* Mark the filter as "pending" and ship off the Filter Work Request.
* When we get the Work Request Reply we'll clear the pending status.
*/
f->pending = 1;
t4_mgmt_tx(ctrlq, mbuf);
return 0;
}
int set_filter_wr(struct rte_eth_dev *dev, unsigned int fidx)
{
struct adapter *adapter = ethdev2adap(dev);
@ -244,6 +298,58 @@ static void cxgbe_clear_ftid(struct tid_info *t, int fidx, int family)
t4_os_unlock(&t->ftid_lock);
}
/**
* Check a delete filter request for validity and send it to the hardware.
* Return 0 on success, an error number otherwise. We attach any provided
* filter operation context to the internal filter specification in order to
* facilitate signaling completion of the operation.
*/
int cxgbe_del_filter(struct rte_eth_dev *dev, unsigned int filter_id,
struct ch_filter_specification *fs,
struct filter_ctx *ctx)
{
struct port_info *pi = (struct port_info *)(dev->data->dev_private);
struct adapter *adapter = pi->adapter;
struct filter_entry *f;
int ret;
if (filter_id >= adapter->tids.nftids)
return -ERANGE;
ret = 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;
}
f = &adapter->tids.ftid_tab[filter_id];
ret = writable_filter(f);
if (ret)
return ret;
if (f->valid) {
f->ctx = ctx;
cxgbe_clear_ftid(&adapter->tids,
f->tid - adapter->tids.ftid_base,
f->fs.type ? FILTER_TYPE_IPV6 :
FILTER_TYPE_IPV4);
return del_filter_wr(dev, filter_id);
}
/*
* If the caller has passed in a Completion Context then we need to
* mark it as a successful completion so they don't stall waiting
* for it.
*/
if (ctx) {
ctx->result = 0;
t4_complete(&ctx->completion);
}
return 0;
}
/**
* Check a Chelsio Filter Request for validity, convert it into our internal
* format and send it to the hardware. Return 0 on success, an error number
@ -415,6 +521,14 @@ void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
ctx->tid = f->tid;
ctx->result = 0;
}
} else if (ret == FW_FILTER_WR_FLT_DELETED) {
/*
* Clear the filter when we get confirmation from the
* hardware that the filter has been deleted.
*/
clear_filter(f);
if (ctx)
ctx->result = 0;
} else {
/*
* Something went wrong. Issue a warning about the

View File

@ -215,6 +215,9 @@ int writable_filter(struct filter_entry *f);
int cxgbe_set_filter(struct rte_eth_dev *dev, unsigned int filter_id,
struct ch_filter_specification *fs,
struct filter_ctx *ctx);
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 validate_filter(struct adapter *adap, struct ch_filter_specification *fs);
#endif /* _CXGBE_FILTER_H_ */

View File

@ -471,6 +471,57 @@ cxgbe_flow_create(struct rte_eth_dev *dev,
return flow;
}
static int __cxgbe_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
{
struct adapter *adap = ethdev2adap(dev);
struct filter_entry *f = flow->f;
struct ch_filter_specification *fs;
struct filter_ctx ctx;
int err;
fs = &f->fs;
if (cxgbe_verify_fidx(flow, flow->fidx, 1))
return -1;
t4_init_completion(&ctx.completion);
err = cxgbe_del_filter(dev, flow->fidx, fs, &ctx);
if (err) {
dev_err(adap, "Error %d while deleting filter.\n", err);
return err;
}
/* Poll the FW for reply */
err = cxgbe_poll_for_completion(&adap->sge.fw_evtq,
CXGBE_FLOW_POLL_US,
CXGBE_FLOW_POLL_CNT,
&ctx.completion);
if (err) {
dev_err(adap, "Filter delete operation timed out (%d)\n", err);
return err;
}
if (ctx.result) {
dev_err(adap, "Hardware error %d while deleting the filter.\n",
ctx.result);
return ctx.result;
}
return 0;
}
static int
cxgbe_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
struct rte_flow_error *e)
{
int ret;
ret = __cxgbe_flow_destroy(dev, flow);
if (ret)
return rte_flow_error_set(e, ret, RTE_FLOW_ERROR_TYPE_HANDLE,
flow, "error destroying filter.");
t4_os_free(flow);
return 0;
}
static int
cxgbe_flow_validate(struct rte_eth_dev *dev,
const struct rte_flow_attr *attr,
@ -524,7 +575,7 @@ cxgbe_flow_validate(struct rte_eth_dev *dev,
static const struct rte_flow_ops cxgbe_flow_ops = {
.validate = cxgbe_flow_validate,
.create = cxgbe_flow_create,
.destroy = NULL,
.destroy = cxgbe_flow_destroy,
.flush = NULL,
.query = NULL,
.isolate = NULL,