Change-Id: Id86dbdd1070e8102bf602765654fe5afde0e0d6c
Signed-off-by: McDaniel, Timothy <timothy.mcdan...@intel.com>
---
 drivers/event/dlb/dlb.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 303 insertions(+)

diff --git a/drivers/event/dlb/dlb.c b/drivers/event/dlb/dlb.c
index deea474bf..7acf8b33d 100644
--- a/drivers/event/dlb/dlb.c
+++ b/drivers/event/dlb/dlb.c
@@ -794,6 +794,29 @@ dlb_hw_create_ldb_queue(struct dlb_eventdev *dlb,
        return qm_qid;
 }
 
+static int32_t
+dlb_hw_create_dir_queue(struct dlb_eventdev *dlb, int32_t qm_port_id)
+{
+       struct dlb_hw_dev *handle = &dlb->qm_instance;
+       struct dlb_create_dir_queue_args cfg;
+       struct dlb_cmd_response response;
+       int32_t ret;
+
+       cfg.response = (uintptr_t)&response;
+
+       /* The directed port is always configured before its queue */
+       cfg.port_id = qm_port_id;
+
+       ret = dlb_iface_dir_queue_create(handle, &cfg);
+       if (ret < 0) {
+               DLB_LOG_ERR("dlb: create DIR event queue error, ret=%d (driver 
status: %s)\n",
+                           ret, dlb_error_strings[response.status]);
+               return -EINVAL;
+       }
+
+       return response.id;
+}
+
 static inline void
 dlb_hw_do_enqueue(struct dlb_port *qm_port,
                  struct process_local_port_data *port_data)
@@ -803,6 +826,42 @@ dlb_hw_do_enqueue(struct dlb_port *qm_port,
        dlb_pp_write(qm_port->qe4, port_data);
 }
 
