Skip to content

Commit d5b8b03

Browse files
committed
accel/amdxdna: Split mailbox channel create function
The management channel used for firmware control command submission is currently created after the firmware is started. If channel creation fails (for example, due to memory allocation failure or workqueue creation interruption), the firmware remains in a pending state and is unable to receive any control commands. To avoid leaving the firmware in this inconsistent state, split xdna_mailbox_create_channel() into two separate functions so that resource allocation can be completed before interacting with the hardware. xdna_mailbox_alloc_channel() Allocates memory and initializes the workqueue. This can be called earlier, before interacting with the hardware. xdna_mailbox_start_channel() Performs the hardware interaction required to start the channel. Rename xdna_mailbox_destroy_channel() to xdna_mailbox_free_channel(). Ensure that xdna_mailbox_stop_channel() and xdna_mailbox_free_channel() properly unwind the corresponding start and allocation steps, respectively. Fixes: b87f920 ("accel/amdxdna: Support hardware mailbox") Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Signed-off-by: Lizhi Hou <lizhi.hou@amd.com> Link: https://patch.msgid.link/20260305062041.3954024-1-lizhi.hou@amd.com
1 parent 76e8173 commit d5b8b03

4 files changed

Lines changed: 112 additions & 90 deletions

File tree

drivers/accel/amdxdna/aie2_message.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,29 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
293293
}
294294

295295
intr_reg = i2x.mb_head_ptr_reg + 4;
296-
hwctx->priv->mbox_chann = xdna_mailbox_create_channel(ndev->mbox, &x2i, &i2x,
297-
intr_reg, ret);
296+
hwctx->priv->mbox_chann = xdna_mailbox_alloc_channel(ndev->mbox);
298297
if (!hwctx->priv->mbox_chann) {
299298
XDNA_ERR(xdna, "Not able to create channel");
300299
ret = -EINVAL;
301300
goto del_ctx_req;
302301
}
302+
303+
ret = xdna_mailbox_start_channel(hwctx->priv->mbox_chann, &x2i, &i2x,
304+
intr_reg, ret);
305+
if (ret) {
306+
XDNA_ERR(xdna, "Not able to create channel");
307+
ret = -EINVAL;
308+
goto free_channel;
309+
}
303310
ndev->hwctx_num++;
304311

305312
XDNA_DBG(xdna, "Mailbox channel irq: %d, msix_id: %d", ret, resp.msix_id);
306313
XDNA_DBG(xdna, "Created fw ctx %d pasid %d", hwctx->fw_ctx_id, hwctx->client->pasid);
307314

308315
return 0;
309316

317+
free_channel:
318+
xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
310319
del_ctx_req:
311320
aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
312321
return ret;
@@ -322,7 +331,7 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
322331

323332
xdna_mailbox_stop_channel(hwctx->priv->mbox_chann);
324333
ret = aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
325-
xdna_mailbox_destroy_channel(hwctx->priv->mbox_chann);
334+
xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
326335
XDNA_DBG(xdna, "Destroyed fw ctx %d", hwctx->fw_ctx_id);
327336
hwctx->priv->mbox_chann = NULL;
328337
hwctx->fw_ctx_id = -1;
@@ -921,7 +930,7 @@ void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev)
921930
return;
922931

923932
xdna_mailbox_stop_channel(ndev->mgmt_chann);
924-
xdna_mailbox_destroy_channel(ndev->mgmt_chann);
933+
xdna_mailbox_free_channel(ndev->mgmt_chann);
925934
ndev->mgmt_chann = NULL;
926935
}
927936

drivers/accel/amdxdna/aie2_pci.c

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,29 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
361361
}
362362
pci_set_master(pdev);
363363

