get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/77494/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 77494,
    "url": "http://patches.dpdk.org/api/patches/77494/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1599851920-16802-12-git-send-email-timothy.mcdaniel@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1599851920-16802-12-git-send-email-timothy.mcdaniel@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1599851920-16802-12-git-send-email-timothy.mcdaniel@intel.com",
    "date": "2020-09-11T19:18:29",
    "name": "[v4,11/22] event/dlb: add port setup",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "98377a31f331c67739953e75207eaa16315bbfdb",
    "submitter": {
        "id": 826,
        "url": "http://patches.dpdk.org/api/people/826/?format=api",
        "name": "Timothy McDaniel",
        "email": "timothy.mcdaniel@intel.com"
    },
    "delegate": {
        "id": 310,
        "url": "http://patches.dpdk.org/api/users/310/?format=api",
        "username": "jerin",
        "first_name": "Jerin",
        "last_name": "Jacob",
        "email": "jerinj@marvell.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1599851920-16802-12-git-send-email-timothy.mcdaniel@intel.com/mbox/",
    "series": [
        {
            "id": 12163,
            "url": "http://patches.dpdk.org/api/series/12163/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12163",
            "date": "2020-09-11T19:18:18",
            "name": "Add DLB PMD",
            "version": 4,
            "mbox": "http://patches.dpdk.org/series/12163/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/77494/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/77494/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 7BD4AA04C1;\n\tFri, 11 Sep 2020 21:23:56 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 862CF1C1E3;\n\tFri, 11 Sep 2020 21:22:23 +0200 (CEST)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n by dpdk.org (Postfix) with ESMTP id E193B1C1A5\n for <dev@dpdk.org>; Fri, 11 Sep 2020 21:22:10 +0200 (CEST)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 11 Sep 2020 12:22:10 -0700",
            "from txasoft-yocto.an.intel.com ([10.123.72.192])\n by fmsmga005.fm.intel.com with ESMTP; 11 Sep 2020 12:22:09 -0700"
        ],
        "IronPort-SDR": [
            "\n CL+G70iRugsPICAKiVrkJM+tsHdWtoB/tYkPDqcmyx5CykQ2f6r3FqZEKt6xSZk+0n63Hpnuoh\n Q62xAo8xwG4A==",
            "\n KU+Xjms4MeFCE9d0oT0/+r/84oL8r4LkNJ92jGpPa1/f+sl9z6390FnBMPmDX9+DPA/qHtg2Mg\n l6fWUE+WbXrw=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9741\"; a=\"138352272\"",
            "E=Sophos;i=\"5.76,416,1592895600\"; d=\"scan'208\";a=\"138352272\"",
            "E=Sophos;i=\"5.76,416,1592895600\"; d=\"scan'208\";a=\"506375676\""
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "From": "Timothy McDaniel <timothy.mcdaniel@intel.com>",
        "To": "",
        "Cc": "dev@dpdk.org, erik.g.carrillo@intel.com, gage.eads@intel.com,\n harry.van.haaren@intel.com, jerinj@marvell.com",
        "Date": "Fri, 11 Sep 2020 14:18:29 -0500",
        "Message-Id": "<1599851920-16802-12-git-send-email-timothy.mcdaniel@intel.com>",
        "X-Mailer": "git-send-email 1.7.10",
        "In-Reply-To": "<1599851920-16802-1-git-send-email-timothy.mcdaniel@intel.com>",
        "References": "<1599851920-16802-1-git-send-email-timothy.mcdaniel@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 11/22] event/dlb: add port setup",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Configure the load balanded (ldb) or directed (dir) port.\nThe consumer queue (CQ) and producer port (PP) are also\nset up here.\n\nSigned-off-by: Timothy McDaniel <timothy.mcdaniel@intel.com>\n---\n drivers/event/dlb/dlb.c                  |  539 +++++++++++\n drivers/event/dlb/dlb_iface.c            |   11 +\n drivers/event/dlb/dlb_iface.h            |   14 +\n drivers/event/dlb/pf/base/dlb_resource.c | 1430 ++++++++++++++++++++++++++++++\n drivers/event/dlb/pf/dlb_pf.c            |  204 +++++\n 5 files changed, 2198 insertions(+)",
    "diff": "diff --git a/drivers/event/dlb/dlb.c b/drivers/event/dlb/dlb.c\nindex 0b474a5..e90a088 100644\n--- a/drivers/event/dlb/dlb.c\n+++ b/drivers/event/dlb/dlb.c\n@@ -157,6 +157,75 @@ dlb_free_qe_mem(struct dlb_port *qm_port)\n \t}\n }\n \n+static int\n+dlb_init_consume_qe(struct dlb_port *qm_port, char *mz_name)\n+{\n+\tstruct dlb_cq_pop_qe *qe;\n+\n+\tqe = rte_malloc(mz_name,\n+\t\t\tDLB_NUM_QES_PER_CACHE_LINE *\n+\t\t\t\tsizeof(struct dlb_cq_pop_qe),\n+\t\t\tRTE_CACHE_LINE_SIZE);\n+\n+\tif (qe == NULL)\t{\n+\t\tDLB_LOG_ERR(\"dlb: no memory for consume_qe\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tqm_port->consume_qe = qe;\n+\n+\tmemset(qe, 0, DLB_NUM_QES_PER_CACHE_LINE *\n+\t       sizeof(struct dlb_cq_pop_qe));\n+\n+\tqe->qe_valid = 0;\n+\tqe->qe_frag = 0;\n+\tqe->qe_comp = 0;\n+\tqe->cq_token = 1;\n+\t/* Tokens value is 0-based; i.e. '0' returns 1 token, '1' returns 2,\n+\t * and so on.\n+\t */\n+\tqe->tokens = 0;\t/* set at run time */\n+\tqe->meas_lat = 0;\n+\tqe->no_dec = 0;\n+\t/* Completion IDs are disabled */\n+\tqe->cmp_id = 0;\n+\n+\treturn 0;\n+}\n+\n+int\n+dlb_init_qe_mem(struct dlb_port *qm_port, char *mz_name)\n+{\n+\tint ret, sz;\n+\n+\tsz = DLB_NUM_QES_PER_CACHE_LINE * sizeof(struct dlb_enqueue_qe);\n+\n+\tqm_port->qe4 = rte_malloc(mz_name, sz, RTE_CACHE_LINE_SIZE);\n+\n+\tif (qm_port->qe4 == NULL) {\n+\t\tDLB_LOG_ERR(\"dlb: no qe4 memory\\n\");\n+\t\tret = -ENOMEM;\n+\t\tgoto error_exit;\n+\t}\n+\n+\tmemset(qm_port->qe4, 0, sz);\n+\n+\tret = dlb_init_consume_qe(qm_port, mz_name);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb: dlb_init_consume_qe ret=%d\\n\",\n+\t\t\t    ret);\n+\t\tgoto error_exit;\n+\t}\n+\n+\treturn 0;\n+\n+error_exit:\n+\n+\tdlb_free_qe_mem(qm_port);\n+\n+\treturn ret;\n+}\n+\n /* Wrapper for string to int conversion. Substituted for atoi(...), which is\n  * unsafe.\n  */\n@@ -662,6 +731,348 @@ dlb_eventdev_queue_default_conf_get(struct rte_eventdev *dev,\n \tqueue_conf->priority = 0;\n }\n \n+static int\n+dlb_hw_create_ldb_port(struct dlb_eventdev *dlb,\n+\t\t       struct dlb_eventdev_port *ev_port,\n+\t\t       uint32_t dequeue_depth,\n+\t\t       uint32_t cq_depth,\n+\t\t       uint32_t enqueue_depth,\n+\t\t       uint16_t rsvd_tokens,\n+\t\t       bool use_rsvd_token_scheme)\n+{\n+\tstruct dlb_hw_dev *handle = &dlb->qm_instance;\n+\tstruct dlb_create_ldb_port_args cfg = {0};\n+\tstruct dlb_cmd_response response = {0};\n+\tint ret;\n+\tstruct dlb_port *qm_port = NULL;\n+\tchar mz_name[RTE_MEMZONE_NAMESIZE];\n+\tuint32_t qm_port_id;\n+\n+\tif (handle == NULL)\n+\t\treturn -EINVAL;\n+\n+\tif (cq_depth < DLB_MIN_LDB_CQ_DEPTH ||\n+\t    cq_depth > DLB_MAX_INPUT_QUEUE_DEPTH) {\n+\t\tDLB_LOG_ERR(\"dlb: invalid cq_depth, must be %d-%d\\n\",\n+\t\t\tDLB_MIN_LDB_CQ_DEPTH, DLB_MAX_INPUT_QUEUE_DEPTH);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (enqueue_depth < DLB_MIN_ENQUEUE_DEPTH) {\n+\t\tDLB_LOG_ERR(\"dlb: invalid enqueue_depth, must be at least %d\\n\",\n+\t\t\t    DLB_MIN_ENQUEUE_DEPTH);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trte_spinlock_lock(&handle->resource_lock);\n+\n+\tcfg.response = (uintptr_t)&response;\n+\n+\t/* We round up to the next power of 2 if necessary */\n+\tcfg.cq_depth = rte_align32pow2(cq_depth);\n+\tcfg.cq_depth_threshold = rsvd_tokens;\n+\n+\tcfg.cq_history_list_size = DLB_NUM_HIST_LIST_ENTRIES_PER_LDB_PORT;\n+\n+\t/* User controls the LDB high watermark via enqueue depth. The DIR high\n+\t * watermark is equal, unless the directed credit pool is too small.\n+\t */\n+\tcfg.ldb_credit_high_watermark = enqueue_depth;\n+\n+\t/* If there are no directed ports, the kernel driver will ignore this\n+\t * port's directed credit settings. Don't use enqueue_depth if it would\n+\t * require more directed credits than are available.\n+\t */\n+\tcfg.dir_credit_high_watermark =\n+\t\tRTE_MIN(enqueue_depth,\n+\t\t\thandle->cfg.num_dir_credits / dlb->num_ports);\n+\n+\tcfg.ldb_credit_quantum = cfg.ldb_credit_high_watermark / 2;\n+\tcfg.ldb_credit_low_watermark = RTE_MIN(16, cfg.ldb_credit_quantum);\n+\n+\tcfg.dir_credit_quantum = cfg.dir_credit_high_watermark / 2;\n+\tcfg.dir_credit_low_watermark = RTE_MIN(16, cfg.dir_credit_quantum);\n+\n+\t/* Per QM values */\n+\n+\tcfg.ldb_credit_pool_id = handle->cfg.ldb_credit_pool_id;\n+\tcfg.dir_credit_pool_id = handle->cfg.dir_credit_pool_id;\n+\n+\tret = dlb_iface_ldb_port_create(handle, &cfg, dlb->poll_mode);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb: dlb_ldb_port_create error, ret=%d (driver status: %s)\\n\",\n+\t\t\t    ret, dlb_error_strings[response.status]);\n+\t\tgoto error_exit;\n+\t}\n+\n+\tqm_port_id = response.id;\n+\n+\tDLB_LOG_DBG(\"dlb: ev_port %d uses qm LB port %d <<<<<\\n\",\n+\t\t    ev_port->id, qm_port_id);\n+\n+\tqm_port = &ev_port->qm_port;\n+\tqm_port->ev_port = ev_port; /* back ptr */\n+\tqm_port->dlb = dlb; /* back ptr */\n+\n+\t/*\n+\t * Allocate and init local qe struct(s).\n+\t * Note: MOVDIR64 requires the enqueue QE (qe4) to be aligned.\n+\t */\n+\n+\tsnprintf(mz_name, sizeof(mz_name), \"%s_ldb_port%d\",\n+\t\t handle->device_name,\n+\t\t ev_port->id);\n+\n+\tret = dlb_init_qe_mem(qm_port, mz_name);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb: init_qe_mem failed, ret=%d\\n\", ret);\n+\t\tgoto error_exit;\n+\t}\n+\n+\tqm_port->pp_mmio_base = DLB_LDB_PP_BASE + PAGE_SIZE * qm_port_id;\n+\tqm_port->id = qm_port_id;\n+\n+\t/* The credit window is one high water mark of QEs */\n+\tqm_port->ldb_pushcount_at_credit_expiry = 0;\n+\tqm_port->cached_ldb_credits = cfg.ldb_credit_high_watermark;\n+\t/* The credit window is one high water mark of QEs */\n+\tqm_port->dir_pushcount_at_credit_expiry = 0;\n+\tqm_port->cached_dir_credits = cfg.dir_credit_high_watermark;\n+\tqm_port->cq_depth = cfg.cq_depth;\n+\t/* CQs with depth < 8 use an 8-entry queue, but withhold credits so\n+\t * the effective depth is smaller.\n+\t */\n+\tqm_port->cq_depth = cfg.cq_depth <= 8 ? 8 : cfg.cq_depth;\n+\tqm_port->cq_idx = 0;\n+\tqm_port->cq_idx_unmasked = 0;\n+\tif (dlb->poll_mode == DLB_CQ_POLL_MODE_SPARSE)\n+\t\tqm_port->cq_depth_mask = (qm_port->cq_depth * 4) - 1;\n+\telse\n+\t\tqm_port->cq_depth_mask = qm_port->cq_depth - 1;\n+\n+\tqm_port->gen_bit_shift = __builtin_popcount(qm_port->cq_depth_mask);\n+\t/* starting value of gen bit - it toggles at wrap time */\n+\tqm_port->gen_bit = 1;\n+\n+\tqm_port->use_rsvd_token_scheme = use_rsvd_token_scheme;\n+\tqm_port->cq_rsvd_token_deficit = rsvd_tokens;\n+\tqm_port->int_armed = false;\n+\n+\t/* Save off for later use in info and lookup APIs. */\n+\tqm_port->qid_mappings = &dlb->qm_ldb_to_ev_queue_id[0];\n+\n+\t/* When using the reserved token scheme, token_pop_thresh is\n+\t * initially 2 * dequeue_depth. Once the tokens are reserved,\n+\t * the enqueue code re-assigns it to dequeue_depth.\n+\t */\n+\tqm_port->dequeue_depth = dequeue_depth;\n+\tqm_port->token_pop_thresh = cq_depth;\n+\n+\t/* When the deferred scheduling vdev arg is selected, use deferred pop\n+\t * for all single-entry CQs.\n+\t */\n+\tif (cfg.cq_depth == 1 || (cfg.cq_depth == 2 && use_rsvd_token_scheme)) {\n+\t\tif (dlb->defer_sched)\n+\t\t\tqm_port->token_pop_mode = DEFERRED_POP;\n+\t}\n+\n+\tqm_port->owed_tokens = 0;\n+\tqm_port->issued_releases = 0;\n+\n+\t/* Save config message too. */\n+\trte_memcpy(&qm_port->cfg.ldb, &cfg, sizeof(cfg));\n+\n+\t/* update state */\n+\tqm_port->state = PORT_STARTED; /* enabled at create time */\n+\tqm_port->config_state = DLB_CONFIGURED;\n+\n+\tqm_port->dir_credits = cfg.dir_credit_high_watermark;\n+\tqm_port->ldb_credits = cfg.ldb_credit_high_watermark;\n+\n+\tDLB_LOG_DBG(\"dlb: created ldb port %d, depth = %d, ldb credits=%d, dir credits=%d\\n\",\n+\t\t    qm_port_id,\n+\t\t    cq_depth,\n+\t\t    qm_port->ldb_credits,\n+\t\t    qm_port->dir_credits);\n+\n+\trte_spinlock_unlock(&handle->resource_lock);\n+\n+\treturn 0;\n+\n+error_exit:\n+\tif (qm_port) {\n+\t\tdlb_free_qe_mem(qm_port);\n+\t\tqm_port->pp_mmio_base = 0;\n+\t}\n+\n+\trte_spinlock_unlock(&handle->resource_lock);\n+\n+\tDLB_LOG_ERR(\"dlb: create ldb port failed!\\n\");\n+\n+\treturn ret;\n+}\n+\n+static int\n+dlb_hw_create_dir_port(struct dlb_eventdev *dlb,\n+\t\t       struct dlb_eventdev_port *ev_port,\n+\t\t       uint32_t dequeue_depth,\n+\t\t       uint32_t cq_depth,\n+\t\t       uint32_t enqueue_depth,\n+\t\t       uint16_t rsvd_tokens,\n+\t\t       bool use_rsvd_token_scheme)\n+{\n+\tstruct dlb_hw_dev *handle = &dlb->qm_instance;\n+\tstruct dlb_create_dir_port_args cfg = {0};\n+\tstruct dlb_cmd_response response = {0};\n+\tint ret;\n+\tstruct dlb_port *qm_port = NULL;\n+\tchar mz_name[RTE_MEMZONE_NAMESIZE];\n+\tuint32_t qm_port_id;\n+\n+\tif (dlb == NULL || handle == NULL)\n+\t\treturn -EINVAL;\n+\n+\tif (cq_depth < DLB_MIN_DIR_CQ_DEPTH ||\n+\t    cq_depth > DLB_MAX_INPUT_QUEUE_DEPTH) {\n+\t\tDLB_LOG_ERR(\"dlb: invalid cq_depth, must be %d-%d\\n\",\n+\t\t\t    DLB_MIN_DIR_CQ_DEPTH, DLB_MAX_INPUT_QUEUE_DEPTH);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trte_spinlock_lock(&handle->resource_lock);\n+\n+\t/* Directed queues are configured at link time. */\n+\tcfg.queue_id = -1;\n+\n+\tcfg.response = (uintptr_t)&response;\n+\n+\t/* We round up to the next power of 2 if necessary */\n+\tcfg.cq_depth = rte_align32pow2(cq_depth);\n+\tcfg.cq_depth_threshold = rsvd_tokens;\n+\n+\t/* User controls the LDB high watermark via enqueue depth. The DIR high\n+\t * watermark is equal, unless the directed credit pool is too small.\n+\t */\n+\tcfg.ldb_credit_high_watermark = enqueue_depth;\n+\n+\t/* Don't use enqueue_depth if it would require more directed credits\n+\t * than are available.\n+\t */\n+\tcfg.dir_credit_high_watermark =\n+\t\tRTE_MIN(enqueue_depth,\n+\t\t\thandle->cfg.num_dir_credits / dlb->num_ports);\n+\n+\tcfg.ldb_credit_quantum = cfg.ldb_credit_high_watermark / 2;\n+\tcfg.ldb_credit_low_watermark = RTE_MIN(16, cfg.ldb_credit_quantum);\n+\n+\tcfg.dir_credit_quantum = cfg.dir_credit_high_watermark / 2;\n+\tcfg.dir_credit_low_watermark = RTE_MIN(16, cfg.dir_credit_quantum);\n+\n+\t/* Per QM values */\n+\n+\tcfg.ldb_credit_pool_id = handle->cfg.ldb_credit_pool_id;\n+\tcfg.dir_credit_pool_id = handle->cfg.dir_credit_pool_id;\n+\n+\tret = dlb_iface_dir_port_create(handle, &cfg, dlb->poll_mode);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb: dlb_dir_port_create error, ret=%d (driver status: %s)\\n\",\n+\t\t\t    ret, dlb_error_strings[response.status]);\n+\t\tgoto error_exit;\n+\t}\n+\n+\tqm_port_id = response.id;\n+\n+\tDLB_LOG_DBG(\"dlb: ev_port %d uses qm DIR port %d <<<<<\\n\",\n+\t\t    ev_port->id, qm_port_id);\n+\n+\tqm_port = &ev_port->qm_port;\n+\tqm_port->ev_port = ev_port; /* back ptr */\n+\tqm_port->dlb = dlb;  /* back ptr */\n+\n+\t/*\n+\t * Init local qe struct(s).\n+\t * Note: MOVDIR64 requires the enqueue QE to be aligned\n+\t */\n+\n+\tsnprintf(mz_name, sizeof(mz_name), \"%s_dir_port%d\",\n+\t\t handle->device_name,\n+\t\t ev_port->id);\n+\n+\tret = dlb_init_qe_mem(qm_port, mz_name);\n+\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb: init_qe_mem failed, ret=%d\\n\", ret);\n+\t\tgoto error_exit;\n+\t}\n+\n+\tqm_port->pp_mmio_base = DLB_DIR_PP_BASE + PAGE_SIZE * qm_port_id;\n+\tqm_port->id = qm_port_id;\n+\n+\t/* The credit window is one high water mark of QEs */\n+\tqm_port->ldb_pushcount_at_credit_expiry = 0;\n+\tqm_port->cached_ldb_credits = cfg.ldb_credit_high_watermark;\n+\t/* The credit window is one high water mark of QEs */\n+\tqm_port->dir_pushcount_at_credit_expiry = 0;\n+\tqm_port->cached_dir_credits = cfg.dir_credit_high_watermark;\n+\tqm_port->cq_depth = cfg.cq_depth;\n+\tqm_port->cq_idx = 0;\n+\tqm_port->cq_idx_unmasked = 0;\n+\tif (dlb->poll_mode == DLB_CQ_POLL_MODE_SPARSE)\n+\t\tqm_port->cq_depth_mask = (cfg.cq_depth * 4) - 1;\n+\telse\n+\t\tqm_port->cq_depth_mask = cfg.cq_depth - 1;\n+\n+\tqm_port->gen_bit_shift = __builtin_popcount(qm_port->cq_depth_mask);\n+\t/* starting value of gen bit - it toggles at wrap time */\n+\tqm_port->gen_bit = 1;\n+\n+\tqm_port->use_rsvd_token_scheme = use_rsvd_token_scheme;\n+\tqm_port->cq_rsvd_token_deficit = rsvd_tokens;\n+\tqm_port->int_armed = false;\n+\n+\t/* Save off for later use in info and lookup APIs. */\n+\tqm_port->qid_mappings = &dlb->qm_dir_to_ev_queue_id[0];\n+\n+\tqm_port->dequeue_depth = dequeue_depth;\n+\n+\t/* Directed ports are auto-pop, by default. */\n+\tqm_port->token_pop_mode = AUTO_POP;\n+\tqm_port->owed_tokens = 0;\n+\tqm_port->issued_releases = 0;\n+\n+\t/* Save config message too. */\n+\trte_memcpy(&qm_port->cfg.dir, &cfg, sizeof(cfg));\n+\n+\t/* update state */\n+\tqm_port->state = PORT_STARTED; /* enabled at create time */\n+\tqm_port->config_state = DLB_CONFIGURED;\n+\n+\tqm_port->dir_credits = cfg.dir_credit_high_watermark;\n+\tqm_port->ldb_credits = cfg.ldb_credit_high_watermark;\n+\n+\tDLB_LOG_DBG(\"dlb: created dir port %d, depth = %d cr=%d,%d\\n\",\n+\t\t    qm_port_id,\n+\t\t    cq_depth,\n+\t\t    cfg.dir_credit_high_watermark,\n+\t\t    cfg.ldb_credit_high_watermark);\n+\n+\trte_spinlock_unlock(&handle->resource_lock);\n+\n+\treturn 0;\n+\n+error_exit:\n+\tif (qm_port) {\n+\t\tqm_port->pp_mmio_base = 0;\n+\t\tdlb_free_qe_mem(qm_port);\n+\t}\n+\n+\trte_spinlock_unlock(&handle->resource_lock);\n+\n+\tDLB_LOG_ERR(\"dlb: create dir port failed!\\n\");\n+\n+\treturn ret;\n+}\n+\n static int32_t\n dlb_hw_create_ldb_queue(struct dlb_eventdev *dlb,\n \t\t\tstruct dlb_queue *queue,\n@@ -955,6 +1366,133 @@ dlb_eventdev_queue_setup(struct rte_eventdev *dev,\n \treturn ret;\n }\n \n+static void\n+dlb_port_link_teardown(struct dlb_eventdev *dlb,\n+\t\t       struct dlb_eventdev_port *ev_port)\n+{\n+\tstruct dlb_eventdev_queue *ev_queue;\n+\tint i;\n+\n+\tfor (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++) {\n+\t\tif (!ev_port->link[i].valid)\n+\t\t\tcontinue;\n+\n+\t\tev_queue = &dlb->ev_queues[ev_port->link[i].queue_id];\n+\n+\t\tev_port->link[i].valid = false;\n+\t\tev_port->num_links--;\n+\t\tev_queue->num_links--;\n+\t}\n+}\n+\n+static int\n+dlb_eventdev_port_setup(struct rte_eventdev *dev,\n+\t\t\tuint8_t ev_port_id,\n+\t\t\tconst struct rte_event_port_conf *port_conf)\n+{\n+\tstruct dlb_eventdev *dlb;\n+\tstruct dlb_eventdev_port *ev_port;\n+\tbool use_rsvd_token_scheme;\n+\tuint32_t adj_cq_depth;\n+\tuint16_t rsvd_tokens;\n+\tint ret;\n+\n+\tif (dev == NULL || port_conf == NULL) {\n+\t\tDLB_LOG_ERR(\"Null parameter\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tdlb = dlb_pmd_priv(dev);\n+\n+\tif (ev_port_id >= DLB_MAX_NUM_PORTS)\n+\t\treturn -EINVAL;\n+\n+\tif (port_conf->dequeue_depth >\n+\t\tevdev_dlb_default_info.max_event_port_dequeue_depth ||\n+\t    port_conf->enqueue_depth >\n+\t\tevdev_dlb_default_info.max_event_port_enqueue_depth)\n+\t\treturn -EINVAL;\n+\n+\tev_port = &dlb->ev_ports[ev_port_id];\n+\t/* configured? */\n+\tif (ev_port->setup_done) {\n+\t\tDLB_LOG_ERR(\"evport %d is already configured\\n\", ev_port_id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* The reserved token interrupt arming scheme requires that one or more\n+\t * CQ tokens be reserved by the PMD. This limits the amount of CQ space\n+\t * usable by the DLB, so in order to give an *effective* CQ depth equal\n+\t * to the user-requested value, we double CQ depth and reserve half of\n+\t * its tokens. If the user requests the max CQ depth (256) then we\n+\t * cannot double it, so we reserve one token and give an effective\n+\t * depth of 255 entries.\n+\t */\n+\tuse_rsvd_token_scheme = true;\n+\trsvd_tokens = 1;\n+\tadj_cq_depth = port_conf->dequeue_depth;\n+\n+\tif (use_rsvd_token_scheme && adj_cq_depth < 256) {\n+\t\trsvd_tokens = adj_cq_depth;\n+\t\tadj_cq_depth *= 2;\n+\t}\n+\n+\tev_port->qm_port.is_directed = port_conf->event_port_cfg &\n+\t\tRTE_EVENT_PORT_CFG_SINGLE_LINK;\n+\n+\tif (!ev_port->qm_port.is_directed) {\n+\t\tret = dlb_hw_create_ldb_port(dlb,\n+\t\t\t\t\t     ev_port,\n+\t\t\t\t\t     port_conf->dequeue_depth,\n+\t\t\t\t\t     adj_cq_depth,\n+\t\t\t\t\t     port_conf->enqueue_depth,\n+\t\t\t\t\t     rsvd_tokens,\n+\t\t\t\t\t     use_rsvd_token_scheme);\n+\t\tif (ret < 0) {\n+\t\t\tDLB_LOG_ERR(\"Failed to create the lB port ve portId=%d\\n\",\n+\t\t\t\t    ev_port_id);\n+\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\tret = dlb_hw_create_dir_port(dlb,\n+\t\t\t\t\t     ev_port,\n+\t\t\t\t\t     port_conf->dequeue_depth,\n+\t\t\t\t\t     adj_cq_depth,\n+\t\t\t\t\t     port_conf->enqueue_depth,\n+\t\t\t\t\t     rsvd_tokens,\n+\t\t\t\t\t     use_rsvd_token_scheme);\n+\t\tif (ret < 0) {\n+\t\t\tDLB_LOG_ERR(\"Failed to create the DIR port\\n\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\t/* Save off port config for reconfig */\n+\tdlb->ev_ports[ev_port_id].conf = *port_conf;\n+\n+\tdlb->ev_ports[ev_port_id].id = ev_port_id;\n+\tdlb->ev_ports[ev_port_id].enq_configured = true;\n+\tdlb->ev_ports[ev_port_id].setup_done = true;\n+\tdlb->ev_ports[ev_port_id].inflight_max =\n+\t\tport_conf->new_event_threshold;\n+\tdlb->ev_ports[ev_port_id].implicit_release =\n+\t\t!(port_conf->event_port_cfg &\n+\t\t  RTE_EVENT_PORT_CFG_DISABLE_IMPL_REL);\n+\tdlb->ev_ports[ev_port_id].outstanding_releases = 0;\n+\tdlb->ev_ports[ev_port_id].inflight_credits = 0;\n+\tdlb->ev_ports[ev_port_id].credit_update_quanta =\n+\t\tRTE_LIBRTE_PMD_DLB_SW_CREDIT_QUANTA;\n+\tdlb->ev_ports[ev_port_id].dlb = dlb; /* reverse link */\n+\n+\t/* Tear down pre-existing port->queue links */\n+\tif (dlb->run_state == DLB_RUN_STATE_STOPPED)\n+\t\tdlb_port_link_teardown(dlb, &dlb->ev_ports[ev_port_id]);\n+\n+\tdev->data->ports[ev_port_id] = &dlb->ev_ports[ev_port_id];\n+\n+\treturn 0;\n+}\n+\n static int\n set_dev_id(const char *key __rte_unused,\n \t   const char *value,\n@@ -1034,6 +1572,7 @@ dlb_entry_points_init(struct rte_eventdev *dev)\n \t\t.queue_def_conf   = dlb_eventdev_queue_default_conf_get,\n \t\t.port_def_conf    = dlb_eventdev_port_default_conf_get,\n \t\t.queue_setup      = dlb_eventdev_queue_setup,\n+\t\t.port_setup       = dlb_eventdev_port_setup,\n \t\t.dump             = dlb_eventdev_dump,\n \t\t.xstats_get       = dlb_eventdev_xstats_get,\n \t\t.xstats_get_names = dlb_eventdev_xstats_get_names,\ndiff --git a/drivers/event/dlb/dlb_iface.c b/drivers/event/dlb/dlb_iface.c\nindex b5757c9..0302be4 100644\n--- a/drivers/event/dlb/dlb_iface.c\n+++ b/drivers/event/dlb/dlb_iface.c\n@@ -47,9 +47,20 @@ int (*dlb_iface_ldb_credit_pool_create)(struct dlb_hw_dev *handle,\n int (*dlb_iface_dir_credit_pool_create)(struct dlb_hw_dev *handle,\n \t\t\t\t\tstruct dlb_create_dir_pool_args *cfg);\n \n+int (*dlb_iface_dir_queue_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t  struct dlb_create_dir_queue_args *cfg);\n+\n int (*dlb_iface_ldb_queue_create)(struct dlb_hw_dev *handle,\n \t\t\t\t  struct dlb_create_ldb_queue_args *cfg);\n \n+int (*dlb_iface_ldb_port_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t struct dlb_create_ldb_port_args *cfg,\n+\t\t\t\t enum dlb_cq_poll_modes poll_mode);\n+\n+int (*dlb_iface_dir_port_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t struct dlb_create_dir_port_args *cfg,\n+\t\t\t\t enum dlb_cq_poll_modes poll_mode);\n+\n int (*dlb_iface_get_cq_poll_mode)(struct dlb_hw_dev *handle,\n \t\t\t\t  enum dlb_cq_poll_modes *mode);\n \ndiff --git a/drivers/event/dlb/dlb_iface.h b/drivers/event/dlb/dlb_iface.h\nindex af1416d..d578185 100644\n--- a/drivers/event/dlb/dlb_iface.h\n+++ b/drivers/event/dlb/dlb_iface.h\n@@ -35,6 +35,20 @@ extern int (*dlb_iface_dir_credit_pool_create)(struct dlb_hw_dev *handle,\n extern int (*dlb_iface_ldb_queue_create)(struct dlb_hw_dev *handle,\n \t\t\t\t  struct dlb_create_ldb_queue_args *cfg);\n \n+extern int (*dlb_iface_dir_queue_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t  struct dlb_create_dir_queue_args *cfg);\n+\n+extern int (*dlb_iface_ldb_port_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t\tstruct dlb_create_ldb_port_args *cfg,\n+\t\t\t\t\tenum dlb_cq_poll_modes poll_mode);\n+\n+extern int (*dlb_iface_dir_port_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t\tstruct dlb_create_dir_port_args *cfg,\n+\t\t\t\t\tenum dlb_cq_poll_modes poll_mode);\n+\n+extern int (*dlb_iface_ldb_queue_create)(struct dlb_hw_dev *handle,\n+\t\t\t\t  struct dlb_create_ldb_queue_args *cfg);\n+\n extern int (*dlb_iface_get_cq_poll_mode)(struct dlb_hw_dev *handle,\n \t\t\t\t\t enum dlb_cq_poll_modes *mode);\n \ndiff --git a/drivers/event/dlb/pf/base/dlb_resource.c b/drivers/event/dlb/pf/base/dlb_resource.c\nindex 2b80e03..a4d9e4a 100644\n--- a/drivers/event/dlb/pf/base/dlb_resource.c\n+++ b/drivers/event/dlb/pf/base/dlb_resource.c\n@@ -4598,3 +4598,1433 @@ int dlb_hw_create_ldb_queue(struct dlb_hw *hw,\n \n \treturn 0;\n }\n+\n+\n+static void\n+dlb_log_create_dir_queue_args(struct dlb_hw *hw,\n+\t\t\t      u32 domain_id,\n+\t\t\t      struct dlb_create_dir_queue_args *args)\n+{\n+\tDLB_HW_INFO(hw, \"DLB create directed queue arguments:\\n\");\n+\tDLB_HW_INFO(hw, \"\\tDomain ID: %d\\n\", domain_id);\n+\tDLB_HW_INFO(hw, \"\\tPort ID:   %d\\n\", args->port_id);\n+}\n+\n+static struct dlb_dir_pq_pair *\n+dlb_get_domain_used_dir_pq(u32 id, struct dlb_domain *domain)\n+{\n+\tstruct dlb_list_entry *iter;\n+\tstruct dlb_dir_pq_pair *port;\n+\tRTE_SET_USED(iter);\n+\n+\tif (id >= DLB_MAX_NUM_DIR_PORTS)\n+\t\treturn NULL;\n+\n+\tDLB_DOM_LIST_FOR(domain->used_dir_pq_pairs, port, iter)\n+\t\tif (port->id == id)\n+\t\t\treturn port;\n+\n+\treturn NULL;\n+}\n+\n+static int\n+dlb_verify_create_dir_queue_args(struct dlb_hw *hw,\n+\t\t\t\t u32 domain_id,\n+\t\t\t\t struct dlb_create_dir_queue_args *args,\n+\t\t\t\t struct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_domain *domain;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\n+\tif (!domain) {\n+\t\tresp->status = DLB_ST_INVALID_DOMAIN_ID;\n+\t\treturn -1;\n+\t}\n+\n+\tif (!domain->configured) {\n+\t\tresp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;\n+\t\treturn -1;\n+\t}\n+\n+\tif (domain->started) {\n+\t\tresp->status = DLB_ST_DOMAIN_STARTED;\n+\t\treturn -1;\n+\t}\n+\n+\t/* If the user claims the port is already configured, validate the port\n+\t * ID, its domain, and whether the port is configured.\n+\t */\n+\tif (args->port_id != -1) {\n+\t\tstruct dlb_dir_pq_pair *port;\n+\n+\t\tport = dlb_get_domain_used_dir_pq(args->port_id, domain);\n+\n+\t\tif (!port || port->domain_id != domain->id ||\n+\t\t    !port->port_configured) {\n+\t\t\tresp->status = DLB_ST_INVALID_PORT_ID;\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t/* If the queue's port is not configured, validate that a free\n+\t * port-queue pair is available.\n+\t */\n+\tif (args->port_id == -1 &&\n+\t    dlb_list_empty(&domain->avail_dir_pq_pairs)) {\n+\t\tresp->status = DLB_ST_DIR_QUEUES_UNAVAILABLE;\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void dlb_configure_dir_queue(struct dlb_hw *hw,\n+\t\t\t\t    struct dlb_domain *domain,\n+\t\t\t\t    struct dlb_dir_pq_pair *queue)\n+{\n+\tunion dlb_sys_dir_vasqid_v r0 = { {0} };\n+\tunion dlb_sys_dir_qid_v r1 = { {0} };\n+\tunsigned int offs;\n+\n+\t/* QID write permissions are turned on when the domain is started */\n+\tr0.field.vasqid_v = 0;\n+\n+\toffs = (domain->id * DLB_MAX_NUM_DIR_PORTS) + queue->id;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_VASQID_V(offs), r0.val);\n+\n+\tr1.field.qid_v = 1;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_QID_V(queue->id), r1.val);\n+\n+\tqueue->queue_configured = true;\n+}\n+\n+/**\n+ * dlb_hw_create_dir_queue() - Allocate and initialize a DLB DIR queue.\n+ * @hw:\t  Contains the current state of the DLB hardware.\n+ * @args: User-provided arguments.\n+ * @resp: Response to user.\n+ *\n+ * Return: returns < 0 on error, 0 otherwise. If the driver is unable to\n+ * satisfy a request, resp->status will be set accordingly.\n+ */\n+int dlb_hw_create_dir_queue(struct dlb_hw *hw,\n+\t\t\t    u32 domain_id,\n+\t\t\t    struct dlb_create_dir_queue_args *args,\n+\t\t\t    struct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_dir_pq_pair *queue;\n+\tstruct dlb_domain *domain;\n+\n+\tdlb_log_create_dir_queue_args(hw, domain_id, args);\n+\n+\t/* Verify that hardware resources are available before attempting to\n+\t * satisfy the request. This simplifies the error unwinding code.\n+\t */\n+\tif (dlb_verify_create_dir_queue_args(hw, domain_id, args, resp))\n+\t\treturn -EINVAL;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\tif (!domain) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: domain not found\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tif (args->port_id != -1)\n+\t\tqueue = dlb_get_domain_used_dir_pq(args->port_id, domain);\n+\telse\n+\t\tqueue = DLB_DOM_LIST_HEAD(domain->avail_dir_pq_pairs,\n+\t\t\t\t\t  typeof(*queue));\n+\n+\t/* Verification should catch this. */\n+\tif (!queue) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: no available dir queues\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tdlb_configure_dir_queue(hw, domain, queue);\n+\n+\t/* Configuration succeeded, so move the resource from the 'avail' to\n+\t * the 'used' list (if it's not already there).\n+\t */\n+\tif (args->port_id == -1) {\n+\t\tdlb_list_del(&domain->avail_dir_pq_pairs, &queue->domain_list);\n+\n+\t\tdlb_list_add(&domain->used_dir_pq_pairs, &queue->domain_list);\n+\t}\n+\n+\tresp->status = 0;\n+\n+\tresp->id = queue->id;\n+\n+\treturn 0;\n+}\n+\n+static void dlb_log_create_ldb_port_args(struct dlb_hw *hw,\n+\t\t\t\t\t u32 domain_id,\n+\t\t\t\t\t u64 pop_count_dma_base,\n+\t\t\t\t\t u64 cq_dma_base,\n+\t\t\t\t\t struct dlb_create_ldb_port_args *args)\n+{\n+\tDLB_HW_INFO(hw, \"DLB create load-balanced port arguments:\\n\");\n+\tDLB_HW_INFO(hw, \"\\tDomain ID:                 %d\\n\",\n+\t\t    domain_id);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit pool ID:        %d\\n\",\n+\t\t    args->ldb_credit_pool_id);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit high watermark: %d\\n\",\n+\t\t    args->ldb_credit_high_watermark);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit low watermark:  %d\\n\",\n+\t\t    args->ldb_credit_low_watermark);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit quantum:        %d\\n\",\n+\t\t    args->ldb_credit_quantum);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit pool ID:        %d\\n\",\n+\t\t    args->dir_credit_pool_id);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit high watermark: %d\\n\",\n+\t\t    args->dir_credit_high_watermark);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit low watermark:  %d\\n\",\n+\t\t    args->dir_credit_low_watermark);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit quantum:        %d\\n\",\n+\t\t    args->dir_credit_quantum);\n+\tDLB_HW_INFO(hw, \"\\tpop_count_address:         0x%\"PRIx64\"\\n\",\n+\t\t    pop_count_dma_base);\n+\tDLB_HW_INFO(hw, \"\\tCQ depth:                  %d\\n\",\n+\t\t    args->cq_depth);\n+\tDLB_HW_INFO(hw, \"\\tCQ hist list size:         %d\\n\",\n+\t\t    args->cq_history_list_size);\n+\tDLB_HW_INFO(hw, \"\\tCQ base address:           0x%\"PRIx64\"\\n\",\n+\t\t    cq_dma_base);\n+}\n+\n+static struct dlb_credit_pool *\n+dlb_get_domain_ldb_pool(u32 id, struct dlb_domain *domain)\n+{\n+\tstruct dlb_list_entry *iter;\n+\tstruct dlb_credit_pool *pool;\n+\tRTE_SET_USED(iter);\n+\n+\tif (id >= DLB_MAX_NUM_LDB_CREDIT_POOLS)\n+\t\treturn NULL;\n+\n+\tDLB_DOM_LIST_FOR(domain->used_ldb_credit_pools, pool, iter)\n+\t\tif (pool->id == id)\n+\t\t\treturn pool;\n+\n+\treturn NULL;\n+}\n+\n+static struct dlb_credit_pool *\n+dlb_get_domain_dir_pool(u32 id, struct dlb_domain *domain)\n+{\n+\tstruct dlb_list_entry *iter;\n+\tstruct dlb_credit_pool *pool;\n+\tRTE_SET_USED(iter);\n+\n+\tif (id >= DLB_MAX_NUM_DIR_CREDIT_POOLS)\n+\t\treturn NULL;\n+\n+\tDLB_DOM_LIST_FOR(domain->used_dir_credit_pools, pool, iter)\n+\t\tif (pool->id == id)\n+\t\t\treturn pool;\n+\n+\treturn NULL;\n+}\n+\n+static int\n+dlb_verify_create_ldb_port_args(struct dlb_hw *hw,\n+\t\t\t\tu32 domain_id,\n+\t\t\t\tu64 pop_count_dma_base,\n+\t\t\t\tu64 cq_dma_base,\n+\t\t\t\tstruct dlb_create_ldb_port_args *args,\n+\t\t\t\tstruct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_domain *domain;\n+\tstruct dlb_credit_pool *pool;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\n+\tif (!domain) {\n+\t\tresp->status = DLB_ST_INVALID_DOMAIN_ID;\n+\t\treturn -1;\n+\t}\n+\n+\tif (!domain->configured) {\n+\t\tresp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;\n+\t\treturn -1;\n+\t}\n+\n+\tif (domain->started) {\n+\t\tresp->status = DLB_ST_DOMAIN_STARTED;\n+\t\treturn -1;\n+\t}\n+\n+\tif (dlb_list_empty(&domain->avail_ldb_ports)) {\n+\t\tresp->status = DLB_ST_LDB_PORTS_UNAVAILABLE;\n+\t\treturn -1;\n+\t}\n+\n+\t/* If the scheduling domain has no LDB queues, we configure the\n+\t * hardware to not supply the port with any LDB credits. In that\n+\t * case, ignore the LDB credit arguments.\n+\t */\n+\tif (!dlb_list_empty(&domain->used_ldb_queues) ||\n+\t    !dlb_list_empty(&domain->avail_ldb_queues)) {\n+\t\tpool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t       domain);\n+\n+\t\tif (!pool || !pool->configured ||\n+\t\t    pool->domain_id != domain->id) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_POOL_ID;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_high_watermark > pool->avail_credits) {\n+\t\t\tresp->status = DLB_ST_LDB_CREDITS_UNAVAILABLE;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_low_watermark >=\n+\t\t    args->ldb_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_LOW_WATERMARK;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_quantum >=\n+\t\t    args->ldb_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_quantum > DLB_MAX_PORT_CREDIT_QUANTUM) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t/* Likewise, if the scheduling domain has no DIR queues, we configure\n+\t * the hardware to not supply the port with any DIR credits. In that\n+\t * case, ignore the DIR credit arguments.\n+\t */\n+\tif (!dlb_list_empty(&domain->used_dir_pq_pairs) ||\n+\t    !dlb_list_empty(&domain->avail_dir_pq_pairs)) {\n+\t\tpool = dlb_get_domain_dir_pool(args->dir_credit_pool_id,\n+\t\t\t\t\t       domain);\n+\n+\t\tif (!pool || !pool->configured ||\n+\t\t    pool->domain_id != domain->id) {\n+\t\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_POOL_ID;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->dir_credit_high_watermark > pool->avail_credits) {\n+\t\t\tresp->status = DLB_ST_DIR_CREDITS_UNAVAILABLE;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->dir_credit_low_watermark >=\n+\t\t    args->dir_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_LOW_WATERMARK;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->dir_credit_quantum >=\n+\t\t    args->dir_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->dir_credit_quantum > DLB_MAX_PORT_CREDIT_QUANTUM) {\n+\t\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t/* Check cache-line alignment */\n+\tif ((pop_count_dma_base & 0x3F) != 0) {\n+\t\tresp->status = DLB_ST_INVALID_POP_COUNT_VIRT_ADDR;\n+\t\treturn -1;\n+\t}\n+\n+\tif ((cq_dma_base & 0x3F) != 0) {\n+\t\tresp->status = DLB_ST_INVALID_CQ_VIRT_ADDR;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->cq_depth != 1 &&\n+\t    args->cq_depth != 2 &&\n+\t    args->cq_depth != 4 &&\n+\t    args->cq_depth != 8 &&\n+\t    args->cq_depth != 16 &&\n+\t    args->cq_depth != 32 &&\n+\t    args->cq_depth != 64 &&\n+\t    args->cq_depth != 128 &&\n+\t    args->cq_depth != 256 &&\n+\t    args->cq_depth != 512 &&\n+\t    args->cq_depth != 1024) {\n+\t\tresp->status = DLB_ST_INVALID_CQ_DEPTH;\n+\t\treturn -1;\n+\t}\n+\n+\t/* The history list size must be >= 1 */\n+\tif (!args->cq_history_list_size) {\n+\t\tresp->status = DLB_ST_INVALID_HIST_LIST_DEPTH;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->cq_history_list_size > domain->avail_hist_list_entries) {\n+\t\tresp->status = DLB_ST_HIST_LIST_ENTRIES_UNAVAILABLE;\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void dlb_ldb_pool_update_credit_count(struct dlb_hw *hw,\n+\t\t\t\t\t     u32 pool_id,\n+\t\t\t\t\t     u32 count)\n+{\n+\thw->rsrcs.ldb_credit_pools[pool_id].avail_credits -= count;\n+}\n+\n+static void dlb_dir_pool_update_credit_count(struct dlb_hw *hw,\n+\t\t\t\t\t     u32 pool_id,\n+\t\t\t\t\t     u32 count)\n+{\n+\thw->rsrcs.dir_credit_pools[pool_id].avail_credits -= count;\n+}\n+\n+static int dlb_ldb_port_configure_pp(struct dlb_hw *hw,\n+\t\t\t\t     struct dlb_domain *domain,\n+\t\t\t\t     struct dlb_ldb_port *port,\n+\t\t\t\t     struct dlb_create_ldb_port_args *args)\n+{\n+\tunion dlb_sys_ldb_pp2ldbpool r0 = { {0} };\n+\tunion dlb_sys_ldb_pp2dirpool r1 = { {0} };\n+\tunion dlb_sys_ldb_pp2vf_pf r2 = { {0} };\n+\tunion dlb_sys_ldb_pp2vas r3 = { {0} };\n+\tunion dlb_sys_ldb_pp_v r4 = { {0} };\n+\tunion dlb_chp_ldb_pp_ldb_crd_hwm r6 = { {0} };\n+\tunion dlb_chp_ldb_pp_dir_crd_hwm r7 = { {0} };\n+\tunion dlb_chp_ldb_pp_ldb_crd_lwm r8 = { {0} };\n+\tunion dlb_chp_ldb_pp_dir_crd_lwm r9 = { {0} };\n+\tunion dlb_chp_ldb_pp_ldb_min_crd_qnt r10 = { {0} };\n+\tunion dlb_chp_ldb_pp_dir_min_crd_qnt r11 = { {0} };\n+\tunion dlb_chp_ldb_pp_ldb_crd_cnt r12 = { {0} };\n+\tunion dlb_chp_ldb_pp_dir_crd_cnt r13 = { {0} };\n+\tunion dlb_chp_ldb_ldb_pp2pool r14 = { {0} };\n+\tunion dlb_chp_ldb_dir_pp2pool r15 = { {0} };\n+\tunion dlb_chp_ldb_pp_crd_req_state r16 = { {0} };\n+\tunion dlb_chp_ldb_pp_ldb_push_ptr r17 = { {0} };\n+\tunion dlb_chp_ldb_pp_dir_push_ptr r18 = { {0} };\n+\n+\tstruct dlb_credit_pool *ldb_pool = NULL;\n+\tstruct dlb_credit_pool *dir_pool = NULL;\n+\n+\tif (port->ldb_pool_used) {\n+\t\tldb_pool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!ldb_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\t}\n+\n+\tif (port->dir_pool_used) {\n+\t\tdir_pool = dlb_get_domain_dir_pool(args->dir_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!dir_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\t}\n+\n+\tr0.field.ldbpool = (port->ldb_pool_used) ? ldb_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP2LDBPOOL(port->id), r0.val);\n+\n+\tr1.field.dirpool = (port->dir_pool_used) ? dir_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP2DIRPOOL(port->id), r1.val);\n+\n+\tr2.field.is_pf = 1;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP2VF_PF(port->id), r2.val);\n+\n+\tr3.field.vas = domain->id;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP2VAS(port->id), r3.val);\n+\n+\tr6.field.hwm = args->ldb_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_LDB_CRD_HWM(port->id), r6.val);\n+\n+\tr7.field.hwm = args->dir_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_DIR_CRD_HWM(port->id), r7.val);\n+\n+\tr8.field.lwm = args->ldb_credit_low_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_LDB_CRD_LWM(port->id), r8.val);\n+\n+\tr9.field.lwm = args->dir_credit_low_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_DIR_CRD_LWM(port->id), r9.val);\n+\n+\tr10.field.quanta = args->ldb_credit_quantum;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_LDB_PP_LDB_MIN_CRD_QNT(port->id),\n+\t\t   r10.val);\n+\n+\tr11.field.quanta = args->dir_credit_quantum;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_LDB_PP_DIR_MIN_CRD_QNT(port->id),\n+\t\t   r11.val);\n+\n+\tr12.field.count = args->ldb_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_LDB_CRD_CNT(port->id), r12.val);\n+\n+\tr13.field.count = args->dir_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_DIR_CRD_CNT(port->id), r13.val);\n+\n+\tr14.field.pool = (port->ldb_pool_used) ? ldb_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_LDB_PP2POOL(port->id), r14.val);\n+\n+\tr15.field.pool = (port->dir_pool_used) ? dir_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_DIR_PP2POOL(port->id), r15.val);\n+\n+\tr16.field.no_pp_credit_update = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_CRD_REQ_STATE(port->id), r16.val);\n+\n+\tr17.field.push_pointer = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_LDB_PUSH_PTR(port->id), r17.val);\n+\n+\tr18.field.push_pointer = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_LDB_PP_DIR_PUSH_PTR(port->id), r18.val);\n+\n+\tr4.field.pp_v = 1;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_LDB_PP_V(port->id),\n+\t\t   r4.val);\n+\n+\treturn 0;\n+}\n+\n+static int dlb_ldb_port_configure_cq(struct dlb_hw *hw,\n+\t\t\t\t     struct dlb_ldb_port *port,\n+\t\t\t\t     u64 pop_count_dma_base,\n+\t\t\t\t     u64 cq_dma_base,\n+\t\t\t\t     struct dlb_create_ldb_port_args *args)\n+{\n+\tint i;\n+\n+\tunion dlb_sys_ldb_cq_addr_l r0 = { {0} };\n+\tunion dlb_sys_ldb_cq_addr_u r1 = { {0} };\n+\tunion dlb_sys_ldb_cq2vf_pf r2 = { {0} };\n+\tunion dlb_chp_ldb_cq_tkn_depth_sel r3 = { {0} };\n+\tunion dlb_chp_hist_list_lim r4 = { {0} };\n+\tunion dlb_chp_hist_list_base r5 = { {0} };\n+\tunion dlb_lsp_cq_ldb_infl_lim r6 = { {0} };\n+\tunion dlb_lsp_cq2priov r7 = { {0} };\n+\tunion dlb_chp_hist_list_push_ptr r8 = { {0} };\n+\tunion dlb_chp_hist_list_pop_ptr r9 = { {0} };\n+\tunion dlb_lsp_cq_ldb_tkn_depth_sel r10 = { {0} };\n+\tunion dlb_sys_ldb_pp_addr_l r11 = { {0} };\n+\tunion dlb_sys_ldb_pp_addr_u r12 = { {0} };\n+\n+\t/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */\n+\tr0.field.addr_l = cq_dma_base >> 6;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_LDB_CQ_ADDR_L(port->id),\n+\t\t   r0.val);\n+\n+\tr1.field.addr_u = cq_dma_base >> 32;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_LDB_CQ_ADDR_U(port->id),\n+\t\t   r1.val);\n+\n+\tr2.field.is_pf = 1;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_LDB_CQ2VF_PF(port->id),\n+\t\t   r2.val);\n+\n+\tif (args->cq_depth <= 8) {\n+\t\tr3.field.token_depth_select = 1;\n+\t} else if (args->cq_depth == 16) {\n+\t\tr3.field.token_depth_select = 2;\n+\t} else if (args->cq_depth == 32) {\n+\t\tr3.field.token_depth_select = 3;\n+\t} else if (args->cq_depth == 64) {\n+\t\tr3.field.token_depth_select = 4;\n+\t} else if (args->cq_depth == 128) {\n+\t\tr3.field.token_depth_select = 5;\n+\t} else if (args->cq_depth == 256) {\n+\t\tr3.field.token_depth_select = 6;\n+\t} else if (args->cq_depth == 512) {\n+\t\tr3.field.token_depth_select = 7;\n+\t} else if (args->cq_depth == 1024) {\n+\t\tr3.field.token_depth_select = 8;\n+\t} else {\n+\t\tDLB_HW_ERR(hw, \"[%s():%d] Internal error: invalid CQ depth\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_LDB_CQ_TKN_DEPTH_SEL(port->id),\n+\t\t   r3.val);\n+\n+\tr10.field.token_depth_select = r3.field.token_depth_select;\n+\tr10.field.ignore_depth = 0;\n+\t/* TDT algorithm: DLB must be able to write CQs with depth < 4 */\n+\tr10.field.enab_shallow_cq = 1;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_LSP_CQ_LDB_TKN_DEPTH_SEL(port->id),\n+\t\t   r10.val);\n+\n+\t/* To support CQs with depth less than 8, program the token count\n+\t * register with a non-zero initial value. Operations such as domain\n+\t * reset must take this initial value into account when quiescing the\n+\t * CQ.\n+\t */\n+\tport->init_tkn_cnt = 0;\n+\n+\tif (args->cq_depth < 8) {\n+\t\tunion dlb_lsp_cq_ldb_tkn_cnt r12 = { {0} };\n+\n+\t\tport->init_tkn_cnt = 8 - args->cq_depth;\n+\n+\t\tr12.field.token_count = port->init_tkn_cnt;\n+\n+\t\tDLB_CSR_WR(hw,\n+\t\t\t   DLB_LSP_CQ_LDB_TKN_CNT(port->id),\n+\t\t\t   r12.val);\n+\t}\n+\n+\tr4.field.limit = port->hist_list_entry_limit - 1;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_HIST_LIST_LIM(port->id), r4.val);\n+\n+\tr5.field.base = port->hist_list_entry_base;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_HIST_LIST_BASE(port->id), r5.val);\n+\n+\tr8.field.push_ptr = r5.field.base;\n+\tr8.field.generation = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_HIST_LIST_PUSH_PTR(port->id), r8.val);\n+\n+\tr9.field.pop_ptr = r5.field.base;\n+\tr9.field.generation = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_CHP_HIST_LIST_POP_PTR(port->id), r9.val);\n+\n+\t/* The inflight limit sets a cap on the number of QEs for which this CQ\n+\t * can owe completions at one time.\n+\t */\n+\tr6.field.limit = args->cq_history_list_size;\n+\n+\tDLB_CSR_WR(hw, DLB_LSP_CQ_LDB_INFL_LIM(port->id), r6.val);\n+\n+\t/* Disable the port's QID mappings */\n+\tr7.field.v = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_LSP_CQ2PRIOV(port->id), r7.val);\n+\n+\t/* Two cache lines (128B) are dedicated for the port's pop counts */\n+\tr11.field.addr_l = pop_count_dma_base >> 7;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP_ADDR_L(port->id), r11.val);\n+\n+\tr12.field.addr_u = pop_count_dma_base >> 32;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_LDB_PP_ADDR_U(port->id), r12.val);\n+\n+\tfor (i = 0; i < DLB_MAX_NUM_QIDS_PER_LDB_CQ; i++)\n+\t\tport->qid_map[i].state = DLB_QUEUE_UNMAPPED;\n+\n+\treturn 0;\n+}\n+\n+static void dlb_update_ldb_arb_threshold(struct dlb_hw *hw)\n+{\n+\tunion dlb_lsp_ctrl_config_0 r0 = { {0} };\n+\n+\t/* From the hardware spec:\n+\t * \"The optimal value for ldb_arb_threshold is in the region of {8 *\n+\t * #CQs}. It is expected therefore that the PF will change this value\n+\t * dynamically as the number of active ports changes.\"\n+\t */\n+\tr0.val = DLB_CSR_RD(hw, DLB_LSP_CTRL_CONFIG_0);\n+\n+\tr0.field.ldb_arb_threshold = hw->pf.num_enabled_ldb_ports * 8;\n+\tr0.field.ldb_arb_ignore_empty = 1;\n+\tr0.field.ldb_arb_mode = 1;\n+\n+\tDLB_CSR_WR(hw, DLB_LSP_CTRL_CONFIG_0, r0.val);\n+\n+\tdlb_flush_csr(hw);\n+}\n+\n+static int dlb_configure_ldb_port(struct dlb_hw *hw,\n+\t\t\t\t  struct dlb_domain *domain,\n+\t\t\t\t  struct dlb_ldb_port *port,\n+\t\t\t\t  u64 pop_count_dma_base,\n+\t\t\t\t  u64 cq_dma_base,\n+\t\t\t\t  struct dlb_create_ldb_port_args *args)\n+{\n+\tstruct dlb_credit_pool *ldb_pool, *dir_pool;\n+\tint ret;\n+\n+\tport->hist_list_entry_base = domain->hist_list_entry_base +\n+\t\t\t\t     domain->hist_list_entry_offset;\n+\tport->hist_list_entry_limit = port->hist_list_entry_base +\n+\t\t\t\t      args->cq_history_list_size;\n+\n+\tdomain->hist_list_entry_offset += args->cq_history_list_size;\n+\tdomain->avail_hist_list_entries -= args->cq_history_list_size;\n+\n+\tport->ldb_pool_used = !dlb_list_empty(&domain->used_ldb_queues) ||\n+\t\t\t      !dlb_list_empty(&domain->avail_ldb_queues);\n+\tport->dir_pool_used = !dlb_list_empty(&domain->used_dir_pq_pairs) ||\n+\t\t\t      !dlb_list_empty(&domain->avail_dir_pq_pairs);\n+\n+\tif (port->ldb_pool_used) {\n+\t\tu32 cnt = args->ldb_credit_high_watermark;\n+\n+\t\tldb_pool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!ldb_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\n+\t\tdlb_ldb_pool_update_credit_count(hw, ldb_pool->id, cnt);\n+\t} else {\n+\t\targs->ldb_credit_high_watermark = 0;\n+\t\targs->ldb_credit_low_watermark = 0;\n+\t\targs->ldb_credit_quantum = 0;\n+\t}\n+\n+\tif (port->dir_pool_used) {\n+\t\tu32 cnt = args->dir_credit_high_watermark;\n+\n+\t\tdir_pool = dlb_get_domain_dir_pool(args->dir_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!dir_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\n+\t\tdlb_dir_pool_update_credit_count(hw, dir_pool->id, cnt);\n+\t} else {\n+\t\targs->dir_credit_high_watermark = 0;\n+\t\targs->dir_credit_low_watermark = 0;\n+\t\targs->dir_credit_quantum = 0;\n+\t}\n+\n+\tret = dlb_ldb_port_configure_cq(hw,\n+\t\t\t\t\tport,\n+\t\t\t\t\tpop_count_dma_base,\n+\t\t\t\t\tcq_dma_base,\n+\t\t\t\t\targs);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = dlb_ldb_port_configure_pp(hw, domain, port, args);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tdlb_ldb_port_cq_enable(hw, port);\n+\n+\tport->num_mappings = 0;\n+\n+\tport->enabled = true;\n+\n+\thw->pf.num_enabled_ldb_ports++;\n+\n+\tdlb_update_ldb_arb_threshold(hw);\n+\n+\tport->configured = true;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * dlb_hw_create_ldb_port() - Allocate and initialize a load-balanced port and\n+ *\tits resources.\n+ * @hw:\t  Contains the current state of the DLB hardware.\n+ * @args: User-provided arguments.\n+ * @resp: Response to user.\n+ *\n+ * Return: returns < 0 on error, 0 otherwise. If the driver is unable to\n+ * satisfy a request, resp->status will be set accordingly.\n+ */\n+int dlb_hw_create_ldb_port(struct dlb_hw *hw,\n+\t\t\t   u32 domain_id,\n+\t\t\t   struct dlb_create_ldb_port_args *args,\n+\t\t\t   u64 pop_count_dma_base,\n+\t\t\t   u64 cq_dma_base,\n+\t\t\t   struct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_ldb_port *port;\n+\tstruct dlb_domain *domain;\n+\tint ret;\n+\n+\tdlb_log_create_ldb_port_args(hw,\n+\t\t\t\t     domain_id,\n+\t\t\t\t     pop_count_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     args);\n+\n+\t/* Verify that hardware resources are available before attempting to\n+\t * satisfy the request. This simplifies the error unwinding code.\n+\t */\n+\tif (dlb_verify_create_ldb_port_args(hw,\n+\t\t\t\t\t    domain_id,\n+\t\t\t\t\t    pop_count_dma_base,\n+\t\t\t\t\t    cq_dma_base,\n+\t\t\t\t\t    args,\n+\t\t\t\t\t    resp))\n+\t\treturn -EINVAL;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\tif (!domain) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: domain not found\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tport = DLB_DOM_LIST_HEAD(domain->avail_ldb_ports, typeof(*port));\n+\n+\t/* Verification should catch this. */\n+\tif (!port) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: no available ldb ports\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tif (port->configured) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s()] Internal error: avail_ldb_ports contains configured ports.\\n\",\n+\t\t\t   __func__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tret = dlb_configure_ldb_port(hw,\n+\t\t\t\t     domain,\n+\t\t\t\t     port,\n+\t\t\t\t     pop_count_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     args);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t/* Configuration succeeded, so move the resource from the 'avail' to\n+\t * the 'used' list.\n+\t */\n+\tdlb_list_del(&domain->avail_ldb_ports, &port->domain_list);\n+\n+\tdlb_list_add(&domain->used_ldb_ports, &port->domain_list);\n+\n+\tresp->status = 0;\n+\tresp->id = port->id;\n+\n+\treturn 0;\n+}\n+\n+static void dlb_log_create_dir_port_args(struct dlb_hw *hw,\n+\t\t\t\t\t u32 domain_id,\n+\t\t\t\t\t u64 pop_count_dma_base,\n+\t\t\t\t\t u64 cq_dma_base,\n+\t\t\t\t\t struct dlb_create_dir_port_args *args)\n+{\n+\tDLB_HW_INFO(hw, \"DLB create directed port arguments:\\n\");\n+\tDLB_HW_INFO(hw, \"\\tDomain ID:                 %d\\n\",\n+\t\t    domain_id);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit pool ID:        %d\\n\",\n+\t\t    args->ldb_credit_pool_id);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit high watermark: %d\\n\",\n+\t\t    args->ldb_credit_high_watermark);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit low watermark:  %d\\n\",\n+\t\t    args->ldb_credit_low_watermark);\n+\tDLB_HW_INFO(hw, \"\\tLDB credit quantum:        %d\\n\",\n+\t\t    args->ldb_credit_quantum);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit pool ID:        %d\\n\",\n+\t\t    args->dir_credit_pool_id);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit high watermark: %d\\n\",\n+\t\t    args->dir_credit_high_watermark);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit low watermark:  %d\\n\",\n+\t\t    args->dir_credit_low_watermark);\n+\tDLB_HW_INFO(hw, \"\\tDIR credit quantum:        %d\\n\",\n+\t\t    args->dir_credit_quantum);\n+\tDLB_HW_INFO(hw, \"\\tpop_count_address:         0x%\"PRIx64\"\\n\",\n+\t\t    pop_count_dma_base);\n+\tDLB_HW_INFO(hw, \"\\tCQ depth:                  %d\\n\",\n+\t\t    args->cq_depth);\n+\tDLB_HW_INFO(hw, \"\\tCQ base address:           0x%\"PRIx64\"\\n\",\n+\t\t    cq_dma_base);\n+}\n+\n+static int\n+dlb_verify_create_dir_port_args(struct dlb_hw *hw,\n+\t\t\t\tu32 domain_id,\n+\t\t\t\tu64 pop_count_dma_base,\n+\t\t\t\tu64 cq_dma_base,\n+\t\t\t\tstruct dlb_create_dir_port_args *args,\n+\t\t\t\tstruct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_domain *domain;\n+\tstruct dlb_credit_pool *pool;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\n+\tif (!domain) {\n+\t\tresp->status = DLB_ST_INVALID_DOMAIN_ID;\n+\t\treturn -1;\n+\t}\n+\n+\tif (!domain->configured) {\n+\t\tresp->status = DLB_ST_DOMAIN_NOT_CONFIGURED;\n+\t\treturn -1;\n+\t}\n+\n+\tif (domain->started) {\n+\t\tresp->status = DLB_ST_DOMAIN_STARTED;\n+\t\treturn -1;\n+\t}\n+\n+\t/* If the user claims the queue is already configured, validate\n+\t * the queue ID, its domain, and whether the queue is configured.\n+\t */\n+\tif (args->queue_id != -1) {\n+\t\tstruct dlb_dir_pq_pair *queue;\n+\n+\t\tqueue = dlb_get_domain_used_dir_pq(args->queue_id,\n+\t\t\t\t\t\t   domain);\n+\n+\t\tif (!queue || queue->domain_id != domain->id ||\n+\t\t    !queue->queue_configured) {\n+\t\t\tresp->status = DLB_ST_INVALID_DIR_QUEUE_ID;\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t/* If the port's queue is not configured, validate that a free\n+\t * port-queue pair is available.\n+\t */\n+\tif (args->queue_id == -1 &&\n+\t    dlb_list_empty(&domain->avail_dir_pq_pairs)) {\n+\t\tresp->status = DLB_ST_DIR_PORTS_UNAVAILABLE;\n+\t\treturn -1;\n+\t}\n+\n+\t/* If the scheduling domain has no LDB queues, we configure the\n+\t * hardware to not supply the port with any LDB credits. In that\n+\t * case, ignore the LDB credit arguments.\n+\t */\n+\tif (!dlb_list_empty(&domain->used_ldb_queues) ||\n+\t    !dlb_list_empty(&domain->avail_ldb_queues)) {\n+\t\tpool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t       domain);\n+\n+\t\tif (!pool || !pool->configured ||\n+\t\t    pool->domain_id != domain->id) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_POOL_ID;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_high_watermark > pool->avail_credits) {\n+\t\t\tresp->status = DLB_ST_LDB_CREDITS_UNAVAILABLE;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_low_watermark >=\n+\t\t    args->ldb_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_LOW_WATERMARK;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_quantum >=\n+\t\t    args->ldb_credit_high_watermark) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (args->ldb_credit_quantum > DLB_MAX_PORT_CREDIT_QUANTUM) {\n+\t\t\tresp->status = DLB_ST_INVALID_LDB_CREDIT_QUANTUM;\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tpool = dlb_get_domain_dir_pool(args->dir_credit_pool_id,\n+\t\t\t\t       domain);\n+\n+\tif (!pool || !pool->configured ||\n+\t    pool->domain_id != domain->id) {\n+\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_POOL_ID;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->dir_credit_high_watermark > pool->avail_credits) {\n+\t\tresp->status = DLB_ST_DIR_CREDITS_UNAVAILABLE;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->dir_credit_low_watermark >= args->dir_credit_high_watermark) {\n+\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_LOW_WATERMARK;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->dir_credit_quantum >= args->dir_credit_high_watermark) {\n+\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_QUANTUM;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->dir_credit_quantum > DLB_MAX_PORT_CREDIT_QUANTUM) {\n+\t\tresp->status = DLB_ST_INVALID_DIR_CREDIT_QUANTUM;\n+\t\treturn -1;\n+\t}\n+\n+\t/* Check cache-line alignment */\n+\tif ((pop_count_dma_base & 0x3F) != 0) {\n+\t\tresp->status = DLB_ST_INVALID_POP_COUNT_VIRT_ADDR;\n+\t\treturn -1;\n+\t}\n+\n+\tif ((cq_dma_base & 0x3F) != 0) {\n+\t\tresp->status = DLB_ST_INVALID_CQ_VIRT_ADDR;\n+\t\treturn -1;\n+\t}\n+\n+\tif (args->cq_depth != 8 &&\n+\t    args->cq_depth != 16 &&\n+\t    args->cq_depth != 32 &&\n+\t    args->cq_depth != 64 &&\n+\t    args->cq_depth != 128 &&\n+\t    args->cq_depth != 256 &&\n+\t    args->cq_depth != 512 &&\n+\t    args->cq_depth != 1024) {\n+\t\tresp->status = DLB_ST_INVALID_CQ_DEPTH;\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int dlb_dir_port_configure_pp(struct dlb_hw *hw,\n+\t\t\t\t     struct dlb_domain *domain,\n+\t\t\t\t     struct dlb_dir_pq_pair *port,\n+\t\t\t\t     struct dlb_create_dir_port_args *args)\n+{\n+\tunion dlb_sys_dir_pp2ldbpool r0 = { {0} };\n+\tunion dlb_sys_dir_pp2dirpool r1 = { {0} };\n+\tunion dlb_sys_dir_pp2vf_pf r2 = { {0} };\n+\tunion dlb_sys_dir_pp2vas r3 = { {0} };\n+\tunion dlb_sys_dir_pp_v r4 = { {0} };\n+\tunion dlb_chp_dir_pp_ldb_crd_hwm r6 = { {0} };\n+\tunion dlb_chp_dir_pp_dir_crd_hwm r7 = { {0} };\n+\tunion dlb_chp_dir_pp_ldb_crd_lwm r8 = { {0} };\n+\tunion dlb_chp_dir_pp_dir_crd_lwm r9 = { {0} };\n+\tunion dlb_chp_dir_pp_ldb_min_crd_qnt r10 = { {0} };\n+\tunion dlb_chp_dir_pp_dir_min_crd_qnt r11 = { {0} };\n+\tunion dlb_chp_dir_pp_ldb_crd_cnt r12 = { {0} };\n+\tunion dlb_chp_dir_pp_dir_crd_cnt r13 = { {0} };\n+\tunion dlb_chp_dir_ldb_pp2pool r14 = { {0} };\n+\tunion dlb_chp_dir_dir_pp2pool r15 = { {0} };\n+\tunion dlb_chp_dir_pp_crd_req_state r16 = { {0} };\n+\tunion dlb_chp_dir_pp_ldb_push_ptr r17 = { {0} };\n+\tunion dlb_chp_dir_pp_dir_push_ptr r18 = { {0} };\n+\n+\tstruct dlb_credit_pool *ldb_pool = NULL;\n+\tstruct dlb_credit_pool *dir_pool = NULL;\n+\n+\tif (port->ldb_pool_used) {\n+\t\tldb_pool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!ldb_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\t}\n+\n+\tif (port->dir_pool_used) {\n+\t\tdir_pool = dlb_get_domain_dir_pool(args->dir_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!dir_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\t}\n+\n+\tr0.field.ldbpool = (port->ldb_pool_used) ? ldb_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_DIR_PP2LDBPOOL(port->id),\n+\t\t   r0.val);\n+\n+\tr1.field.dirpool = (port->dir_pool_used) ? dir_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_DIR_PP2DIRPOOL(port->id),\n+\t\t   r1.val);\n+\n+\tr2.field.is_pf = 1;\n+\tr2.field.is_hw_dsi = 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_DIR_PP2VF_PF(port->id),\n+\t\t   r2.val);\n+\n+\tr3.field.vas = domain->id;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_SYS_DIR_PP2VAS(port->id),\n+\t\t   r3.val);\n+\n+\tr6.field.hwm = args->ldb_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_LDB_CRD_HWM(port->id),\n+\t\t   r6.val);\n+\n+\tr7.field.hwm = args->dir_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_DIR_CRD_HWM(port->id),\n+\t\t   r7.val);\n+\n+\tr8.field.lwm = args->ldb_credit_low_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_LDB_CRD_LWM(port->id),\n+\t\t   r8.val);\n+\n+\tr9.field.lwm = args->dir_credit_low_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_DIR_CRD_LWM(port->id),\n+\t\t   r9.val);\n+\n+\tr10.field.quanta = args->ldb_credit_quantum;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_LDB_MIN_CRD_QNT(port->id),\n+\t\t   r10.val);\n+\n+\tr11.field.quanta = args->dir_credit_quantum;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_DIR_MIN_CRD_QNT(port->id),\n+\t\t   r11.val);\n+\n+\tr12.field.count = args->ldb_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_LDB_CRD_CNT(port->id),\n+\t\t   r12.val);\n+\n+\tr13.field.count = args->dir_credit_high_watermark;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_DIR_CRD_CNT(port->id),\n+\t\t   r13.val);\n+\n+\tr14.field.pool = (port->ldb_pool_used) ? ldb_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_LDB_PP2POOL(port->id),\n+\t\t   r14.val);\n+\n+\tr15.field.pool = (port->dir_pool_used) ? dir_pool->id : 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_DIR_PP2POOL(port->id),\n+\t\t   r15.val);\n+\n+\tr16.field.no_pp_credit_update = 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_CRD_REQ_STATE(port->id),\n+\t\t   r16.val);\n+\n+\tr17.field.push_pointer = 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_LDB_PUSH_PTR(port->id),\n+\t\t   r17.val);\n+\n+\tr18.field.push_pointer = 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_PP_DIR_PUSH_PTR(port->id),\n+\t\t   r18.val);\n+\n+\tr4.field.pp_v = 1;\n+\tr4.field.mb_dm = 0;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_PP_V(port->id), r4.val);\n+\n+\treturn 0;\n+}\n+\n+static int dlb_dir_port_configure_cq(struct dlb_hw *hw,\n+\t\t\t\t     struct dlb_dir_pq_pair *port,\n+\t\t\t\t     u64 pop_count_dma_base,\n+\t\t\t\t     u64 cq_dma_base,\n+\t\t\t\t     struct dlb_create_dir_port_args *args)\n+{\n+\tunion dlb_sys_dir_cq_addr_l r0 = { {0} };\n+\tunion dlb_sys_dir_cq_addr_u r1 = { {0} };\n+\tunion dlb_sys_dir_cq2vf_pf r2 = { {0} };\n+\tunion dlb_chp_dir_cq_tkn_depth_sel r3 = { {0} };\n+\tunion dlb_lsp_cq_dir_tkn_depth_sel_dsi r4 = { {0} };\n+\tunion dlb_sys_dir_pp_addr_l r5 = { {0} };\n+\tunion dlb_sys_dir_pp_addr_u r6 = { {0} };\n+\n+\t/* The CQ address is 64B-aligned, and the DLB only wants bits [63:6] */\n+\tr0.field.addr_l = cq_dma_base >> 6;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_CQ_ADDR_L(port->id), r0.val);\n+\n+\tr1.field.addr_u = cq_dma_base >> 32;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_CQ_ADDR_U(port->id), r1.val);\n+\n+\tr2.field.is_pf = 1;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_CQ2VF_PF(port->id), r2.val);\n+\n+\tif (args->cq_depth == 8) {\n+\t\tr3.field.token_depth_select = 1;\n+\t} else if (args->cq_depth == 16) {\n+\t\tr3.field.token_depth_select = 2;\n+\t} else if (args->cq_depth == 32) {\n+\t\tr3.field.token_depth_select = 3;\n+\t} else if (args->cq_depth == 64) {\n+\t\tr3.field.token_depth_select = 4;\n+\t} else if (args->cq_depth == 128) {\n+\t\tr3.field.token_depth_select = 5;\n+\t} else if (args->cq_depth == 256) {\n+\t\tr3.field.token_depth_select = 6;\n+\t} else if (args->cq_depth == 512) {\n+\t\tr3.field.token_depth_select = 7;\n+\t} else if (args->cq_depth == 1024) {\n+\t\tr3.field.token_depth_select = 8;\n+\t} else {\n+\t\tDLB_HW_ERR(hw, \"[%s():%d] Internal error: invalid CQ depth\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_CHP_DIR_CQ_TKN_DEPTH_SEL(port->id),\n+\t\t   r3.val);\n+\n+\tr4.field.token_depth_select = r3.field.token_depth_select;\n+\tr4.field.disable_wb_opt = 0;\n+\n+\tDLB_CSR_WR(hw,\n+\t\t   DLB_LSP_CQ_DIR_TKN_DEPTH_SEL_DSI(port->id),\n+\t\t   r4.val);\n+\n+\t/* Two cache lines (128B) are dedicated for the port's pop counts */\n+\tr5.field.addr_l = pop_count_dma_base >> 7;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_PP_ADDR_L(port->id), r5.val);\n+\n+\tr6.field.addr_u = pop_count_dma_base >> 32;\n+\n+\tDLB_CSR_WR(hw, DLB_SYS_DIR_PP_ADDR_U(port->id), r6.val);\n+\n+\treturn 0;\n+}\n+\n+static int dlb_configure_dir_port(struct dlb_hw *hw,\n+\t\t\t\t  struct dlb_domain *domain,\n+\t\t\t\t  struct dlb_dir_pq_pair *port,\n+\t\t\t\t  u64 pop_count_dma_base,\n+\t\t\t\t  u64 cq_dma_base,\n+\t\t\t\t  struct dlb_create_dir_port_args *args)\n+{\n+\tstruct dlb_credit_pool *ldb_pool, *dir_pool;\n+\tint ret;\n+\n+\tport->ldb_pool_used = !dlb_list_empty(&domain->used_ldb_queues) ||\n+\t\t\t      !dlb_list_empty(&domain->avail_ldb_queues);\n+\n+\t/* Each directed port has a directed queue, hence this port requires\n+\t * directed credits.\n+\t */\n+\tport->dir_pool_used = true;\n+\n+\tif (port->ldb_pool_used) {\n+\t\tu32 cnt = args->ldb_credit_high_watermark;\n+\n+\t\tldb_pool = dlb_get_domain_ldb_pool(args->ldb_credit_pool_id,\n+\t\t\t\t\t\t   domain);\n+\t\tif (!ldb_pool) {\n+\t\t\tDLB_HW_ERR(hw,\n+\t\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t\t   __func__);\n+\t\t\treturn -EFAULT;\n+\t\t}\n+\n+\t\tdlb_ldb_pool_update_credit_count(hw, ldb_pool->id, cnt);\n+\t} else {\n+\t\targs->ldb_credit_high_watermark = 0;\n+\t\targs->ldb_credit_low_watermark = 0;\n+\t\targs->ldb_credit_quantum = 0;\n+\t}\n+\n+\tdir_pool = dlb_get_domain_dir_pool(args->dir_credit_pool_id, domain);\n+\tif (!dir_pool) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s()] Internal error: port validation failed\\n\",\n+\t\t\t   __func__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tdlb_dir_pool_update_credit_count(hw,\n+\t\t\t\t\t dir_pool->id,\n+\t\t\t\t\t args->dir_credit_high_watermark);\n+\n+\tret = dlb_dir_port_configure_cq(hw,\n+\t\t\t\t\tport,\n+\t\t\t\t\tpop_count_dma_base,\n+\t\t\t\t\tcq_dma_base,\n+\t\t\t\t\targs);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = dlb_dir_port_configure_pp(hw, domain, port, args);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tdlb_dir_port_cq_enable(hw, port);\n+\n+\tport->enabled = true;\n+\n+\tport->port_configured = true;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * dlb_hw_create_dir_port() - Allocate and initialize a DLB directed port and\n+ *\tqueue. The port/queue pair have the same ID and name.\n+ * @hw:\t  Contains the current state of the DLB hardware.\n+ * @args: User-provided arguments.\n+ * @resp: Response to user.\n+ *\n+ * Return: returns < 0 on error, 0 otherwise. If the driver is unable to\n+ * satisfy a request, resp->status will be set accordingly.\n+ */\n+int dlb_hw_create_dir_port(struct dlb_hw *hw,\n+\t\t\t   u32 domain_id,\n+\t\t\t   struct dlb_create_dir_port_args *args,\n+\t\t\t   u64 pop_count_dma_base,\n+\t\t\t   u64 cq_dma_base,\n+\t\t\t   struct dlb_cmd_response *resp)\n+{\n+\tstruct dlb_dir_pq_pair *port;\n+\tstruct dlb_domain *domain;\n+\tint ret;\n+\n+\tdlb_log_create_dir_port_args(hw,\n+\t\t\t\t     domain_id,\n+\t\t\t\t     pop_count_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     args);\n+\n+\t/* Verify that hardware resources are available before attempting to\n+\t * satisfy the request. This simplifies the error unwinding code.\n+\t */\n+\tif (dlb_verify_create_dir_port_args(hw,\n+\t\t\t\t\t    domain_id,\n+\t\t\t\t\t    pop_count_dma_base,\n+\t\t\t\t\t    cq_dma_base,\n+\t\t\t\t\t    args,\n+\t\t\t\t\t    resp))\n+\t\treturn -EINVAL;\n+\n+\tdomain = dlb_get_domain_from_id(hw, domain_id);\n+\tif (!domain) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: domain not found\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tif (args->queue_id != -1)\n+\t\tport = dlb_get_domain_used_dir_pq(args->queue_id,\n+\t\t\t\t\t\t  domain);\n+\telse\n+\t\tport = DLB_DOM_LIST_HEAD(domain->avail_dir_pq_pairs,\n+\t\t\t\t\t typeof(*port));\n+\n+\t/* Verification should catch this. */\n+\tif (!port) {\n+\t\tDLB_HW_ERR(hw,\n+\t\t\t   \"[%s():%d] Internal error: no available dir ports\\n\",\n+\t\t\t   __func__, __LINE__);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tret = dlb_configure_dir_port(hw,\n+\t\t\t\t     domain,\n+\t\t\t\t     port,\n+\t\t\t\t     pop_count_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     args);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t/* Configuration succeeded, so move the resource from the 'avail' to\n+\t * the 'used' list (if it's not already there).\n+\t */\n+\tif (args->queue_id == -1) {\n+\t\tdlb_list_del(&domain->avail_dir_pq_pairs, &port->domain_list);\n+\n+\t\tdlb_list_add(&domain->used_dir_pq_pairs, &port->domain_list);\n+\t}\n+\n+\tresp->status = 0;\n+\tresp->id = port->id;\n+\n+\treturn 0;\n+}\n+\ndiff --git a/drivers/event/dlb/pf/dlb_pf.c b/drivers/event/dlb/pf/dlb_pf.c\nindex fffb88b..cd766d3 100644\n--- a/drivers/event/dlb/pf/dlb_pf.c\n+++ b/drivers/event/dlb/pf/dlb_pf.c\n@@ -221,6 +221,207 @@ dlb_pf_ldb_queue_create(struct dlb_hw_dev *handle,\n }\n \n static int\n+dlb_pf_dir_queue_create(struct dlb_hw_dev *handle,\n+\t\t\tstruct dlb_create_dir_queue_args *cfg)\n+{\n+\tstruct dlb_dev *dlb_dev = (struct dlb_dev *)handle->pf_dev;\n+\tstruct dlb_cmd_response response = {0};\n+\tint ret;\n+\n+\tDLB_INFO(dev->dlb_device, \"Entering %s()\\n\", __func__);\n+\n+\tret = dlb_hw_create_dir_queue(&dlb_dev->hw,\n+\t\t\t\t      handle->domain_id,\n+\t\t\t\t      cfg,\n+\t\t\t\t      &response);\n+\n+\t*(struct dlb_cmd_response *)cfg->response = response;\n+\n+\tDLB_INFO(dev->dlb_device, \"Exiting %s() with ret=%d\\n\", __func__, ret);\n+\n+\treturn ret;\n+}\n+\n+static void *\n+dlb_alloc_coherent_aligned(rte_iova_t *phys, size_t size, int align)\n+{\n+\tconst struct rte_memzone *mz;\n+\tchar mz_name[RTE_MEMZONE_NAMESIZE];\n+\tuint32_t core_id = rte_lcore_id();\n+\tunsigned int socket_id;\n+\n+\tsnprintf(mz_name, sizeof(mz_name) - 1, \"%lx\",\n+\t\t (unsigned long)rte_get_timer_cycles());\n+\tif (core_id == (unsigned int)LCORE_ID_ANY)\n+\t\tcore_id = rte_get_master_lcore();\n+\tsocket_id = rte_lcore_to_socket_id(core_id);\n+\tmz = rte_memzone_reserve_aligned(mz_name, size, socket_id,\n+\t\t\t\t\t RTE_MEMZONE_IOVA_CONTIG, align);\n+\tif (!mz) {\n+\t\tDLB_LOG_ERR(\"Unable to allocate DMA memory of size %zu bytes\\n\",\n+\t\t\t    size);\n+\t\t*phys = 0;\n+\t\treturn NULL;\n+\t}\n+\t*phys = mz->iova;\n+\treturn mz->addr;\n+}\n+\n+static int\n+dlb_pf_ldb_port_create(struct dlb_hw_dev *handle,\n+\t\t       struct dlb_create_ldb_port_args *cfg,\n+\t\t       enum dlb_cq_poll_modes poll_mode)\n+{\n+\tstruct dlb_dev *dlb_dev = (struct dlb_dev *)handle->pf_dev;\n+\tstruct dlb_cmd_response response = {0};\n+\tint ret;\n+\tuint8_t *port_base;\n+\tint alloc_sz, qe_sz, cq_alloc_depth;\n+\trte_iova_t pp_dma_base;\n+\trte_iova_t pc_dma_base;\n+\trte_iova_t cq_dma_base;\n+\tint is_dir = false;\n+\n+\tDLB_INFO(dev->dlb_device, \"Entering %s()\\n\", __func__);\n+\n+\tif (poll_mode == DLB_CQ_POLL_MODE_STD)\n+\t\tqe_sz = sizeof(struct dlb_dequeue_qe);\n+\telse\n+\t\tqe_sz = RTE_CACHE_LINE_SIZE;\n+\n+\t/* The hardware always uses a CQ depth of at least\n+\t * DLB_MIN_HARDWARE_CQ_DEPTH, even though from the user\n+\t * perspective we support a depth as low as 1 for LDB ports.\n+\t */\n+\tcq_alloc_depth = RTE_MAX(cfg->cq_depth, DLB_MIN_HARDWARE_CQ_DEPTH);\n+\n+\t/* Calculate the port memory required, including two cache lines for\n+\t * credit pop counts. Round up to the nearest cache line.\n+\t */\n+\talloc_sz = 2 * RTE_CACHE_LINE_SIZE + cq_alloc_depth * qe_sz;\n+\talloc_sz = RTE_CACHE_LINE_ROUNDUP(alloc_sz);\n+\n+\tport_base = dlb_alloc_coherent_aligned(&pc_dma_base,\n+\t\t\t\t\t       alloc_sz,\n+\t\t\t\t\t       PAGE_SIZE);\n+\tif (port_base == NULL)\n+\t\treturn -ENOMEM;\n+\n+\t/* Lock the page in memory */\n+\tret = rte_mem_lock_page(port_base);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb pf pmd could not lock page for device i/o\\n\");\n+\t\tgoto create_port_err;\n+\t}\n+\n+\tmemset(port_base, 0, alloc_sz);\n+\tcq_dma_base = (uintptr_t)(pc_dma_base + (2 * RTE_CACHE_LINE_SIZE));\n+\n+\tret = dlb_hw_create_ldb_port(&dlb_dev->hw,\n+\t\t\t\t     handle->domain_id,\n+\t\t\t\t     cfg,\n+\t\t\t\t     pc_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     &response);\n+\tif (ret)\n+\t\tgoto create_port_err;\n+\n+\tpp_dma_base = (uintptr_t)dlb_dev->hw.func_kva + PP_BASE(is_dir);\n+\tdlb_port[response.id][DLB_LDB].pp_addr =\n+\t\t(void *)(uintptr_t)(pp_dma_base + (PAGE_SIZE * response.id));\n+\n+\tdlb_port[response.id][DLB_LDB].cq_base =\n+\t\t(void *)(uintptr_t)(port_base + (2 * RTE_CACHE_LINE_SIZE));\n+\n+\tdlb_port[response.id][DLB_LDB].ldb_popcount =\n+\t\t(void *)(uintptr_t)port_base;\n+\tdlb_port[response.id][DLB_LDB].dir_popcount = (void *)(uintptr_t)\n+\t\t(port_base + RTE_CACHE_LINE_SIZE);\n+\n+\t*(struct dlb_cmd_response *)cfg->response = response;\n+\n+\tDLB_INFO(dev->dlb_device, \"Exiting %s() with ret=%d\\n\", __func__, ret);\n+\n+create_port_err:\n+\n+\treturn ret;\n+}\n+\n+static int\n+dlb_pf_dir_port_create(struct dlb_hw_dev *handle,\n+\t\t       struct dlb_create_dir_port_args *cfg,\n+\t\t       enum dlb_cq_poll_modes poll_mode)\n+{\n+\tstruct dlb_dev *dlb_dev = (struct dlb_dev *)handle->pf_dev;\n+\tstruct dlb_cmd_response response = {0};\n+\tint ret;\n+\tuint8_t *port_base;\n+\tint alloc_sz, qe_sz;\n+\trte_iova_t pp_dma_base;\n+\trte_iova_t pc_dma_base;\n+\trte_iova_t cq_dma_base;\n+\tint is_dir = true;\n+\n+\tDLB_INFO(dev->dlb_device, \"Entering %s()\\n\", __func__);\n+\n+\tif (poll_mode == DLB_CQ_POLL_MODE_STD)\n+\t\tqe_sz = sizeof(struct dlb_dequeue_qe);\n+\telse\n+\t\tqe_sz = RTE_CACHE_LINE_SIZE;\n+\n+\t/* Calculate the port memory required, including two cache lines for\n+\t * credit pop counts. Round up to the nearest cache line.\n+\t */\n+\talloc_sz = 2 * RTE_CACHE_LINE_SIZE + cfg->cq_depth * qe_sz;\n+\talloc_sz = RTE_CACHE_LINE_ROUNDUP(alloc_sz);\n+\n+\tport_base = dlb_alloc_coherent_aligned(&pc_dma_base,\n+\t\t\t\t\t       alloc_sz,\n+\t\t\t\t\t       PAGE_SIZE);\n+\tif (port_base == NULL)\n+\t\treturn -ENOMEM;\n+\n+\t/* Lock the page in memory */\n+\tret = rte_mem_lock_page(port_base);\n+\tif (ret < 0) {\n+\t\tDLB_LOG_ERR(\"dlb pf pmd could not lock page for device i/o\\n\");\n+\t\tgoto create_port_err;\n+\t}\n+\n+\tmemset(port_base, 0, alloc_sz);\n+\tcq_dma_base = (uintptr_t)(pc_dma_base + (2 * RTE_CACHE_LINE_SIZE));\n+\n+\tret = dlb_hw_create_dir_port(&dlb_dev->hw,\n+\t\t\t\t     handle->domain_id,\n+\t\t\t\t     cfg,\n+\t\t\t\t     pc_dma_base,\n+\t\t\t\t     cq_dma_base,\n+\t\t\t\t     &response);\n+\tif (ret)\n+\t\tgoto create_port_err;\n+\n+\tpp_dma_base = (uintptr_t)dlb_dev->hw.func_kva + PP_BASE(is_dir);\n+\tdlb_port[response.id][DLB_DIR].pp_addr =\n+\t\t(void *)(uintptr_t)(pp_dma_base + (PAGE_SIZE * response.id));\n+\n+\tdlb_port[response.id][DLB_DIR].cq_base =\n+\t\t(void *)(uintptr_t)(port_base + (2 * RTE_CACHE_LINE_SIZE));\n+\n+\tdlb_port[response.id][DLB_DIR].ldb_popcount =\n+\t\t(void *)(uintptr_t)port_base;\n+\tdlb_port[response.id][DLB_DIR].dir_popcount = (void *)(uintptr_t)\n+\t\t(port_base + RTE_CACHE_LINE_SIZE);\n+\n+\t*(struct dlb_cmd_response *)cfg->response = response;\n+\n+\tDLB_INFO(dev->dlb_device, \"Exiting %s() with ret=%d\\n\", __func__, ret);\n+\n+create_port_err:\n+\n+\treturn ret;\n+}\n+\n+static int\n dlb_pf_get_sn_allocation(struct dlb_hw_dev *handle,\n \t\t\t struct dlb_get_sn_allocation_args *args)\n {\n@@ -287,6 +488,9 @@ dlb_pf_iface_fn_ptrs_init(void)\n \tdlb_iface_ldb_credit_pool_create = dlb_pf_ldb_credit_pool_create;\n \tdlb_iface_dir_credit_pool_create = dlb_pf_dir_credit_pool_create;\n \tdlb_iface_ldb_queue_create = dlb_pf_ldb_queue_create;\n+\tdlb_iface_dir_queue_create = dlb_pf_dir_queue_create;\n+\tdlb_iface_ldb_port_create = dlb_pf_ldb_port_create;\n+\tdlb_iface_dir_port_create = dlb_pf_dir_port_create;\n \tdlb_iface_get_cq_poll_mode = dlb_pf_get_cq_poll_mode;\n \tdlb_iface_get_sn_allocation = dlb_pf_get_sn_allocation;\n \tdlb_iface_set_sn_allocation = dlb_pf_set_sn_allocation;\n",
    "prefixes": [
        "v4",
        "11/22"
    ]
}