net/cxgbe: add control queue to communicate filter requests
authorShagun Agrawal <shaguna@chelsio.com>
Fri, 8 Jun 2018 17:58:13 +0000 (23:28 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 14 Jun 2018 17:27:50 +0000 (19:27 +0200)
Add control queue to communicate filter creation/deletion requests
with firmware. This API will be used by subsequent patches.

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/base/adapter.h
drivers/net/cxgbe/base/common.h
drivers/net/cxgbe/base/t4_hw.c
drivers/net/cxgbe/base/t4fw_interface.h
drivers/net/cxgbe/cxgbe.h
drivers/net/cxgbe/cxgbe_ethdev.c
drivers/net/cxgbe/cxgbe_main.c
drivers/net/cxgbe/sge.c

index f3434d2..9a66a4a 100644 (file)
@@ -19,6 +19,7 @@
 
 enum {
        MAX_ETH_QSETS = 64,           /* # of Ethernet Tx/Rx queue sets */
+       MAX_CTRL_QUEUES = NCHAN,      /* # of control Tx queues */
 };
 
 struct adapter;
@@ -256,10 +257,20 @@ struct sge_eth_txq {                   /* state for an SGE Ethernet Tx queue */
        unsigned int flags;            /* flags for state of the queue */
 } __rte_cache_aligned;
 
+struct sge_ctrl_txq {                /* State for an SGE control Tx queue */
+       struct sge_txq q;            /* txq */
+       struct adapter *adapter;     /* adapter associated with this queue */
+       rte_spinlock_t ctrlq_lock;   /* control queue lock */
+       u8 full;                     /* the Tx ring is full */
+       u64 txp;                     /* number of transmits */
+       struct rte_mempool *mb_pool; /* mempool to generate ctrl pkts */
+} __rte_cache_aligned;
+
 struct sge {
        struct sge_eth_txq ethtxq[MAX_ETH_QSETS];
        struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
        struct sge_rspq fw_evtq __rte_cache_aligned;
+       struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES];
 
        u16 max_ethqsets;           /* # of available Ethernet queue sets */
        u32 stat_len;               /* length of status page at ring end */
@@ -720,6 +731,7 @@ void t4_sge_tx_monitor_start(struct adapter *adap);
 void t4_sge_tx_monitor_stop(struct adapter *adap);
 int t4_eth_xmit(struct sge_eth_txq *txq, struct rte_mbuf *mbuf,
                uint16_t nb_pkts);
+int t4_mgmt_tx(struct sge_ctrl_txq *txq, struct rte_mbuf *mbuf);
 int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
                     const struct pkt_gl *gl);
 int t4_sge_init(struct adapter *adap);
@@ -727,6 +739,9 @@ int t4vf_sge_init(struct adapter *adap);
 int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
                         struct rte_eth_dev *eth_dev, uint16_t queue_id,
                         unsigned int iqid, int socket_id);
+int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
+                         struct rte_eth_dev *eth_dev, uint16_t queue_id,
+                         unsigned int iqid, int socket_id);
 int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *rspq, bool fwevtq,
                     struct rte_eth_dev *eth_dev, int intr_idx,
                     struct sge_fl *fl, rspq_handler_t handler,
index 155a302..c80304b 100644 (file)
@@ -378,6 +378,8 @@ int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
               unsigned int fl0id, unsigned int fl1id);
 int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
                   unsigned int vf, unsigned int eqid);
+int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
+                   unsigned int vf, unsigned int eqid);
 
 static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
 {
index e5ef73b..c146c91 100644 (file)
@@ -4490,6 +4490,31 @@ static void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
        }
 }
 