364+
mbox_res.ringbuf_base = ndev->sram_base;
365+
mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
366+
mbox_res.mbox_base = ndev->mbox_base;
367+
mbox_res.mbox_size = MBOX_SIZE(ndev);
368+
mbox_res.name = "xdna_mailbox";
369+
ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
370+
if (!ndev->mbox) {
371+
XDNA_ERR(xdna, "failed to create mailbox device");
372+
ret = -ENODEV;
373+
goto disable_dev;
374+
}
375+
376+
ndev->mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
377+
if (!ndev->mgmt_chann) {
378+
XDNA_ERR(xdna, "failed to alloc channel");
379+
ret = -ENODEV;
380+
goto disable_dev;
381+
}
382+
364383
ret = aie2_smu_init(ndev);
365384
if (ret) {
366385
XDNA_ERR(xdna, "failed to init smu, ret %d", ret);
367-
goto disable_dev;
386+
goto free_channel;
368387
}
369388

370389
ret = aie2_psp_start(ndev->psp_hdl);
@@ -379,18 +398,6 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
379398
goto stop_psp;
380399
}
381400

382-
mbox_res.ringbuf_base = ndev->sram_base;
383-
mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
384-
mbox_res.mbox_base = ndev->mbox_base;
385-
mbox_res.mbox_size = MBOX_SIZE(ndev);
386-
mbox_res.name = "xdna_mailbox";
387-
ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
388-
if (!ndev->mbox) {
389-
XDNA_ERR(xdna, "failed to create mailbox device");
390-
ret = -ENODEV;
391-
goto stop_psp;
392-
}
393-
394401
mgmt_mb_irq = pci_irq_vector(pdev, ndev->mgmt_chan_idx);
395402
if (mgmt_mb_irq < 0) {
396403
ret = mgmt_mb_irq;
@@ -399,51 +406,55 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
399406
}
400407

401408
xdna_mailbox_intr_reg = ndev->mgmt_i2x.mb_head_ptr_reg + 4;
402-
ndev->mgmt_chann = xdna_mailbox_create_channel(ndev->mbox,
403-
&ndev->mgmt_x2i,
404-
&ndev->mgmt_i2x,
405-
xdna_mailbox_intr_reg,
406-
mgmt_mb_irq);
407-
if (!ndev->mgmt_chann) {
408-
XDNA_ERR(xdna, "failed to create management mailbox channel");
409+
ret = xdna_mailbox_start_channel(ndev->mgmt_chann,
410+
&ndev->mgmt_x2i,
411+
&ndev->mgmt_i2x,
412+
xdna_mailbox_intr_reg,
413+
mgmt_mb_irq);
414+
if (ret) {
415+
XDNA_ERR(xdna, "failed to start management mailbox channel");
409416
ret = -EINVAL;
410417
goto stop_psp;
411418
}
412419

413420
ret = aie2_mgmt_fw_init(ndev);
414421
if (ret) {
415422
XDNA_ERR(xdna, "initial mgmt firmware failed, ret %d", ret);
416-
goto destroy_mgmt_chann;
423+
goto stop_fw;
417424
}
418425

419426
ret = aie2_pm_init(ndev);
420427
if (ret) {
421428
XDNA_ERR(xdna, "failed to init pm, ret %d", ret);
422-
goto destroy_mgmt_chann;
429+
goto stop_fw;
423430
}
424431

425432
ret = aie2_mgmt_fw_query(ndev);
426433
if (ret) {
427434
XDNA_ERR(xdna, "failed to query fw, ret %d", ret);
428-
goto destroy_mgmt_chann;
435+
goto stop_fw;
429436
}
430437

431438
ret = aie2_error_async_events_alloc(ndev);
432439
if (ret) {
433440
XDNA_ERR(xdna, "Allocate async events failed, ret %d", ret);
434-
goto destroy_mgmt_chann;
441+
goto stop_fw;
435442
}
436443

437444
ndev->dev_status = AIE2_DEV_START;
438445

439446
return 0;
440447

441-
destroy_mgmt_chann:
442-
aie2_destroy_mgmt_chann(ndev);
448+
stop_fw:
449+
aie2_suspend_fw(ndev);
450+
xdna_mailbox_stop_channel(ndev->mgmt_chann);
443451
stop_psp:
444452
aie2_psp_stop(ndev->psp_hdl);
445453
fini_smu:
446454
aie2_smu_fini(ndev);
455+
free_channel:
456+
xdna_mailbox_free_channel(ndev->mgmt_chann);
457+
ndev->mgmt_chann = NULL;
447458
disable_dev:
448459
pci_disable_device(pdev);
449460

drivers/accel/amdxdna/amdxdna_mailbox.c

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -460,26 +460,49 @@ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
460460
return ret;
461461
}
462462