+static int16_t
+dlb_hw_map_ldb_qid_to_port(struct dlb_hw_dev *handle,
+                          uint32_t qm_port_id,
+                          uint16_t qm_qid,
+                          uint8_t priority)
+{
+       struct dlb_map_qid_args cfg;
+       struct dlb_cmd_response response;
+       int32_t ret;
+
+       if (handle == NULL)
+               return -EINVAL;
+
+       /* Build message */
+       cfg.response = (uintptr_t)&response;
+       cfg.port_id = qm_port_id;
+       cfg.qid = qm_qid;
+       cfg.priority = EV_TO_DLB_PRIO(priority);
+
+       ret = dlb_iface_map_qid(handle, &cfg);
+       if (ret < 0) {
+               DLB_LOG_ERR("dlb: map qid error, ret=%d (driver status: %s)\n",
+                           ret, dlb_error_strings[response.status]);
+               DLB_LOG_ERR("dlb: device_id=%d grp=%d, qm_port=%d, qm_qid=%d 
prio=%d\n",
+                           handle->device_id,
+                           handle->domain_id, cfg.port_id,
+                           cfg.qid,
+                           cfg.priority);
+       } else {
+               DLB_LOG_DBG("dlb: mapped queue %d to qm_port %d\n",
+                           qm_qid, qm_port_id);
+       }
+
+       return ret;
+}
+
 /* VDEV-only notes:
  * This function first unmaps all memory mappings and closes the
  * domain's file descriptor, which causes the driver to reset the
@@ -1785,6 +1844,249 @@ dlb_eventdev_configure(const struct rte_eventdev *dev)
        return 0;
 }
 
+static int
+dlb_event_queue_join_ldb(struct dlb_eventdev *dlb,
+                        struct dlb_eventdev_port *ev_port,
+                        struct dlb_eventdev_queue *ev_queue,
+                        uint8_t priority)
+{
+       int first_avail = -1;
+       int ret, i;
+
+       for (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++) {
+               if (ev_port->link[i].valid) {
+                       if (ev_port->link[i].queue_id == ev_queue->id &&
+                           ev_port->link[i].priority == priority) {
+                               if (ev_port->link[i].mapped)
+                                       return 0; /* already mapped */
+                               first_avail = i;
+                       }
+               } else {
+                       if (first_avail == -1)
+                               first_avail = i;
+               }
+       }
+       if (first_avail == -1) {
+               DLB_LOG_ERR("dlb: qm_port %d has no available QID slots.\n",
+                           ev_port->qm_port.id);
+               return -EINVAL;
+       }
+
+       ret = dlb_hw_map_ldb_qid_to_port(&dlb->qm_instance,
+                                        ev_port->qm_port.id,
+                                        ev_queue->qm_queue.id,
+                                        priority);
+
+       if (!ret)
+               ev_port->link[first_avail].mapped = true;
+
+       return ret;
+}
+
+static int
+dlb_eventdev_dir_queue_setup(struct dlb_eventdev *dlb,
+                            struct dlb_eventdev_queue *ev_queue,
+                            struct dlb_eventdev_port *ev_port)
+{
+       int32_t qm_qid;
+
+       qm_qid = dlb_hw_create_dir_queue(dlb, ev_port->qm_port.id);
+
+       if (qm_qid < 0) {
+               DLB_LOG_ERR("Failed to create the DIR queue\n");
+               return qm_qid;
+       }
+
+       dlb->qm_dir_to_ev_queue_id[qm_qid] = ev_queue->id;
+
+       ev_queue->qm_queue.id = qm_qid;
+
+       return 0;
+}
+
+static int
+dlb_do_port_link(struct rte_eventdev *dev,
+                struct dlb_eventdev_queue *ev_queue,
+                struct dlb_eventdev_port *ev_port,
+                uint8_t prio)
+{
+       struct dlb_eventdev *dlb = dlb_pmd_priv(dev);
+       int err;
+
+       /* Don't link until start time. */
+       if (dlb->run_state == DLB_RUN_STATE_STOPPED)
+               return 0;
+
+       if (ev_queue->qm_queue.is_directed)
+               err = dlb_eventdev_dir_queue_setup(dlb, ev_queue, ev_port);
+       else
+               err = dlb_event_queue_join_ldb(dlb, ev_port, ev_queue, prio);
+
+       if (err) {
+               DLB_LOG_ERR("port link failure for %s ev_q %d, ev_port %d\n",
+                           ev_queue->qm_queue.is_directed ? "DIR" : "LDB",
+                           ev_queue->id, ev_port->id);
+
+               rte_errno = err;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+dlb_validate_port_link(struct dlb_eventdev_port *ev_port,
+                      uint8_t queue_id,
+                      bool link_exists,
+                      int index)
+{
+       struct dlb_eventdev *dlb = ev_port->dlb;
+       struct dlb_eventdev_queue *ev_queue;
+       bool port_is_dir, queue_is_dir;
+
+       if (queue_id > dlb->num_queues) {
+               rte_errno = -EINVAL;
+               return -1;
+       }
+
+       ev_queue = &dlb->ev_queues[queue_id];
+
+       if (!ev_queue->setup_done &&
+           ev_queue->qm_queue.config_state != DLB_PREV_CONFIGURED) {
+               rte_errno = -EINVAL;
+               return -1;
+       }
+
+       port_is_dir = ev_port->qm_port.is_directed;
+       queue_is_dir = ev_queue->qm_queue.is_directed;
+
+       if (port_is_dir != queue_is_dir) {
+               DLB_LOG_ERR("%s queue %u can't link to %s port %u\n",
+                           queue_is_dir ? "DIR" : "LDB", ev_queue->id,
+                           port_is_dir ? "DIR" : "LDB", ev_port->id);
+
+               rte_errno = -EINVAL;
+               return -1;
+       }
+
+       /* Check if there is space for the requested link */
+       if (!link_exists && index == -1) {
+               DLB_LOG_ERR("no space for new link\n");
+               rte_errno = -ENOSPC;
+               return -1;
+       }
+
+       /* Check if the directed port is already linked */
+       if (ev_port->qm_port.is_directed && ev_port->num_links > 0 &&
+           !link_exists) {
+               DLB_LOG_ERR("Can't link DIR port %d to >1 queues\n",
+                           ev_port->id);
+               rte_errno = -EINVAL;
+               return -1;
+       }
+
+       /* Check if the directed queue is already linked */
+       if (ev_queue->qm_queue.is_directed && ev_queue->num_links > 0 &&
+           !link_exists) {
+               DLB_LOG_ERR("Can't link DIR queue %d to >1 ports\n",
+                           ev_queue->id);
+               rte_errno = -EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+dlb_eventdev_port_link(struct rte_eventdev *dev, void *event_port,
+                      const uint8_t queues[], const uint8_t priorities[],
+                      uint16_t nb_links)
+
+{
+       struct dlb_eventdev_port *ev_port = event_port;
+       struct dlb_eventdev *dlb;
+       int i, j;
+
+       RTE_SET_USED(dev);
+
+       if (!ev_port) {
+               DLB_LOG_ERR("dlb: evport not setup\n");
+               rte_errno = -EINVAL;
+               return 0;
+       }
+
+       if (!ev_port->setup_done &&
+           ev_port->qm_port.config_state != DLB_PREV_CONFIGURED) {
+               DLB_LOG_ERR("dlb: evport not setup\n");
+               rte_errno = -EINVAL;
+               return 0;
+       }
+
+       /* Note: rte_event_port_link() ensures the PMD won't receive a NULL
+        * queues pointer.
+        */
+       if (nb_links == 0) {
+               DLB_LOG_DBG("dlb: nb_links is 0\n");
+               return 0; /* Ignore and return success */
+       }
+
+       dlb = ev_port->dlb;
+
+       DLB_LOG_DBG("Linking %u queues to %s port %d\n",
+                   nb_links,
+                   ev_port->qm_port.is_directed ? "DIR" : "LDB",
+                   ev_port->id);
+
+       for (i = 0; i < nb_links; i++) {
+               struct dlb_eventdev_queue *ev_queue;
+               uint8_t queue_id, prio;
+               bool found = false;
+               int index = -1;
+
+               queue_id = queues[i];
+               prio = priorities[i];
+
+               /* Check if the link already exists. */
+               for (j = 0; j < DLB_MAX_NUM_QIDS_PER_LDB_CQ; j++)
+                       if (ev_port->link[j].valid) {
+                               if (ev_port->link[j].queue_id == queue_id) {
+                                       found = true;
+                                       index = j;
+                                       break;
+                               }
+                       } else {
+                               if (index == -1)
+                                       index = j;
+                       }
+
+               /* could not link */
+               if (index == -1)
+                       break;
+
+               /* Check if already linked at the requested priority */
+               if (found && ev_port->link[j].priority == prio)
+                       continue;
+
+               if (dlb_validate_port_link(ev_port, queue_id, found, index))
+                       break; /* return index of offending queue */
+
+               ev_queue = &dlb->ev_queues[queue_id];
+
+               if (dlb_do_port_link(dev, ev_queue, ev_port, prio))
+                       break; /* return index of offending queue */
+
+               ev_queue->num_links++;
+
+               ev_port->link[index].queue_id = queue_id;
+               ev_port->link[index].priority = prio;
+               ev_port->link[index].valid = true;
+               /* Entry already exists?  If so, then must be prio change */
+               if (!found)
+                       ev_port->num_links++;
+       }
+       return i;
+}
+
 static void
 dlb_eventdev_port_default_conf_get(struct rte_eventdev *dev,
                                   uint8_t port_id,
@@ -2255,6 +2557,7 @@ dlb_entry_points_init(struct rte_eventdev *dev)
                .queue_setup      = dlb_eventdev_queue_setup,
                .port_def_conf    = dlb_eventdev_port_default_conf_get,
                .port_setup       = dlb_eventdev_port_setup,
+               .port_link        = dlb_eventdev_port_link,
        };
 
        /* Expose PMD's eventdev interface */
-- 
2.13.6

Reply via email to