net/cxgbe: implement flow destroy operation
authorShagun Agrawal <shaguna@chelsio.com>
Fri, 8 Jun 2018 17:58:15 +0000 (23:28 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 14 Jun 2018 17:27:50 +0000 (19:27 +0200)
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>
drivers/net/cxgbe/cxgbe_filter.c
drivers/net/cxgbe/cxgbe_filter.h
drivers/net/cxgbe/cxgbe_flow.c

index d0b9cd6..daf710d 100644 (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
index 7558793..2459010 100644 (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_ */
index 188c11b..8d25dc2 100644 (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,