463-
struct mailbox_channel *
464-
xdna_mailbox_create_channel(struct mailbox *mb,
465-
const struct xdna_mailbox_chann_res *x2i,
466-
const struct xdna_mailbox_chann_res *i2x,
467-
u32 iohub_int_addr,
468-
int mb_irq)
463+
struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
469464
{
470465
struct mailbox_channel *mb_chann;
471-
int ret;
472-
473-
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
474-
pr_err("Ring buf size must be power of 2");
475-
return NULL;
476-
}
477466

478467
mb_chann = kzalloc_obj(*mb_chann);
479468
if (!mb_chann)
480469
return NULL;
481470

471+
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
472+
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
473+
if (!mb_chann->work_q) {
474+
MB_ERR(mb_chann, "Create workqueue failed");
475+
goto free_chann;
476+
}
482477
mb_chann->mb = mb;
478+
479+
return mb_chann;
480+
481+
free_chann:
482+
kfree(mb_chann);
483+
return NULL;
484+
}
485+
486+
void xdna_mailbox_free_channel(struct mailbox_channel *mb_chann)
487+
{
488+
destroy_workqueue(mb_chann->work_q);
489+
kfree(mb_chann);
490+
}
491+
492+
int
493+
xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
494+
const struct xdna_mailbox_chann_res *x2i,
495+
const struct xdna_mailbox_chann_res *i2x,
496+
u32 iohub_int_addr,
497+
int mb_irq)
498+
{
499+
int ret;
500+
501+
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
502+
pr_err("Ring buf size must be power of 2");
503+
return -EINVAL;
504+
}
505+
483506
mb_chann->msix_irq = mb_irq;
484507
mb_chann->iohub_int_addr = iohub_int_addr;
485508
memcpy(&mb_chann->res[CHAN_RES_X2I], x2i, sizeof(*x2i));
@@ -489,61 +512,37 @@ xdna_mailbox_create_channel(struct mailbox *mb,
489512
mb_chann->x2i_tail = mailbox_get_tailptr(mb_chann, CHAN_RES_X2I);
490513
mb_chann->i2x_head = mailbox_get_headptr(mb_chann, CHAN_RES_I2X);
491514

492-
INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
493-
mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
494-
if (!mb_chann->work_q) {
495-
MB_ERR(mb_chann, "Create workqueue failed");
496-
goto free_and_out;
497-
}
498-
499515
/* Everything look good. Time to enable irq handler */
500516
ret = request_irq(mb_irq, mailbox_irq_handler, 0, MAILBOX_NAME, mb_chann);
501517
if (ret) {
502518
MB_ERR(mb_chann, "Failed to request irq %d ret %d", mb_irq, ret);
503-
goto destroy_wq;
519+
return ret;
504520
}
505521

506522
mb_chann->bad_state = false;
507523
mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
508524

509-
MB_DBG(mb_chann, "Mailbox channel created (irq: %d)", mb_chann->msix_irq);
510-
return mb_chann;
511-
512-
destroy_wq:
513-
destroy_workqueue(mb_chann->work_q);
514-
free_and_out:
515-
kfree(mb_chann);
516-
return NULL;
525+
MB_DBG(mb_chann, "Mailbox channel started (irq: %d)", mb_chann->msix_irq);
526+
return 0;
517527
}
518528

