net/liquidio: add API to setup Rx queue
authorShijith Thotton <shijith.thotton@caviumnetworks.com>
Sat, 25 Mar 2017 06:24:31 +0000 (11:54 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 4 Apr 2017 16:59:48 +0000 (18:59 +0200)
Signed-off-by: Shijith Thotton <shijith.thotton@caviumnetworks.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Derek Chickles <derek.chickles@caviumnetworks.com>
Signed-off-by: Venkat Koppula <venkat.koppula@caviumnetworks.com>
Signed-off-by: Srisivasubramanian S <ssrinivasan@caviumnetworks.com>
Signed-off-by: Mallesham Jatharakonda <mjatharakonda@oneconvergence.com>
drivers/net/liquidio/base/lio_hw_defs.h
drivers/net/liquidio/lio_ethdev.c
drivers/net/liquidio/lio_rxtx.c
drivers/net/liquidio/lio_rxtx.h
drivers/net/liquidio/lio_struct.h

index 3201dc5..35d59fd 100644 (file)
@@ -78,6 +78,8 @@ enum lio_card_type {
 
 #define LIO_DEV_RUNNING                0xc
 
+#define LIO_OQ_REFILL_THRESHOLD_CFG(cfg)                               \
+               ((cfg)->default_config->oq.refill_threshold)
 #define LIO_NUM_DEF_TX_DESCS_CFG(cfg)                                  \
                ((cfg)->default_config->num_def_tx_descs)
 
@@ -89,6 +91,7 @@ enum lio_card_type {
 #define LIO_MAX_INSTR_QUEUES(lio_dev)          CN23XX_MAX_RINGS_PER_VF
 
 #define LIO_MAX_POSSIBLE_INSTR_QUEUES          CN23XX_MAX_INPUT_QUEUES
+#define LIO_MAX_POSSIBLE_OUTPUT_QUEUES         CN23XX_MAX_OUTPUT_QUEUES
 
 #define LIO_DEVICE_NAME_LEN            32
 #define LIO_BASE_MAJOR_VERSION         1
index 194b096..a93fa4a 100644 (file)
@@ -55,6 +55,72 @@ lio_hweight64(uint64_t w)
        return (res + (res >> 32)) & 0x00000000000000FFul;
 }
 
+/**
+ * Setup our receive queue/ringbuffer. This is the
+ * queue the Octeon uses to send us packets and
+ * responses. We are given a memory pool for our
+ * packet buffers that are used to populate the receive
+ * queue.
+ *
+ * @param eth_dev
+ *    Pointer to the structure rte_eth_dev
+ * @param q_no
+ *    Queue number
+ * @param num_rx_descs
+ *    Number of entries in the queue
+ * @param socket_id
+ *    Where to allocate memory
+ * @param rx_conf
+ *    Pointer to the struction rte_eth_rxconf
+ * @param mp
+ *    Pointer to the packet pool
+ *
+ * @return
+ *    - On success, return 0
+ *    - On failure, return -1
+ */
+static int
+lio_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t q_no,
+                      uint16_t num_rx_descs, unsigned int socket_id,
+                      const struct rte_eth_rxconf *rx_conf __rte_unused,
+                      struct rte_mempool *mp)
+{
+       struct lio_device *lio_dev = LIO_DEV(eth_dev);
+       struct rte_pktmbuf_pool_private *mbp_priv;
+       uint32_t fw_mapped_oq;
+       uint16_t buf_size;
+
+       if (q_no >= lio_dev->nb_rx_queues) {
+               lio_dev_err(lio_dev, "Invalid rx queue number %u\n", q_no);
+               return -EINVAL;
+       }
+
+       lio_dev_dbg(lio_dev, "setting up rx queue %u\n", q_no);
+
+       fw_mapped_oq = lio_dev->linfo.rxpciq[q_no].s.q_no;
+
+       if ((lio_dev->droq[fw_mapped_oq]) &&
+           (num_rx_descs != lio_dev->droq[fw_mapped_oq]->max_count)) {
+               lio_dev_err(lio_dev,
+                           "Reconfiguring Rx descs not supported. Configure descs to same value %u or restart application\n",
+                           lio_dev->droq[fw_mapped_oq]->max_count);
+               return -ENOTSUP;
+       }
+
+       mbp_priv = rte_mempool_get_priv(mp);
+       buf_size = mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM;
+
+       if (lio_setup_droq(lio_dev, fw_mapped_oq, num_rx_descs, buf_size, mp,
+                          socket_id)) {
+               lio_dev_err(lio_dev, "droq allocation failed\n");
+               return -1;
+       }
+
+       eth_dev->data->rx_queues[q_no] = lio_dev->droq[fw_mapped_oq];
+
+       return 0;
+}
+
 static int lio_dev_configure(struct rte_eth_dev *eth_dev)
 {
        struct lio_device *lio_dev = LIO_DEV(eth_dev);
@@ -199,6 +265,7 @@ nic_config_fail:
 /* Define our ethernet definitions */
 static const struct eth_dev_ops liovf_eth_dev_ops = {
        .dev_configure          = lio_dev_configure,
+       .rx_queue_setup         = lio_dev_rx_queue_setup,
 };
 
 static void
index 7e2202c..942fe9b 100644 (file)
@@ -62,6 +62,174 @@ lio_dma_zone_free(struct lio_device *lio_dev, const struct rte_memzone *mz)
                lio_dev_err(lio_dev, "Memzone free Failed ret %d\n", ret);
 }
 
+/**
+ *  Frees the space for descriptor ring for the droq.
+ *
+ *  @param lio_dev     - pointer to the lio device structure
+ *  @param q_no                - droq no.
+ */
+static void
+lio_delete_droq(struct lio_device *lio_dev, uint32_t q_no)
+{
+       struct lio_droq *droq = lio_dev->droq[q_no];
+
+       lio_dev_dbg(lio_dev, "OQ[%d]\n", q_no);
+
+       rte_free(droq->recv_buf_list);
+       droq->recv_buf_list = NULL;
+       lio_dma_zone_free(lio_dev, droq->info_mz);
+       lio_dma_zone_free(lio_dev, droq->desc_ring_mz);
+
+       memset(droq, 0, LIO_DROQ_SIZE);
+}
+
+static void *
+lio_alloc_info_buffer(struct lio_device *lio_dev,
+                     struct lio_droq *droq, unsigned int socket_id)
+{
+       droq->info_mz = rte_eth_dma_zone_reserve(lio_dev->eth_dev,
+                                                "info_list", droq->q_no,
+                                                (droq->max_count *
+                                                       LIO_DROQ_INFO_SIZE),
+                                                RTE_CACHE_LINE_SIZE,
+                                                socket_id);
+
+       if (droq->info_mz == NULL)
+               return NULL;
+
+       droq->info_list_dma = droq->info_mz->phys_addr;
+       droq->info_alloc_size = droq->info_mz->len;
+       droq->info_base_addr = (size_t)droq->info_mz->addr;
+
+       return droq->info_mz->addr;
+}
+
+/**
+ *  Allocates space for the descriptor ring for the droq and
+ *  sets the base addr, num desc etc in Octeon registers.
+ *
+ * @param lio_dev      - pointer to the lio device structure
+ * @param q_no         - droq no.
+ * @param app_ctx      - pointer to application context
+ * @return Success: 0  Failure: -1
+ */
+static int
+lio_init_droq(struct lio_device *lio_dev, uint32_t q_no,
+             uint32_t num_descs, uint32_t desc_size,
+             struct rte_mempool *mpool, unsigned int socket_id)
+{
+       uint32_t c_refill_threshold;
+       uint32_t desc_ring_size;
+       struct lio_droq *droq;
+
+       lio_dev_dbg(lio_dev, "OQ[%d]\n", q_no);
+
+       droq = lio_dev->droq[q_no];
+       droq->lio_dev = lio_dev;
+       droq->q_no = q_no;
+       droq->mpool = mpool;
+
+       c_refill_threshold = LIO_OQ_REFILL_THRESHOLD_CFG(lio_dev);
+
+       droq->max_count = num_descs;
+       droq->buffer_size = desc_size;
+
+       desc_ring_size = droq->max_count * LIO_DROQ_DESC_SIZE;
+       droq->desc_ring_mz = rte_eth_dma_zone_reserve(lio_dev->eth_dev,
+                                                     "droq", q_no,
+                                                     desc_ring_size,
+                                                     RTE_CACHE_LINE_SIZE,
+                                                     socket_id);
+
+       if (droq->desc_ring_mz == NULL) {
+               lio_dev_err(lio_dev,
+                           "Output queue %d ring alloc failed\n", q_no);
+               return -1;
+       }
+
+       droq->desc_ring_dma = droq->desc_ring_mz->phys_addr;
+       droq->desc_ring = (struct lio_droq_desc *)droq->desc_ring_mz->addr;
+
+       lio_dev_dbg(lio_dev, "droq[%d]: desc_ring: virt: 0x%p, dma: %lx\n",
+                   q_no, droq->desc_ring, (unsigned long)droq->desc_ring_dma);
+       lio_dev_dbg(lio_dev, "droq[%d]: num_desc: %d\n", q_no,
+                   droq->max_count);
+
+       droq->info_list = lio_alloc_info_buffer(lio_dev, droq, socket_id);
+       if (droq->info_list == NULL) {
+               lio_dev_err(lio_dev, "Cannot allocate memory for info list.\n");
+               goto init_droq_fail;
+       }
+
+       droq->recv_buf_list = rte_zmalloc_socket("recv_buf_list",
+                                                (droq->max_count *
+                                                       LIO_DROQ_RECVBUF_SIZE),
+                                                RTE_CACHE_LINE_SIZE,
+                                                socket_id);
+       if (droq->recv_buf_list == NULL) {
+               lio_dev_err(lio_dev,
+                           "Output queue recv buf list alloc failed\n");
+               goto init_droq_fail;
+       }
+
+       droq->refill_threshold = c_refill_threshold;
+
+       rte_spinlock_init(&droq->lock);
+
+       lio_dev->io_qmask.oq |= (1ULL << q_no);
+
+       return 0;
+
+init_droq_fail:
+       lio_delete_droq(lio_dev, q_no);
+
+       return -1;
+}
+
+int
+lio_setup_droq(struct lio_device *lio_dev, int oq_no, int num_descs,
+              int desc_size, struct rte_mempool *mpool, unsigned int socket_id)
+{
+       struct lio_droq *droq;
+
+       PMD_INIT_FUNC_TRACE();
+
+       if (lio_dev->droq[oq_no]) {
+               lio_dev_dbg(lio_dev, "Droq %d in use\n", oq_no);
+               return 0;
+       }
+
+       /* Allocate the DS for the new droq. */
+       droq = rte_zmalloc_socket("ethdev RX queue", sizeof(*droq),
+                                 RTE_CACHE_LINE_SIZE, socket_id);
+       if (droq == NULL)
+               return -ENOMEM;
+
+       lio_dev->droq[oq_no] = droq;
+
+       /* Initialize the Droq */
+       if (lio_init_droq(lio_dev, oq_no, num_descs, desc_size, mpool,
+                         socket_id)) {
+               lio_dev_err(lio_dev, "Droq[%u] Initialization Failed\n", oq_no);
+               rte_free(lio_dev->droq[oq_no]);
+               lio_dev->droq[oq_no] = NULL;
+               return -ENOMEM;
+       }
+
+       lio_dev->num_oqs++;
+
+       lio_dev_dbg(lio_dev, "Total number of OQ: %d\n", lio_dev->num_oqs);
+
+       /* Send credit for octeon output queues. credits are always
+        * sent after the output queue is enabled.
+        */
+       rte_write32(lio_dev->droq[oq_no]->max_count,
+                   lio_dev->droq[oq_no]->pkts_credit_reg);
+       rte_wmb();
+
+       return 0;
+}
+
 /**
  *  lio_init_instr_queue()
  *  @param lio_dev     - pointer to the lio device structure.
index 9e2d967..05f4704 100644 (file)
 #define lio_uptime             \
        (size_t)(rte_get_timer_cycles() / rte_get_timer_hz())
 
+/** Descriptor format.
+ *  The descriptor ring is made of descriptors which have 2 64-bit values:
+ *  -# Physical (bus) address of the data buffer.
+ *  -# Physical (bus) address of a lio_droq_info structure.
+ *  The device DMA's incoming packets and its information at the address
+ *  given by these descriptor fields.
+ */
+struct lio_droq_desc {
+       /** The buffer pointer */
+       uint64_t buffer_ptr;
+
+       /** The Info pointer */
+       uint64_t info_ptr;
+};
+
+#define LIO_DROQ_DESC_SIZE     (sizeof(struct lio_droq_desc))
+
+/** Information about packet DMA'ed by Octeon.
+ *  The format of the information available at Info Pointer after Octeon
+ *  has posted a packet. Not all descriptors have valid information. Only
+ *  the Info field of the first descriptor for a packet has information
+ *  about the packet.
+ */
+struct lio_droq_info {
+       /** The Output Receive Header. */
+       union octeon_rh rh;
+
+       /** The Length of the packet. */
+       uint64_t length;
+};
+
+#define LIO_DROQ_INFO_SIZE     (sizeof(struct lio_droq_info))
+
+/** Pointer to data buffer.
+ *  Driver keeps a pointer to the data buffer that it made available to
+ *  the Octeon device. Since the descriptor ring keeps physical (bus)
+ *  addresses, this field is required for the driver to keep track of
+ *  the virtual address pointers.
+ */
+struct lio_recv_buffer {
+       /** Packet buffer, including meta data. */
+       void *buffer;
+
+       /** Data in the packet buffer. */
+       uint8_t *data;
+
+};
+
+#define LIO_DROQ_RECVBUF_SIZE  (sizeof(struct lio_recv_buffer))
+
+#define LIO_DROQ_SIZE          (sizeof(struct lio_droq))
+
 #define LIO_IQ_SEND_OK         0
 #define LIO_IQ_SEND_STOP       1
 #define LIO_IQ_SEND_FAILED     -1
@@ -458,6 +510,10 @@ lio_incr_index(uint32_t index, uint32_t count, uint32_t max)
        return index;
 }
 