+/**
+ * t4_ctrl_eq_free - free a control egress queue
+ * @adap: the adapter
+ * @mbox: mailbox to use for the FW command
+ * @pf: the PF owning the queue
+ * @vf: the VF owning the queue
+ * @eqid: egress queue id
+ *
+ * Frees a control egress queue.
+ */
+int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
+                   unsigned int vf, unsigned int eqid)
+{
+       struct fw_eq_ctrl_cmd c;
+
+       memset(&c, 0, sizeof(c));
+       c.op_to_vfn = cpu_to_be32(V_FW_CMD_OP(FW_EQ_CTRL_CMD) |
+                                 F_FW_CMD_REQUEST | F_FW_CMD_EXEC |
+                                 V_FW_EQ_CTRL_CMD_PFN(pf) |
+                                 V_FW_EQ_CTRL_CMD_VFN(vf));
+       c.alloc_to_len16 = cpu_to_be32(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
+       c.cmpliqid_eqid = cpu_to_be32(V_FW_EQ_CTRL_CMD_EQID(eqid));
+       return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
+}
+
 /**
  * t4_handle_fw_rpl - process a FW reply message
  * @adap: the adapter
index 95b2aec..44b6f6d 100644 (file)
@@ -178,6 +178,7 @@ enum fw_cmd_opcodes {
        FW_PFVF_CMD                    = 0x09,
        FW_IQ_CMD                      = 0x10,
        FW_EQ_ETH_CMD                  = 0x12,
+       FW_EQ_CTRL_CMD                 = 0x13,
        FW_VI_CMD                      = 0x14,
        FW_VI_MAC_CMD                  = 0x15,
        FW_VI_RXMODE_CMD               = 0x16,
@@ -960,6 +961,75 @@ struct fw_eq_eth_cmd {
 #define G_FW_EQ_ETH_CMD_VIID(x)        \
        (((x) >> S_FW_EQ_ETH_CMD_VIID) & M_FW_EQ_ETH_CMD_VIID)
 
+struct fw_eq_ctrl_cmd {
+       __be32 op_to_vfn;
+       __be32 alloc_to_len16;
+       __be32 cmpliqid_eqid;
+       __be32 physeqid_pkd;
+       __be32 fetchszm_to_iqid;
+       __be32 dcaen_to_eqsize;
+       __be64 eqaddr;
+};
+
+#define S_FW_EQ_CTRL_CMD_PFN           8
+#define V_FW_EQ_CTRL_CMD_PFN(x)                ((x) << S_FW_EQ_CTRL_CMD_PFN)
+
+#define S_FW_EQ_CTRL_CMD_VFN           0
+#define V_FW_EQ_CTRL_CMD_VFN(x)                ((x) << S_FW_EQ_CTRL_CMD_VFN)
+
+#define S_FW_EQ_CTRL_CMD_ALLOC         31
+#define V_FW_EQ_CTRL_CMD_ALLOC(x)      ((x) << S_FW_EQ_CTRL_CMD_ALLOC)
+#define F_FW_EQ_CTRL_CMD_ALLOC         V_FW_EQ_CTRL_CMD_ALLOC(1U)
+
+#define S_FW_EQ_CTRL_CMD_FREE          30
+#define V_FW_EQ_CTRL_CMD_FREE(x)       ((x) << S_FW_EQ_CTRL_CMD_FREE)
+#define F_FW_EQ_CTRL_CMD_FREE          V_FW_EQ_CTRL_CMD_FREE(1U)
+
+#define S_FW_EQ_CTRL_CMD_EQSTART       28
+#define V_FW_EQ_CTRL_CMD_EQSTART(x)    ((x) << S_FW_EQ_CTRL_CMD_EQSTART)
+#define F_FW_EQ_CTRL_CMD_EQSTART       V_FW_EQ_CTRL_CMD_EQSTART(1U)
+
+#define S_FW_EQ_CTRL_CMD_CMPLIQID      20
+#define V_FW_EQ_CTRL_CMD_CMPLIQID(x)   ((x) << S_FW_EQ_CTRL_CMD_CMPLIQID)
+
+#define S_FW_EQ_CTRL_CMD_EQID          0
+#define M_FW_EQ_CTRL_CMD_EQID          0xfffff
+#define V_FW_EQ_CTRL_CMD_EQID(x)       ((x) << S_FW_EQ_CTRL_CMD_EQID)
+#define G_FW_EQ_CTRL_CMD_EQID(x)       \
+       (((x) >> S_FW_EQ_CTRL_CMD_EQID) & M_FW_EQ_CTRL_CMD_EQID)
+
+#define S_FW_EQ_CTRL_CMD_PHYSEQID       0
+#define M_FW_EQ_CTRL_CMD_PHYSEQID       0xfffff
+#define V_FW_EQ_CTRL_CMD_PHYSEQID(x)    ((x) << S_FW_EQ_CTRL_CMD_PHYSEQID)
+#define G_FW_EQ_CTRL_CMD_PHYSEQID(x)    \
+       (((x) >> S_FW_EQ_CTRL_CMD_PHYSEQID) & M_FW_EQ_CTRL_CMD_PHYSEQID)
+
+#define S_FW_EQ_CTRL_CMD_FETCHRO       22
+#define V_FW_EQ_CTRL_CMD_FETCHRO(x)    ((x) << S_FW_EQ_CTRL_CMD_FETCHRO)
+#define F_FW_EQ_CTRL_CMD_FETCHRO       V_FW_EQ_CTRL_CMD_FETCHRO(1U)
+
+#define S_FW_EQ_CTRL_CMD_HOSTFCMODE    20
+#define M_FW_EQ_CTRL_CMD_HOSTFCMODE    0x3
+#define V_FW_EQ_CTRL_CMD_HOSTFCMODE(x) ((x) << S_FW_EQ_CTRL_CMD_HOSTFCMODE)
+
+#define S_FW_EQ_CTRL_CMD_PCIECHN       16
+#define V_FW_EQ_CTRL_CMD_PCIECHN(x)    ((x) << S_FW_EQ_CTRL_CMD_PCIECHN)
+
+#define S_FW_EQ_CTRL_CMD_IQID          0
+#define V_FW_EQ_CTRL_CMD_IQID(x)       ((x) << S_FW_EQ_CTRL_CMD_IQID)
+
+#define S_FW_EQ_CTRL_CMD_FBMIN         23
+#define V_FW_EQ_CTRL_CMD_FBMIN(x)      ((x) << S_FW_EQ_CTRL_CMD_FBMIN)
+
+#define S_FW_EQ_CTRL_CMD_FBMAX         20
+#define V_FW_EQ_CTRL_CMD_FBMAX(x)      ((x) << S_FW_EQ_CTRL_CMD_FBMAX)
+
+#define S_FW_EQ_CTRL_CMD_CIDXFTHRESH   16
+#define V_FW_EQ_CTRL_CMD_CIDXFTHRESH(x)        ((x) << S_FW_EQ_CTRL_CMD_CIDXFTHRESH)
+
+#define S_FW_EQ_CTRL_CMD_EQSIZE                0
+#define V_FW_EQ_CTRL_CMD_EQSIZE(x)     ((x) << S_FW_EQ_CTRL_CMD_EQSIZE)
+
 enum fw_vi_func {
        FW_VI_FUNC_ETH,
 };
index e4a5256..44f5934 100644 (file)
@@ -42,6 +42,7 @@ int link_start(struct port_info *pi);
 void init_rspq(struct adapter *adap, struct sge_rspq *q, unsigned int us,
               unsigned int cnt, unsigned int size, unsigned int iqe_size);
 int setup_sge_fwevtq(struct adapter *adapter);
+int setup_sge_ctrl_txq(struct adapter *adapter);
 void cfg_queues(struct rte_eth_dev *eth_dev);
 int cfg_queue_count(struct rte_eth_dev *eth_dev);
 int init_rss(struct adapter *adap);
index 1adb8e4..713dc8f 100644 (file)
@@ -365,6 +365,9 @@ int cxgbe_dev_configure(struct rte_eth_dev *eth_dev)
                if (err)
                        return err;
                adapter->flags |= FW_QUEUE_BOUND;
+               err = setup_sge_ctrl_txq(adapter);
+               if (err)
+                       return err;
        }
 
        err = cfg_queue_count(eth_dev);
index 9880257..5416800 100644 (file)
@@ -94,6 +94,47 @@ out:
        return 0;
 }
 
+/**
+ * Setup sge control queues to pass control information.
+ */
+int setup_sge_ctrl_txq(struct adapter *adapter)
+{
+       struct sge *s = &adapter->sge;
+       int err = 0, i = 0;
+
+       for_each_port(adapter, i) {
+               char name[RTE_ETH_NAME_MAX_LEN];
+               struct sge_ctrl_txq *q = &s->ctrlq[i];
+
+               q->q.size = 1024;
+               err = t4_sge_alloc_ctrl_txq(adapter, q,
+                                           adapter->eth_dev,  i,
+                                           s->fw_evtq.cntxt_id,
+                                           rte_socket_id());
+               if (err) {
+                       dev_err(adapter, "Failed to alloc ctrl txq. Err: %d",
+                               err);
+                       goto out;
+               }
+               snprintf(name, sizeof(name), "cxgbe_ctrl_pool_%d", i);
+               q->mb_pool = rte_pktmbuf_pool_create(name, s->ctrlq[i].q.size,
+                                                    RTE_CACHE_LINE_SIZE,
+                                                    RTE_MBUF_PRIV_ALIGN,
+                                                    RTE_MBUF_DEFAULT_BUF_SIZE,
+                                                    SOCKET_ID_ANY);
+               if (!q->mb_pool) {
+                       dev_err(adapter, "Can't create ctrl pool for port: %d",
+                               i);
+                       err = -ENOMEM;
+                       goto out;
+               }
+       }
+       return 0;
+out:
+       t4_free_sge_resources(adapter);
+       return err;
+}
+
 int setup_sge_fwevtq(struct adapter *adapter)
 {
        struct sge *s = &adapter->sge;
index b5d3611..357b485 100644 (file)
@@ -54,6 +54,11 @@ static inline void ship_tx_pkt_coalesce_wr(struct adapter *adap,
  */
 #define MAX_IMM_TX_PKT_LEN 256
 
+/*
+ * Max size of a WR sent through a control Tx queue.
+ */
+#define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN
+
 /*
  * Rx buffer sizes for "usembufs" Free List buffers (one ingress packet
  * per mbuf buffer).  We currently only support two sizes for 1500- and
@@ -1299,6 +1304,126 @@ out_free:
        return 0;
 }
 
+/**
+ * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ * @q: the SGE control Tx queue
+ *
+ * This is a variant of reclaim_completed_tx() that is used for Tx queues
+ * that send only immediate data (presently just the control queues) and
+ * thus do not have any mbufs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+       int hw_cidx = ntohs(q->stat->cidx);
+       int reclaim = hw_cidx - q->cidx;
+
+       if (reclaim < 0)
+               reclaim += q->size;
+
+       q->in_use -= reclaim;
+       q->cidx = hw_cidx;
+}
+
+/**
+ * is_imm - check whether a packet can be sent as immediate data
+ * @mbuf: the packet
+ *
+ * Returns true if a packet can be sent as a WR with immediate data.
+ */
+static inline int is_imm(const struct rte_mbuf *mbuf)
+{
+       return mbuf->pkt_len <= MAX_CTRL_WR_LEN;
+}
+
+/**
+ * inline_tx_mbuf: inline a packet's data into TX descriptors
+ * @q: the TX queue where the packet will be inlined
+ * @from: pointer to data portion of packet
+ * @to: pointer after cpl where data has to be inlined
+ * @len: length of data to inline
+ *
+ * Inline a packet's contents directly to TX descriptors, starting at
+ * the given position within the TX DMA ring.
+ * Most of the complexity of this operation is dealing with wrap arounds
+ * in the middle of the packet we want to inline.
+ */
+static void inline_tx_mbuf(const struct sge_txq *q, caddr_t from, caddr_t *to,
+                          int len)
+{
+       int left = RTE_PTR_DIFF(q->stat, *to);
+
+       if (likely((uintptr_t)*to + len <= (uintptr_t)q->stat)) {
+               rte_memcpy(*to, from, len);
+               *to = RTE_PTR_ADD(*to, len);
+       } else {
+               rte_memcpy(*to, from, left);
+               from = RTE_PTR_ADD(from, left);
+               left = len - left;
+               rte_memcpy((void *)q->desc, from, left);
+               *to = RTE_PTR_ADD((void *)q->desc, left);
+       }
+}
+
+/**
+ * ctrl_xmit - send a packet through an SGE control Tx queue
+ * @q: the control queue
+ * @mbuf: the packet
+ *
+ * Send a packet through an SGE control Tx queue.  Packets sent through
+ * a control queue must fit entirely as immediate data.
+ */
+static int ctrl_xmit(struct sge_ctrl_txq *q, struct rte_mbuf *mbuf)
+{
+       unsigned int ndesc;
+       struct fw_wr_hdr *wr;
+       caddr_t dst;
+
+       if (unlikely(!is_imm(mbuf))) {
+               WARN_ON(1);
+               rte_pktmbuf_free(mbuf);
+               return -1;
+       }
+
+       reclaim_completed_tx_imm(&q->q);
+       ndesc = DIV_ROUND_UP(mbuf->pkt_len, sizeof(struct tx_desc));
+       t4_os_lock(&q->ctrlq_lock);
+
+       q->full = txq_avail(&q->q) < ndesc ? 1 : 0;
+       if (unlikely(q->full)) {
+               t4_os_unlock(&q->ctrlq_lock);
+               return -1;
+       }
+
+       wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx];
+       dst = (void *)wr;
+       inline_tx_mbuf(&q->q, rte_pktmbuf_mtod(mbuf, caddr_t),
+                      &dst, mbuf->data_len);
+
+       txq_advance(&q->q, ndesc);
+       if (unlikely(txq_avail(&q->q) < 64))
+               wr->lo |= htonl(F_FW_WR_EQUEQ);
+
+       q->txp++;
+
+       ring_tx_db(q->adapter, &q->q);
+       t4_os_unlock(&q->ctrlq_lock);
+
+       rte_pktmbuf_free(mbuf);
+       return 0;
+}
+
+/**
+ * t4_mgmt_tx - send a management message
+ * @q: the control queue
+ * @mbuf: the packet containing the management message
+ *
+ * Send a management message through control queue.
+ */
+int t4_mgmt_tx(struct sge_ctrl_txq *q, struct rte_mbuf *mbuf)
+{
+       return ctrl_xmit(q, mbuf);
+}
+
 /**
  * alloc_ring - allocate resources for an SGE descriptor ring
  * @dev: the PCI device's core device
@@ -2080,6 +2205,64 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
        return 0;
 }
 
+int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
+                         struct rte_eth_dev *eth_dev, uint16_t queue_id,
+                         unsigned int iqid, int socket_id)
+{
+       int ret, nentries;
+       struct fw_eq_ctrl_cmd c;
+       struct sge *s = &adap->sge;
+       struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
+       char z_name[RTE_MEMZONE_NAMESIZE];
+       char z_name_sw[RTE_MEMZONE_NAMESIZE];
+
+       /* Add status entries */
+       nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
+
+       snprintf(z_name, sizeof(z_name), "%s_%s_%d_%d",
+                eth_dev->device->driver->name, "ctrl_tx_ring",
+                eth_dev->data->port_id, queue_id);
+       snprintf(z_name_sw, sizeof(z_name_sw), "%s_sw_ring", z_name);
+
+       txq->q.desc = alloc_ring(txq->q.size, sizeof(struct tx_desc),
+                                0, &txq->q.phys_addr,
+                                NULL, 0, queue_id,
+                                socket_id, z_name, z_name_sw);
+       if (!txq->q.desc)
+               return -ENOMEM;
+
+       memset(&c, 0, sizeof(c));
+       c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST |
+                           F_FW_CMD_WRITE | F_FW_CMD_EXEC |
+                           V_FW_EQ_CTRL_CMD_PFN(adap->pf) |
+                           V_FW_EQ_CTRL_CMD_VFN(0));
+       c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_ALLOC |
+                                F_FW_EQ_CTRL_CMD_EQSTART | (sizeof(c) / 16));
+       c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_CMPLIQID(0));
+       c.physeqid_pkd = htonl(0);
+       c.fetchszm_to_iqid =
+               htonl(V_FW_EQ_CTRL_CMD_HOSTFCMODE(X_HOSTFCMODE_NONE) |
+                     V_FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) |
+                     F_FW_EQ_CTRL_CMD_FETCHRO | V_FW_EQ_CTRL_CMD_IQID(iqid));
+       c.dcaen_to_eqsize =
+               htonl(V_FW_EQ_CTRL_CMD_FBMIN(X_FETCHBURSTMIN_64B) |
+                     V_FW_EQ_CTRL_CMD_FBMAX(X_FETCHBURSTMAX_512B) |
+                     V_FW_EQ_CTRL_CMD_EQSIZE(nentries));
+       c.eqaddr = cpu_to_be64(txq->q.phys_addr);
+
+       ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c);
+       if (ret) {
+               txq->q.desc = NULL;
+               return ret;
+       }
+
+       init_txq(adap, &txq->q, G_FW_EQ_CTRL_CMD_EQID(ntohl(c.cmpliqid_eqid)),
+                G_FW_EQ_CTRL_CMD_EQID(ntohl(c. physeqid_pkd)));
+       txq->adapter = adap;
+       txq->full = 0;
+       return 0;
+}
+
 static void free_txq(struct sge_txq *q)
 {
        q->cntxt_id = 0;
@@ -2174,7 +2357,7 @@ void t4_sge_tx_monitor_stop(struct adapter *adap)
  */
 void t4_free_sge_resources(struct adapter *adap)
 {
-       int i;
+       unsigned int i;
        struct sge_eth_rxq *rxq = &adap->sge.ethrxq[0];
        struct sge_eth_txq *txq = &adap->sge.ethtxq[0];
 
@@ -2191,6 +2374,18 @@ void t4_free_sge_resources(struct adapter *adap)
                }
        }
 
+       /* clean up control Tx queues */
+       for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) {
+               struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i];
+
+               if (cq->q.desc) {
+                       reclaim_completed_tx_imm(&cq->q);
+                       t4_ctrl_eq_free(adap, adap->mbox, adap->pf, 0,
+                                       cq->q.cntxt_id);
+                       free_txq(&cq->q);
+               }
+       }
+
        if (adap->sge.fw_evtq.desc)
                free_rspq_fl(adap, &adap->sge.fw_evtq, NULL);
 }