519-
int xdna_mailbox_destroy_channel(struct mailbox_channel *mb_chann)
529+
void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
520530
{
521531
struct mailbox_msg *mb_msg;
522532
unsigned long msg_id;
523533

524-
MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
534+
/* Disable an irq and wait. This might sleep. */
525535
free_irq(mb_chann->msix_irq, mb_chann);
526-
destroy_workqueue(mb_chann->work_q);
527-
/* We can clean up and release resources */
528536

537+
/* Cancel RX work and wait for it to finish */
538+
drain_workqueue(mb_chann->work_q);
539+
540+
/* We can clean up and release resources */
529541
xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)
530542
mailbox_release_msg(mb_chann, mb_msg);
531-
532543
xa_destroy(&mb_chann->chan_xa);
533544

534-
MB_DBG(mb_chann, "Mailbox channel destroyed, irq: %d", mb_chann->msix_irq);
535-
kfree(mb_chann);
536-
return 0;
537-
}
538-
539-
void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
540-
{
541-
/* Disable an irq and wait. This might sleep. */
542-
disable_irq(mb_chann->msix_irq);
543-
544-
/* Cancel RX work and wait for it to finish */
545-
cancel_work_sync(&mb_chann->rx_work);
546-
MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
545+
MB_DBG(mb_chann, "Mailbox channel stopped, irq: %d", mb_chann->msix_irq);
547546
}
548547

549548
struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,

drivers/accel/amdxdna/amdxdna_mailbox.h

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -74,38 +74,41 @@ struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
7474
const struct xdna_mailbox_res *res);
7575

7676
/*
77-
* xdna_mailbox_create_channel() -- Create a mailbox channel instance
77+
* xdna_mailbox_alloc_channel() -- alloc a mailbox channel
7878
*
79-
* @mailbox: the handle return from xdna_mailbox_create()
79+
* @mb: mailbox handle
80+
*/
81+
struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb);
82+
83+
/*
84+
* xdna_mailbox_start_channel() -- start a mailbox channel instance
85+
*
86+
* @mb_chann: the handle return from xdna_mailbox_alloc_channel()
8087
* @x2i: host to firmware mailbox resources
8188
* @i2x: firmware to host mailbox resources
8289
* @xdna_mailbox_intr_reg: register addr of MSI-X interrupt
8390
* @mb_irq: Linux IRQ number associated with mailbox MSI-X interrupt vector index
8491
*
8592
* Return: If success, return a handle of mailbox channel. Otherwise, return NULL.
8693
*/
87-
struct mailbox_channel *
88-
xdna_mailbox_create_channel(struct mailbox *mailbox,
89-
const struct xdna_mailbox_chann_res *x2i,
90-
const struct xdna_mailbox_chann_res *i2x,
91-
u32 xdna_mailbox_intr_reg,
92-
int mb_irq);
94+
int
95+
xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
96+
const struct xdna_mailbox_chann_res *x2i,
97+
const struct xdna_mailbox_chann_res *i2x,
98+
u32 xdna_mailbox_intr_reg,
99+
int mb_irq);
93100

94101
/*
95-
* xdna_mailbox_destroy_channel() -- destroy mailbox channel
102+
* xdna_mailbox_free_channel() -- free mailbox channel
96103
*
97104
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
98-
*
99-
* Return: if success, return 0. otherwise return error code
100105
*/
101-
int xdna_mailbox_destroy_channel(struct mailbox_channel *mailbox_chann);
106+
void xdna_mailbox_free_channel(struct mailbox_channel *mailbox_chann);
102107

103108
/*
104109
* xdna_mailbox_stop_channel() -- stop mailbox channel
105110
*
106111
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
107-
*
108-
* Return: if success, return 0. otherwise return error code
109112
*/
110113
void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
111114

0 commit comments

Comments
 (0)