net/liquidio: add APIs to enable and disable IO queues
[dpdk.git] / drivers / net / liquidio / lio_rxtx.c
index 9e4da3a..63d8896 100644 (file)
@@ -40,6 +40,8 @@
 #include "lio_ethdev.h"
 #include "lio_rxtx.h"
 
+#define LIO_MAX_SG 12
+
 static void
 lio_droq_compute_max_packet_bufs(struct lio_droq *droq)
 {
@@ -706,6 +708,16 @@ lio_dev_recv_pkts(void *rx_queue,
        return pkts_processed;
 }
 
+void
+lio_delete_droq_queue(struct lio_device *lio_dev,
+                     int oq_no)
+{
+       lio_delete_droq(lio_dev, oq_no);
+       lio_dev->num_oqs--;
+       rte_free(lio_dev->droq[oq_no]);
+       lio_dev->droq[oq_no] = NULL;
+}
+
 /**
  *  lio_init_instr_queue()
  *  @param lio_dev     - pointer to the lio device structure.
@@ -851,6 +863,50 @@ lio_free_instr_queue0(struct lio_device *lio_dev)
        lio_dev->num_iqs--;
 }
 
+/* Return 0 on success, -1 on failure */
+int
+lio_setup_iq(struct lio_device *lio_dev, int q_index,
+            union octeon_txpciq txpciq, uint32_t num_descs, void *app_ctx,
+            unsigned int socket_id)
+{
+       uint32_t iq_no = (uint32_t)txpciq.s.q_no;
+
+       if (lio_dev->instr_queue[iq_no]) {
+               lio_dev_dbg(lio_dev, "IQ is in use. Cannot create the IQ: %d again\n",
+                           iq_no);
+               lio_dev->instr_queue[iq_no]->txpciq.txpciq64 = txpciq.txpciq64;
+               lio_dev->instr_queue[iq_no]->app_ctx = app_ctx;
+               return 0;
+       }
+
+       lio_dev->instr_queue[iq_no] = rte_zmalloc_socket("ethdev TX queue",
+                                               sizeof(struct lio_instr_queue),
+                                               RTE_CACHE_LINE_SIZE, socket_id);
+       if (lio_dev->instr_queue[iq_no] == NULL)
+               return -1;
+
+       lio_dev->instr_queue[iq_no]->q_index = q_index;
+       lio_dev->instr_queue[iq_no]->app_ctx = app_ctx;
+
+       if (lio_init_instr_queue(lio_dev, txpciq, num_descs, socket_id))
+               goto release_lio_iq;
+
+       lio_dev->num_iqs++;
+       if (lio_dev->fn_list.enable_io_queues(lio_dev))
+               goto delete_lio_iq;
+
+       return 0;
+
+delete_lio_iq:
+       lio_delete_instr_queue(lio_dev, iq_no);
+       lio_dev->num_iqs--;
+release_lio_iq:
+       rte_free(lio_dev->instr_queue[iq_no]);
+       lio_dev->instr_queue[iq_no] = NULL;
+
+       return -1;
+}
+
 static inline void
 lio_ring_doorbell(struct lio_device *lio_dev,
                  struct lio_instr_queue *iq)
@@ -1223,3 +1279,108 @@ lio_process_ordered_list(struct lio_device *lio_dev)
 
        return 0;
 }
+
+static inline struct lio_stailq_node *
+list_delete_first_node(struct lio_stailq_head *head)
+{
+       struct lio_stailq_node *node;
+
+       if (STAILQ_EMPTY(head))
+               node = NULL;
+       else
+               node = STAILQ_FIRST(head);
+
+       if (node)
+               STAILQ_REMOVE(head, node, lio_stailq_node, entries);
+
+       return node;
+}
+
+static void
+lio_delete_sglist(struct lio_instr_queue *txq)
+{
+       struct lio_device *lio_dev = txq->lio_dev;
+       int iq_no = txq->q_index;
+       struct lio_gather *g;
+
+       if (lio_dev->glist_head == NULL)
+               return;
+
+       do {
+               g = (struct lio_gather *)list_delete_first_node(
+                                               &lio_dev->glist_head[iq_no]);
+               if (g) {
+                       if (g->sg)
+                               rte_free(
+                                   (void *)((unsigned long)g->sg - g->adjust));
+                       rte_free(g);
+               }
+       } while (g);
+}
+
+/**
+ * \brief Setup gather lists
+ * @param lio per-network private data
+ */
+int
+lio_setup_sglists(struct lio_device *lio_dev, int iq_no,
+                 int fw_mapped_iq, int num_descs, unsigned int socket_id)
+{
+       struct lio_gather *g;
+       int i;
+
+       rte_spinlock_init(&lio_dev->glist_lock[iq_no]);
+
+       STAILQ_INIT(&lio_dev->glist_head[iq_no]);
+
+       for (i = 0; i < num_descs; i++) {
+               g = rte_zmalloc_socket(NULL, sizeof(*g), RTE_CACHE_LINE_SIZE,
+                                      socket_id);
+               if (g == NULL) {
+                       lio_dev_err(lio_dev,
+                                   "lio_gather memory allocation failed for qno %d\n",
+                                   iq_no);
+                       break;
+               }
+
+               g->sg_size =
+                   ((ROUNDUP4(LIO_MAX_SG) >> 2) * LIO_SG_ENTRY_SIZE);
+
+               g->sg = rte_zmalloc_socket(NULL, g->sg_size + 8,
+                                          RTE_CACHE_LINE_SIZE, socket_id);
+               if (g->sg == NULL) {
+                       lio_dev_err(lio_dev,
+                                   "sg list memory allocation failed for qno %d\n",
+                                   iq_no);
+                       rte_free(g);
+                       break;
+               }
+
+               /* The gather component should be aligned on 64-bit boundary */
+               if (((unsigned long)g->sg) & 7) {
+                       g->adjust = 8 - (((unsigned long)g->sg) & 7);
+                       g->sg =
+                           (struct lio_sg_entry *)((unsigned long)g->sg +
+                                                      g->adjust);
+               }
+
+               STAILQ_INSERT_TAIL(&lio_dev->glist_head[iq_no], &g->list,
+                                  entries);
+       }
+
+       if (i != num_descs) {
+               lio_delete_sglist(lio_dev->instr_queue[fw_mapped_iq]);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void
+lio_delete_instruction_queue(struct lio_device *lio_dev, int iq_no)
+{
+       lio_delete_instr_queue(lio_dev, iq_no);
+       rte_free(lio_dev->instr_queue[iq_no]);
+       lio_dev->instr_queue[iq_no] = NULL;
+       lio_dev->num_iqs--;
+}