git: 623918a198f9 - main - mana: Improve the HWC error handling

From: Wei Hu <whu_at_FreeBSD.org>
Date: Thu, 13 Jan 2022 06:10:02 UTC
The branch main has been updated by whu:

URL: https://cgit.FreeBSD.org/src/commit/?id=623918a198f9231621d60c9294ac1db469fe1565

commit 623918a198f9231621d60c9294ac1db469fe1565
Author:     Wei Hu <whu@FreeBSD.org>
AuthorDate: 2022-01-12 14:33:54 +0000
Commit:     Wei Hu <whu@FreeBSD.org>
CommitDate: 2022-01-13 06:08:43 +0000

    mana: Improve the HWC error handling
    
    Currently when the HWC creation fails, the error handling is flawed,
    e.g. if mana_hwc_create_channel() -> mana_hwc_establish_channel() fails,
    the resources acquired in mana_hwc_init_queues() is not released.
    
    Enhance mana_hwc_destroy_channel() to do the proper cleanup work and
    call it accordingly.
    
    MFC after:      2 weeks
    Sponsored by:   Microsoft
---
 sys/dev/mana/gdma_main.c  |  5 ----
 sys/dev/mana/hw_channel.c | 73 +++++++++++++++++++++--------------------------
 2 files changed, 33 insertions(+), 45 deletions(-)

diff --git a/sys/dev/mana/gdma_main.c b/sys/dev/mana/gdma_main.c
index 49af54f4be5d..b879695825b1 100644
--- a/sys/dev/mana/gdma_main.c
+++ b/sys/dev/mana/gdma_main.c
@@ -1808,9 +1808,6 @@ mana_gd_attach(device_t dev)
 
 err_clean_up_gdma:
 	mana_hwc_destroy_channel(gc);
-	if (gc->cq_table)
-		free(gc->cq_table, M_DEVBUF);
-	gc->cq_table = NULL;
 err_remove_irq:
 	mana_gd_remove_irqs(dev);
 err_free_pci_res:
@@ -1836,8 +1833,6 @@ mana_gd_detach(device_t dev)
 	mana_remove(&gc->mana);
 
 	mana_hwc_destroy_channel(gc);
-	free(gc->cq_table, M_DEVBUF);
-	gc->cq_table = NULL;
 
 	mana_gd_remove_irqs(dev);
 
