From patchwork Tue Mar 16 22:18:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Timothy McDaniel X-Patchwork-Id: 89287 X-Patchwork-Delegate: jerinj@marvell.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C0F09A054F; Tue, 16 Mar 2021 23:21:10 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5C7A8242ABE; Tue, 16 Mar 2021 23:20:08 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id A94BE242A9E for ; Tue, 16 Mar 2021 23:20:01 +0100 (CET) IronPort-SDR: OZb1UinSbLXNS23op++qEJ4TBQacyPF8VJKDkma1D60eDQ4OisHkvb0FEo9RXeOohQmZt/kwER omJ01KUm8KTw== X-IronPort-AV: E=McAfee;i="6000,8403,9925"; a="253359251" X-IronPort-AV: E=Sophos;i="5.81,254,1610438400"; d="scan'208";a="253359251" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Mar 2021 15:19:55 -0700 IronPort-SDR: 2uiuHExuFi0f9rr90QvTTGeENX5XLx7wr8I9l3dVRrmOvMvLTCFAH2tj5t7MqtvNVc58Icy1aG DFSIVcVOix3Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,254,1610438400"; d="scan'208";a="605440244" Received: from txasoft-yocto.an.intel.com ([10.123.72.192]) by fmsmga005.fm.intel.com with ESMTP; 16 Mar 2021 15:19:54 -0700 From: Timothy McDaniel To: dev@dpdk.org Cc: jerinj@marvell.com, harry.van.haaren@intel.com, mdr@ashroe.eu, nhorman@tuxdriver.com, nikhil.rao@intel.com, erik.g.carrillo@intel.com, abhinandan.gujjar@intel.com, pbhagavatula@marvell.com, hemant.agrawal@nxp.com, mattias.ronnblom@ericsson.com, peter.mccarthy@intel.com Date: Tue, 16 Mar 2021 17:18:43 -0500 Message-Id: <20210316221857.2254-12-timothy.mcdaniel@intel.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20210316221857.2254-1-timothy.mcdaniel@intel.com> References: <20210316221857.2254-1-timothy.mcdaniel@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 11/25] event/dlb2: add DLB v2.5 support to unmap queue X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Update low level functions to account for new register map and hardware access macros. Signed-off-by: Timothy McDaniel --- drivers/event/dlb2/pf/base/dlb2_resource.c | 331 ------------------ .../event/dlb2/pf/base/dlb2_resource_new.c | 298 ++++++++++++++++ 2 files changed, 298 insertions(+), 331 deletions(-) diff --git a/drivers/event/dlb2/pf/base/dlb2_resource.c b/drivers/event/dlb2/pf/base/dlb2_resource.c index 4fa867c3f..02c2836ad 100644 --- a/drivers/event/dlb2/pf/base/dlb2_resource.c +++ b/drivers/event/dlb2/pf/base/dlb2_resource.c @@ -1226,26 +1226,6 @@ dlb2_get_domain_used_dir_pq(struct dlb2_hw *hw, return NULL; } -static bool -dlb2_port_find_slot_with_pending_map_queue(struct dlb2_ldb_port *port, - struct dlb2_ldb_queue *queue, - int *slot) -{ - int i; - - for (i = 0; i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ; i++) { - struct dlb2_ldb_port_qid_map *map = &port->qid_map[i]; - - if (map->state == DLB2_QUEUE_UNMAP_IN_PROG_PENDING_MAP && - map->pending_qid == queue->id.phys_id) - break; - } - - *slot = i; - - return (i < DLB2_MAX_NUM_QIDS_PER_LDB_CQ); -} - static struct dlb2_ldb_queue * dlb2_get_domain_ldb_queue(u32 id, bool vdev_req, @@ -1266,317 +1246,6 @@ dlb2_get_domain_ldb_queue(u32 id, return NULL; } -static struct dlb2_ldb_port * -dlb2_get_domain_used_ldb_port(u32 id, - bool vdev_req, - struct dlb2_hw_domain *domain) -{ - struct dlb2_list_entry *iter; - struct dlb2_ldb_port *port; - int i; - RTE_SET_USED(iter); - - if (id >= DLB2_MAX_NUM_LDB_PORTS) - return NULL; - - for (i = 0; i < DLB2_NUM_COS_DOMAINS; i++) { - DLB2_DOM_LIST_FOR(domain->used_ldb_ports[i], port, iter) - if ((!vdev_req && port->id.phys_id == id) || - (vdev_req && port->id.virt_id == id)) - return port; - - DLB2_DOM_LIST_FOR(domain->avail_ldb_ports[i], port, iter) - if ((!vdev_req && port->id.phys_id == id) || - (vdev_req && port->id.virt_id == id)) - return port; - } - - return NULL; -} - -static void dlb2_log_unmap_qid(struct dlb2_hw *hw, - u32 domain_id, - struct dlb2_unmap_qid_args *args, - bool vdev_req, - unsigned int vdev_id) -{ - DLB2_HW_DBG(hw, "DLB2 unmap QID arguments:\n"); - if (vdev_req) - DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id); - DLB2_HW_DBG(hw, "\tDomain ID: %d\n", - domain_id); - DLB2_HW_DBG(hw, "\tPort ID: %d\n", - args->port_id); - DLB2_HW_DBG(hw, "\tQueue ID: %d\n", - args->qid); - if (args->qid < DLB2_MAX_NUM_LDB_QUEUES) - DLB2_HW_DBG(hw, "\tQueue's num mappings: %d\n", - hw->rsrcs.ldb_queues[args->qid].num_mappings); -} - -static int dlb2_verify_unmap_qid_args(struct dlb2_hw *hw, - u32 domain_id, - struct dlb2_unmap_qid_args *args, - struct dlb2_cmd_response *resp, - bool vdev_req, - unsigned int vdev_id) -{ - enum dlb2_qid_map_state state; - struct dlb2_hw_domain *domain; - struct dlb2_ldb_queue *queue; - struct dlb2_ldb_port *port; - int slot; - int id; - - domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id); - - if (domain == NULL) { - resp->status = DLB2_ST_INVALID_DOMAIN_ID; - return -EINVAL; - } - - if (!domain->configured) { - resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED; - return -EINVAL; - } - - id = args->port_id; - - port = dlb2_get_domain_used_ldb_port(id, vdev_req, domain); - - if (port == NULL || !port->configured) { - resp->status = DLB2_ST_INVALID_PORT_ID; - return -EINVAL; - } - - if (port->domain_id.phys_id != domain->id.phys_id) { - resp->status = DLB2_ST_INVALID_PORT_ID; - return -EINVAL; - } - - queue = dlb2_get_domain_ldb_queue(args->qid, vdev_req, domain); - - if (queue == NULL || !queue->configured) { - DLB2_HW_ERR(hw, "[%s()] Can't unmap unconfigured queue %d\n", - __func__, args->qid); - resp->status = DLB2_ST_INVALID_QID; - return -EINVAL; - } - - /* - * Verify that the port has the queue mapped. From the application's - * perspective a queue is mapped if it is actually mapped, the map is - * in progress, or the map is blocked pending an unmap. - */ - state = DLB2_QUEUE_MAPPED; - if (dlb2_port_find_slot_queue(port, state, queue, &slot)) - return 0; - - state = DLB2_QUEUE_MAP_IN_PROG; - if (dlb2_port_find_slot_queue(port, state, queue, &slot)) - return 0; - - if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &slot)) - return 0; - - resp->status = DLB2_ST_INVALID_QID; - return -EINVAL; -} - -int dlb2_hw_unmap_qid(struct dlb2_hw *hw, - u32 domain_id, - struct dlb2_unmap_qid_args *args, - struct dlb2_cmd_response *resp, - bool vdev_req, - unsigned int vdev_id) -{ - struct dlb2_hw_domain *domain; - struct dlb2_ldb_queue *queue; - enum dlb2_qid_map_state st; - struct dlb2_ldb_port *port; - bool unmap_complete; - int i, ret, id; - - dlb2_log_unmap_qid(hw, domain_id, args, vdev_req, vdev_id); - - /* - * Verify that hardware resources are available before attempting to - * satisfy the request. This simplifies the error unwinding code. - */ - ret = dlb2_verify_unmap_qid_args(hw, - domain_id, - args, - resp, - vdev_req, - vdev_id); - if (ret) - return ret; - - domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id); - if (domain == NULL) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: domain not found\n", - __func__, __LINE__); - return -EFAULT; - } - - id = args->port_id; - - port = dlb2_get_domain_used_ldb_port(id, vdev_req, domain); - if (port == NULL) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: port not found\n", - __func__, __LINE__); - return -EFAULT; - } - - queue = dlb2_get_domain_ldb_queue(args->qid, vdev_req, domain); - if (queue == NULL) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: queue not found\n", - __func__, __LINE__); - return -EFAULT; - } - - /* - * If the queue hasn't been mapped yet, we need to update the slot's - * state and re-enable the queue's inflights. - */ - st = DLB2_QUEUE_MAP_IN_PROG; - if (dlb2_port_find_slot_queue(port, st, queue, &i)) { - if (i >= DLB2_MAX_NUM_QIDS_PER_LDB_CQ) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: port slot tracking failed\n", - __func__, __LINE__); - return -EFAULT; - } - - /* - * Since the in-progress map was aborted, re-enable the QID's - * inflights. - */ - if (queue->num_pending_additions == 0) - dlb2_ldb_queue_set_inflight_limit(hw, queue); - - st = DLB2_QUEUE_UNMAPPED; - ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); - if (ret) - return ret; - - goto unmap_qid_done; - } - - /* - * If the queue mapping is on hold pending an unmap, we simply need to - * update the slot's state. - */ - if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &i)) { - if (i >= DLB2_MAX_NUM_QIDS_PER_LDB_CQ) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: port slot tracking failed\n", - __func__, __LINE__); - return -EFAULT; - } - - st = DLB2_QUEUE_UNMAP_IN_PROG; - ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); - if (ret) - return ret; - - goto unmap_qid_done; - } - - st = DLB2_QUEUE_MAPPED; - if (!dlb2_port_find_slot_queue(port, st, queue, &i)) { - DLB2_HW_ERR(hw, - "[%s()] Internal error: no available CQ slots\n", - __func__); - return -EFAULT; - } - - if (i >= DLB2_MAX_NUM_QIDS_PER_LDB_CQ) { - DLB2_HW_ERR(hw, - "[%s():%d] Internal error: port slot tracking failed\n", - __func__, __LINE__); - return -EFAULT; - } - - /* - * QID->CQ mapping removal is an asynchronous procedure. It requires - * stopping the DLB2 from scheduling this CQ, draining all inflights - * from the CQ, then unmapping the queue from the CQ. This function - * simply marks the port as needing the queue unmapped, and (if - * necessary) starts the unmapping worker thread. - */ - dlb2_ldb_port_cq_disable(hw, port); - - st = DLB2_QUEUE_UNMAP_IN_PROG; - ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); - if (ret) - return ret; - - /* - * Attempt to finish the unmapping now, in case the port has no - * outstanding inflights. If that's not the case, this will fail and - * the unmapping will be completed at a later time. - */ - unmap_complete = dlb2_domain_finish_unmap_port(hw, domain, port); - - /* - * If the unmapping couldn't complete immediately, launch the worker - * thread (if it isn't already launched) to finish it later. - */ - if (!unmap_complete && !os_worker_active(hw)) - os_schedule_work(hw); - -unmap_qid_done: - resp->status = 0; - - return 0; -} - -static void -dlb2_log_pending_port_unmaps_args(struct dlb2_hw *hw, - struct dlb2_pending_port_unmaps_args *args, - bool vdev_req, - unsigned int vdev_id) -{ - DLB2_HW_DBG(hw, "DLB unmaps in progress arguments:\n"); - if (vdev_req) - DLB2_HW_DBG(hw, "(Request from VF %d)\n", vdev_id); - DLB2_HW_DBG(hw, "\tPort ID: %d\n", args->port_id); -} - -int dlb2_hw_pending_port_unmaps(struct dlb2_hw *hw, - u32 domain_id, - struct dlb2_pending_port_unmaps_args *args, - struct dlb2_cmd_response *resp, - bool vdev_req, - unsigned int vdev_id) -{ - struct dlb2_hw_domain *domain; - struct dlb2_ldb_port *port; - - dlb2_log_pending_port_unmaps_args(hw, args, vdev_req, vdev_id); - - domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id); - - if (domain == NULL) { - resp->status = DLB2_ST_INVALID_DOMAIN_ID; - return -EINVAL; - } - - port = dlb2_get_domain_used_ldb_port(args->port_id, vdev_req, domain); - if (port == NULL || !port->configured) { - resp->status = DLB2_ST_INVALID_PORT_ID; - return -EINVAL; - } - - resp->id = port->num_pending_removals; - - return 0; -} - static int dlb2_verify_start_domain_args(struct dlb2_hw *hw, u32 domain_id, struct dlb2_cmd_response *resp, diff --git a/drivers/event/dlb2/pf/base/dlb2_resource_new.c b/drivers/event/dlb2/pf/base/dlb2_resource_new.c index 5070428ba..6f35a9118 100644 --- a/drivers/event/dlb2/pf/base/dlb2_resource_new.c +++ b/drivers/event/dlb2/pf/base/dlb2_resource_new.c @@ -5477,3 +5477,301 @@ int dlb2_hw_map_qid(struct dlb2_hw *hw, return 0; } + +static void dlb2_log_unmap_qid(struct dlb2_hw *hw, + u32 domain_id, + struct dlb2_unmap_qid_args *args, + bool vdev_req, + unsigned int vdev_id) +{ + DLB2_HW_DBG(hw, "DLB2 unmap QID arguments:\n"); + if (vdev_req) + DLB2_HW_DBG(hw, "(Request from vdev %d)\n", vdev_id); + DLB2_HW_DBG(hw, "\tDomain ID: %d\n", + domain_id); + DLB2_HW_DBG(hw, "\tPort ID: %d\n", + args->port_id); + DLB2_HW_DBG(hw, "\tQueue ID: %d\n", + args->qid); + if (args->qid < DLB2_MAX_NUM_LDB_QUEUES) + DLB2_HW_DBG(hw, "\tQueue's num mappings: %d\n", + hw->rsrcs.ldb_queues[args->qid].num_mappings); +} + +static int dlb2_verify_unmap_qid_args(struct dlb2_hw *hw, + u32 domain_id, + struct dlb2_unmap_qid_args *args, + struct dlb2_cmd_response *resp, + bool vdev_req, + unsigned int vdev_id, + struct dlb2_hw_domain **out_domain, + struct dlb2_ldb_port **out_port, + struct dlb2_ldb_queue **out_queue) +{ + enum dlb2_qid_map_state state; + struct dlb2_hw_domain *domain; + struct dlb2_ldb_queue *queue; + struct dlb2_ldb_port *port; + int slot; + int id; + + domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id); + + if (!domain) { + resp->status = DLB2_ST_INVALID_DOMAIN_ID; + return -EINVAL; + } + + if (!domain->configured) { + resp->status = DLB2_ST_DOMAIN_NOT_CONFIGURED; + return -EINVAL; + } + + id = args->port_id; + + port = dlb2_get_domain_used_ldb_port(id, vdev_req, domain); + + if (!port || !port->configured) { + resp->status = DLB2_ST_INVALID_PORT_ID; + return -EINVAL; + } + + if (port->domain_id.phys_id != domain->id.phys_id) { + resp->status = DLB2_ST_INVALID_PORT_ID; + return -EINVAL; + } + + queue = dlb2_get_domain_ldb_queue(args->qid, vdev_req, domain); + + if (!queue || !queue->configured) { + DLB2_HW_ERR(hw, "[%s()] Can't unmap unconfigured queue %d\n", + __func__, args->qid); + resp->status = DLB2_ST_INVALID_QID; + return -EINVAL; + } + + /* + * Verify that the port has the queue mapped. From the application's + * perspective a queue is mapped if it is actually mapped, the map is + * in progress, or the map is blocked pending an unmap. + */ + state = DLB2_QUEUE_MAPPED; + if (dlb2_port_find_slot_queue(port, state, queue, &slot)) + goto done; + + state = DLB2_QUEUE_MAP_IN_PROG; + if (dlb2_port_find_slot_queue(port, state, queue, &slot)) + goto done; + + if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &slot)) + goto done; + + resp->status = DLB2_ST_INVALID_QID; + return -EINVAL; + +done: + *out_domain = domain; + *out_port = port; + *out_queue = queue; + + return 0; +} + +/** + * dlb2_hw_unmap_qid() - Unmap a load-balanced queue from a load-balanced port + * @hw: dlb2_hw handle for a particular device. + * @domain_id: domain ID. + * @args: unmap QID arguments. + * @resp: response structure. + * @vdev_req: indicates whether this request came from a vdev. + * @vdev_id: If vdev_req is true, this contains the vdev's ID. + * + * This function configures the DLB to stop scheduling QEs from the specified + * queue to the specified port. + * + * A successful return does not necessarily mean the mapping was removed. If + * this function is unable to immediately unmap the queue from the port, it + * will add the requested operation to a per-port list of pending map/unmap + * operations, and (if it's not already running) launch a kernel thread that + * periodically attempts to process all pending operations. See + * dlb2_hw_map_qid() for more details. + * + * A vdev can be either an SR-IOV virtual function or a Scalable IOV virtual + * device. + * + * Return: + * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is + * assigned a detailed error code from enum dlb2_error. + * + * Errors: + * EINVAL - A requested resource is unavailable, invalid port or queue ID, or + * the domain is not configured. + * EFAULT - Internal error (resp->status not set). + */ +int dlb2_hw_unmap_qid(struct dlb2_hw *hw, + u32 domain_id, + struct dlb2_unmap_qid_args *args, + struct dlb2_cmd_response *resp, + bool vdev_req, + unsigned int vdev_id) +{ + struct dlb2_hw_domain *domain; + struct dlb2_ldb_queue *queue; + enum dlb2_qid_map_state st; + struct dlb2_ldb_port *port; + bool unmap_complete; + int i, ret; + + dlb2_log_unmap_qid(hw, domain_id, args, vdev_req, vdev_id); + + /* + * Verify that hardware resources are available before attempting to + * satisfy the request. This simplifies the error unwinding code. + */ + ret = dlb2_verify_unmap_qid_args(hw, + domain_id, + args, + resp, + vdev_req, + vdev_id, + &domain, + &port, + &queue); + if (ret) + return ret; + + /* + * If the queue hasn't been mapped yet, we need to update the slot's + * state and re-enable the queue's inflights. + */ + st = DLB2_QUEUE_MAP_IN_PROG; + if (dlb2_port_find_slot_queue(port, st, queue, &i)) { + /* + * Since the in-progress map was aborted, re-enable the QID's + * inflights. + */ + if (queue->num_pending_additions == 0) + dlb2_ldb_queue_set_inflight_limit(hw, queue); + + st = DLB2_QUEUE_UNMAPPED; + ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); + if (ret) + return ret; + + goto unmap_qid_done; + } + + /* + * If the queue mapping is on hold pending an unmap, we simply need to + * update the slot's state. + */ + if (dlb2_port_find_slot_with_pending_map_queue(port, queue, &i)) { + st = DLB2_QUEUE_UNMAP_IN_PROG; + ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); + if (ret) + return ret; + + goto unmap_qid_done; + } + + st = DLB2_QUEUE_MAPPED; + if (!dlb2_port_find_slot_queue(port, st, queue, &i)) { + DLB2_HW_ERR(hw, + "[%s()] Internal error: no available CQ slots\n", + __func__); + return -EFAULT; + } + + /* + * QID->CQ mapping removal is an asynchronous procedure. It requires + * stopping the DLB2 from scheduling this CQ, draining all inflights + * from the CQ, then unmapping the queue from the CQ. This function + * simply marks the port as needing the queue unmapped, and (if + * necessary) starts the unmapping worker thread. + */ + dlb2_ldb_port_cq_disable(hw, port); + + st = DLB2_QUEUE_UNMAP_IN_PROG; + ret = dlb2_port_slot_state_transition(hw, port, queue, i, st); + if (ret) + return ret; + + /* + * Attempt to finish the unmapping now, in case the port has no + * outstanding inflights. If that's not the case, this will fail and + * the unmapping will be completed at a later time. + */ + unmap_complete = dlb2_domain_finish_unmap_port(hw, domain, port); + + /* + * If the unmapping couldn't complete immediately, launch the worker + * thread (if it isn't already launched) to finish it later. + */ + if (!unmap_complete && !os_worker_active(hw)) + os_schedule_work(hw); + +unmap_qid_done: + resp->status = 0; + + return 0; +} + +static void +dlb2_log_pending_port_unmaps_args(struct dlb2_hw *hw, + struct dlb2_pending_port_unmaps_args *args, + bool vdev_req, + unsigned int vdev_id) +{ + DLB2_HW_DBG(hw, "DLB unmaps in progress arguments:\n"); + if (vdev_req) + DLB2_HW_DBG(hw, "(Request from VF %d)\n", vdev_id); + DLB2_HW_DBG(hw, "\tPort ID: %d\n", args->port_id); +} + +/** + * dlb2_hw_pending_port_unmaps() - returns the number of unmap operations in + * progress. + * @hw: dlb2_hw handle for a particular device. + * @domain_id: domain ID. + * @args: number of unmaps in progress args + * @resp: response structure. + * @vdev_req: indicates whether this request came from a vdev. + * @vdev_id: If vdev_req is true, this contains the vdev's ID. + * + * Return: + * Returns 0 upon success, < 0 otherwise. If an error occurs, resp->status is + * assigned a detailed error code from enum dlb2_error. If successful, resp->id + * contains the number of unmaps in progress. + * + * Errors: + * EINVAL - Invalid port ID. + */ +int dlb2_hw_pending_port_unmaps(struct dlb2_hw *hw, + u32 domain_id, + struct dlb2_pending_port_unmaps_args *args, + struct dlb2_cmd_response *resp, + bool vdev_req, + unsigned int vdev_id) +{ + struct dlb2_hw_domain *domain; + struct dlb2_ldb_port *port; + + dlb2_log_pending_port_unmaps_args(hw, args, vdev_req, vdev_id); + + domain = dlb2_get_domain_from_id(hw, domain_id, vdev_req, vdev_id); + + if (!domain) { + resp->status = DLB2_ST_INVALID_DOMAIN_ID; + return -EINVAL; + } + + port = dlb2_get_domain_used_ldb_port(args->port_id, vdev_req, domain); + if (!port || !port->configured) { + resp->status = DLB2_ST_INVALID_PORT_ID; + return -EINVAL; + } + + resp->id = port->num_pending_removals; + + return 0; +}