Skip to content

Commit 2ca492e

Browse files
hotrangroeck
authored andcommitted
hwmon: (xgene) Fix crash when alarm occurs before driver probe
The system crashes during probing xgene-hwmon driver when temperature alarm interrupt occurs before. It's because - xgene_hwmon_probe() requests mailbox channel which also enables the mailbox interrupt. - As temperature alarm interrupt is pending, ISR runs and crashes when accesses into invalid resourse as unmapped PCC shared memory. This patch fixes this issue by saving this alarm message and scheduling a bottom handler after xgene_hwmon_probe() finish. Signed-off-by: Hoan Tran <hotran@apm.com> Reported-by: Itaru Kitayama <itaru.kitayama@riken.jp> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent 9417fef commit 2ca492e

File tree

1 file changed

+50
-19
lines changed

1 file changed

+50
-19
lines changed

drivers/hwmon/xgene-hwmon.c

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -465,13 +465,34 @@ static void xgene_hwmon_evt_work(struct work_struct *work)
465465
}
466466
}
467467

468+
static int xgene_hwmon_rx_ready(struct xgene_hwmon_dev *ctx, void *msg)
469+
{
470+
if (IS_ERR_OR_NULL(ctx->hwmon_dev) && !ctx->resp_pending) {
471+
/* Enqueue to the FIFO */
472+
kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
473+
sizeof(struct slimpro_resp_msg),
474+
&ctx->kfifo_lock);
475+
return -ENODEV;
476+
}
477+
478+
return 0;
479+
}
480+
468481
/*
469482
* This function is called when the SLIMpro Mailbox received a message
470483
*/
471484
static void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
472485
{
473486
struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl);
474-
struct slimpro_resp_msg amsg;
487+
488+
/*
489+
* While the driver registers with the mailbox framework, an interrupt
490+
* can be pending before the probe function completes its
491+
* initialization. If such condition occurs, just queue up the message
492+
* as the driver is not ready for servicing the callback.
493+
*/
494+
if (xgene_hwmon_rx_ready(ctx, msg) < 0)
495+
return;
475496

476497
/*
477498
* Response message format:
@@ -500,12 +521,8 @@ static void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
500521
return;
501522
}
502523

503-
amsg.msg = ((u32 *)msg)[0];
504-
amsg.param1 = ((u32 *)msg)[1];
505-
amsg.param2 = ((u32 *)msg)[2];
506-
507524
/* Enqueue to the FIFO */
508-
kfifo_in_spinlocked(&ctx->async_msg_fifo, &amsg,
525+
kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
509526
sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock);
510527
/* Schedule the bottom handler */
511528
schedule_work(&ctx->workq);
@@ -520,6 +537,15 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
520537
struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
521538
struct slimpro_resp_msg amsg;
522539

540+
/*
541+
* While the driver registers with the mailbox framework, an interrupt
542+
* can be pending before the probe function completes its
543+
* initialization. If such condition occurs, just queue up the message
544+
* as the driver is not ready for servicing the callback.
545+
*/
546+
if (xgene_hwmon_rx_ready(ctx, &amsg) < 0)
547+
return;
548+
523549
msg = generic_comm_base + 1;
524550
/* Check if platform sends interrupt */
525551
if (!xgene_word_tst_and_clr(&generic_comm_base->status,
@@ -596,6 +622,17 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
596622
platform_set_drvdata(pdev, ctx);
597623
cl = &ctx->mbox_client;
598624

625+
spin_lock_init(&ctx->kfifo_lock);
626+
mutex_init(&ctx->rd_mutex);
627+
628+
rc = kfifo_alloc(&ctx->async_msg_fifo,
629+
sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE,
630+
GFP_KERNEL);
631+
if (rc)
632+
goto out_mbox_free;
633+
634+
INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);
635+
599636
/* Request mailbox channel */
600637
cl->dev = &pdev->dev;
601638
cl->tx_done = xgene_hwmon_tx_done;
@@ -676,17 +713,6 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
676713
ctx->usecs_lat = PCC_NUM_RETRIES * cppc_ss->latency;
677714
}
678715

679-
spin_lock_init(&ctx->kfifo_lock);
680-
mutex_init(&ctx->rd_mutex);
681-
682-
rc = kfifo_alloc(&ctx->async_msg_fifo,
683-
sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE,
684-
GFP_KERNEL);
685-
if (rc)
686-
goto out_mbox_free;
687-
688-
INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);
689-
690716
ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev,
691717
"apm_xgene",
692718
ctx,
@@ -697,17 +723,22 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
697723
goto out;
698724
}
699725

726+
/*
727+
* Schedule the bottom handler if there is a pending message.
728+
*/
729+
schedule_work(&ctx->workq);
730+
700731
dev_info(&pdev->dev, "APM X-Gene SoC HW monitor driver registered\n");
701732

702733
return 0;
703734

704735
out:
705-
kfifo_free(&ctx->async_msg_fifo);
706-
out_mbox_free:
707736
if (acpi_disabled)
708737
mbox_free_channel(ctx->mbox_chan);
709738
else
710739
pcc_mbox_free_channel(ctx->mbox_chan);
740+
out_mbox_free:
741+
kfifo_free(&ctx->async_msg_fifo);
711742

712743
return rc;
713744
}

0 commit comments

Comments
 (0)