diff --git a/sys/dev/mana/hw_channel.c b/sys/dev/mana/hw_channel.c
index c24e62970f69..16b644d6c6b7 100644
--- a/sys/dev/mana/hw_channel.c
+++ b/sys/dev/mana/hw_channel.c
@@ -383,9 +383,6 @@ mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self)
 static void
 mana_hwc_destroy_cq(struct gdma_context *gc, struct hwc_cq *hwc_cq)
 {
-	if (!hwc_cq)
-		return;
-
 	if (hwc_cq->comp_buf)
 		free(hwc_cq->comp_buf, M_DEVBUF);
 
@@ -531,9 +528,6 @@ static void
 mana_hwc_destroy_wq(struct hw_channel_context *hwc,
     struct hwc_wq *hwc_wq)
 {
-	if (!hwc_wq)
-		return;
-
 	mana_hwc_dealloc_dma_buf(hwc, hwc_wq->msg_buf);
 
 	if (hwc_wq->gdma_wq)
@@ -718,6 +712,7 @@ mana_hwc_establish_channel(struct gdma_context *gc, uint16_t *q_depth,
 	*max_req_msg_size = hwc->hwc_init_max_req_msg_size;
 	*max_resp_msg_size = hwc->hwc_init_max_resp_msg_size;
 
+	/* Both were set in mana_hwc_init_event_handler(). */
 	if (cq->id >= gc->max_num_cqs) {
 		mana_warn(NULL, "invalid cq id %u > %u\n",
 		    cq->id, gc->max_num_cqs);
@@ -738,9 +733,6 @@ static int
 mana_hwc_init_queues(struct hw_channel_context *hwc, uint16_t q_depth,
     uint32_t max_req_msg_size, uint32_t max_resp_msg_size)
 {
-	struct hwc_wq *hwc_rxq = NULL;
-	struct hwc_wq *hwc_txq = NULL;
-	struct hwc_cq *hwc_cq = NULL;
 	int err;
 
 	err = mana_hwc_init_inflight_msg(hwc, q_depth);
@@ -753,44 +745,32 @@ mana_hwc_init_queues(struct hw_channel_context *hwc, uint16_t q_depth,
 	err = mana_hwc_create_cq(hwc, q_depth * 2,
 	    mana_hwc_init_event_handler, hwc,
 	    mana_hwc_rx_event_handler, hwc,
-	    mana_hwc_tx_event_handler, hwc, &hwc_cq);
+	    mana_hwc_tx_event_handler, hwc, &hwc->cq);
 	if (err) {
 		device_printf(hwc->dev, "Failed to create HWC CQ: %d\n", err);
 		goto out;
 	}
-	hwc->cq = hwc_cq;
 
 	err = mana_hwc_create_wq(hwc, GDMA_RQ, q_depth, max_req_msg_size,
-	    hwc_cq, &hwc_rxq);
+	    hwc->cq, &hwc->rxq);
 	if (err) {
 		device_printf(hwc->dev, "Failed to create HWC RQ: %d\n", err);
 		goto out;
 	}
-	hwc->rxq = hwc_rxq;
 
 	err = mana_hwc_create_wq(hwc, GDMA_SQ, q_depth, max_resp_msg_size,
-	    hwc_cq, &hwc_txq);
+	    hwc->cq, &hwc->txq);
 	if (err) {
 		device_printf(hwc->dev, "Failed to create HWC SQ: %d\n", err);
 		goto out;
 	}
-	hwc->txq = hwc_txq;
 
 	hwc->num_inflight_msg = q_depth;
 	hwc->max_req_msg_size = max_req_msg_size;
 
 	return 0;
 out:
-	if (hwc_txq)
-		mana_hwc_destroy_wq(hwc, hwc_txq);
-
-	if (hwc_rxq)
-		mana_hwc_destroy_wq(hwc, hwc_rxq);
-
-	if (hwc_cq)
-		mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc_cq);
-
-	mana_gd_free_res_map(&hwc->inflight_msg_res);
+	/* mana_hwc_create_channel() will do the cleanup.*/
 	return err;
 }
 
@@ -819,6 +799,10 @@ mana_hwc_create_channel(struct gdma_context *gc)
 	gd->pdid = INVALID_PDID;
 	gd->doorbell = INVALID_DOORBELL;
 
+	/*
+	 * mana_hwc_init_queues() only creates the required data structures,
+	 * and doesn't touch the HWC device.
+	 */
 	err = mana_hwc_init_queues(hwc, HW_CHANNEL_VF_BOOTSTRAP_QUEUE_DEPTH,
 	    HW_CHANNEL_MAX_REQUEST_SIZE,
 	    HW_CHANNEL_MAX_RESPONSE_SIZE);
@@ -846,7 +830,7 @@ mana_hwc_create_channel(struct gdma_context *gc)
 
 	return 0;
 out:
-	free(hwc, M_DEVBUF);
+	mana_hwc_destroy_channel(gc);
 	return (err);
 }
 
@@ -854,35 +838,44 @@ void
 mana_hwc_destroy_channel(struct gdma_context *gc)
 {
 	struct hw_channel_context *hwc = gc->hwc.driver_data;
-	struct hwc_caller_ctx *ctx;
 
-	mana_smc_teardown_hwc(&gc->shm_channel, false);
+	if (!hwc)
+		return;
+
+	/*
+	 * gc->max_num_cqs is set in mana_hwc_init_event_handler(). If it's
+	 * non-zero, the HWC worked and we should tear down the HWC here.
+	 */
+	if (gc->max_num_cqs > 0) {
+		mana_smc_teardown_hwc(&gc->shm_channel, false);
+		gc->max_num_cqs = 0;
+	}
 
-	ctx = hwc->caller_ctx;
-	free(ctx, M_DEVBUF);
+	free(hwc->caller_ctx, M_DEVBUF);
 	hwc->caller_ctx = NULL;
 
-	mana_hwc_destroy_wq(hwc, hwc->txq);
-	hwc->txq = NULL;
+	if (hwc->txq)
+		mana_hwc_destroy_wq(hwc, hwc->txq);
 
-	mana_hwc_destroy_wq(hwc, hwc->rxq);
-	hwc->rxq = NULL;
+	if (hwc->rxq)
+		mana_hwc_destroy_wq(hwc, hwc->rxq);
 
-	mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
-	hwc->cq = NULL;
+	if (hwc->cq)
+		mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
 
 	mana_gd_free_res_map(&hwc->inflight_msg_res);
 
 	hwc->num_inflight_msg = 0;
 
-	if (hwc->gdma_dev->pdid != INVALID_PDID) {
-		hwc->gdma_dev->doorbell = INVALID_DOORBELL;
-		hwc->gdma_dev->pdid = INVALID_PDID;
-	}
+	hwc->gdma_dev->doorbell = INVALID_DOORBELL;
+	hwc->gdma_dev->pdid = INVALID_PDID;
 
 	free(hwc, M_DEVBUF);
 	gc->hwc.driver_data = NULL;
 	gc->hwc.gdma_context = NULL;
+
+	free(gc->cq_table, M_DEVBUF);
+	gc->cq_table = NULL;
 }
 
 int