+int lio_setup_droq(struct lio_device *lio_dev, int q_no, int num_descs,
+                  int desc_size, struct rte_mempool *mpool,
+                  unsigned int socket_id);
+
 /** Setup instruction queue zero for the device
  *  @param lio_dev which lio device to setup
  *
index 48c4cae..3df79e1 100644 (file)
@@ -56,6 +56,150 @@ struct lio_version {
        uint16_t reserved;
 };
 
+/** The Descriptor Ring Output Queue structure.
+ *  This structure has all the information required to implement a
+ *  DROQ.
+ */
+struct lio_droq {
+       /** A spinlock to protect access to this ring. */
+       rte_spinlock_t lock;
+
+       uint32_t q_no;
+
+       uint32_t pkt_count;
+
+       struct lio_device *lio_dev;
+
+       /** The 8B aligned descriptor ring starts at this address. */
+       struct lio_droq_desc *desc_ring;
+
+       /** Index in the ring where the driver should read the next packet */
+       uint32_t read_idx;
+
+       /** Index in the ring where Octeon will write the next packet */
+       uint32_t write_idx;
+
+       /** Index in the ring where the driver will refill the descriptor's
+        * buffer
+        */
+       uint32_t refill_idx;
+
+       /** Packets pending to be processed */
+       rte_atomic64_t pkts_pending;
+
+       /** Number of  descriptors in this ring. */
+       uint32_t max_count;
+
+       /** The number of descriptors pending refill. */
+       uint32_t refill_count;
+
+       uint32_t refill_threshold;
+
+       /** The 8B aligned info ptrs begin from this address. */
+       struct lio_droq_info *info_list;
+
+       /** The receive buffer list. This list has the virtual addresses of the
+        *  buffers.
+        */
+       struct lio_recv_buffer *recv_buf_list;
+
+       /** The size of each buffer pointed by the buffer pointer. */
+       uint32_t buffer_size;
+
+       /** Pointer to the mapped packet credit register.
+        *  Host writes number of info/buffer ptrs available to this register
+        */
+       void *pkts_credit_reg;
+
+       /** Pointer to the mapped packet sent register.
+        *  Octeon writes the number of packets DMA'ed to host memory
+        *  in this register.
+        */
+       void *pkts_sent_reg;
+
+       /** DMA mapped address of the DROQ descriptor ring. */
+       size_t desc_ring_dma;
+
+       /** Info ptr list are allocated at this virtual address. */
+       size_t info_base_addr;
+
+       /** DMA mapped address of the info list */
+       size_t info_list_dma;
+
+       /** Allocated size of info list. */
+       uint32_t info_alloc_size;
+
+       /** Memory zone **/
+       const struct rte_memzone *desc_ring_mz;
+       const struct rte_memzone *info_mz;
+       struct rte_mempool *mpool;
+};
+
+/** Receive Header */
+union octeon_rh {
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+       uint64_t rh64;
+       struct  {
+               uint64_t opcode : 4;
+               uint64_t subcode : 8;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t reserved : 17;
+               uint64_t ossp : 32; /** opcode/subcode specific parameters */
+       } r;
+       struct  {
+               uint64_t opcode : 4;
+               uint64_t subcode : 8;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t extra : 28;
+               uint64_t vlan : 12;
+               uint64_t priority : 3;
+               uint64_t csum_verified : 3; /** checksum verified. */
+               uint64_t has_hwtstamp : 1; /** Has hardware timestamp.1 = yes.*/
+               uint64_t encap_on : 1;
+               uint64_t has_hash : 1; /** Has hash (rth or rss). 1 = yes. */
+       } r_dh;
+       struct {
+               uint64_t opcode : 4;
+               uint64_t subcode : 8;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t reserved : 8;
+               uint64_t extra : 25;
+               uint64_t gmxport : 16;
+       } r_nic_info;
+#else
+       uint64_t rh64;
+       struct {
+               uint64_t ossp : 32; /** opcode/subcode specific parameters */
+               uint64_t reserved : 17;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t subcode : 8;
+               uint64_t opcode : 4;
+       } r;
+       struct {
+               uint64_t has_hash : 1; /** Has hash (rth or rss). 1 = yes. */
+               uint64_t encap_on : 1;
+               uint64_t has_hwtstamp : 1;  /** 1 = has hwtstamp */
+               uint64_t csum_verified : 3; /** checksum verified. */
+               uint64_t priority : 3;
+               uint64_t vlan : 12;
+               uint64_t extra : 28;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t subcode : 8;
+               uint64_t opcode : 4;
+       } r_dh;
+       struct {
+               uint64_t gmxport : 16;
+               uint64_t extra : 25;
+               uint64_t reserved : 8;
+               uint64_t len : 3; /** additional 64-bit words */
+               uint64_t subcode : 8;
+               uint64_t opcode : 4;
+       } r_nic_info;
+#endif
+};
+
+#define OCTEON_RH_SIZE (sizeof(union octeon_rh))
+
 /** The txpciq info passed to host from the firmware */
 union octeon_txpciq {
        uint64_t txpciq64;
@@ -380,6 +524,11 @@ struct lio_device {
        /** The singly-linked tail queues of instruction response */
        struct lio_response_list response_list;
 
+       uint32_t num_oqs;
+
+       /** The DROQ output queues  */
+       struct lio_droq *droq[LIO_MAX_POSSIBLE_OUTPUT_QUEUES];
+
        struct lio_io_enable io_qmask;
 
        struct lio_sriov_info sriov_info;