Skip to content

Commit

Permalink
hwmon: (xgene) Fix crash when alarm occurs before driver probe
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reported-by: Itaru Kitayama <[email protected]>
Signed-off-by: Guenter Roeck <[email protected]>
  • Loading branch information
hotran authored and groeck committed Sep 9, 2016
1 parent 9417fef commit 2ca492e
Showing 1 changed file with 50 additions and 19 deletions.
69 changes: 50 additions & 19 deletions drivers/hwmon/xgene-hwmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,13 +465,34 @@ static void xgene_hwmon_evt_work(struct work_struct *work)
}
}

static int xgene_hwmon_rx_ready(struct xgene_hwmon_dev *ctx, void *msg)
{
if (IS_ERR_OR_NULL(ctx->hwmon_dev) && !ctx->resp_pending) {
/* Enqueue to the FIFO */
kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
sizeof(struct slimpro_resp_msg),
&ctx->kfifo_lock);
return -ENODEV;
}

return 0;
}

/*
* This function is called when the SLIMpro Mailbox received a message
*/
static void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
{
struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl);
struct slimpro_resp_msg amsg;

/*
* While the driver registers with the mailbox framework, an interrupt
* can be pending before the probe function completes its
* initialization. If such condition occurs, just queue up the message
* as the driver is not ready for servicing the callback.
*/
if (xgene_hwmon_rx_ready(ctx, msg) < 0)
return;

/*
* Response message format:
Expand Down Expand Up @@ -500,12 +521,8 @@ static void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
return;
}

amsg.msg = ((u32 *)msg)[0];
amsg.param1 = ((u32 *)msg)[1];
amsg.param2 = ((u32 *)msg)[2];

/* Enqueue to the FIFO */
kfifo_in_spinlocked(&ctx->async_msg_fifo, &amsg,
kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock);
/* Schedule the bottom handler */
schedule_work(&ctx->workq);
Expand All @@ -520,6 +537,15 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
struct slimpro_resp_msg amsg;

/*
* While the driver registers with the mailbox framework, an interrupt
* can be pending before the probe function completes its
* initialization. If such condition occurs, just queue up the message
* as the driver is not ready for servicing the callback.
*/
if (xgene_hwmon_rx_ready(ctx, &amsg) < 0)
return;

msg = generic_comm_base + 1;
/* Check if platform sends interrupt */
if (!xgene_word_tst_and_clr(&generic_comm_base->status,
Expand Down Expand Up @@ -596,6 +622,17 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
cl = &ctx->mbox_client;

spin_lock_init(&ctx->kfifo_lock);
mutex_init(&ctx->rd_mutex);

rc = kfifo_alloc(&ctx->async_msg_fifo,
sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE,
GFP_KERNEL);
if (rc)
goto out_mbox_free;

INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);

/* Request mailbox channel */
cl->dev = &pdev->dev;
cl->tx_done = xgene_hwmon_tx_done;
Expand Down Expand Up @@ -676,17 +713,6 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
ctx->usecs_lat = PCC_NUM_RETRIES * cppc_ss->latency;
}

spin_lock_init(&ctx->kfifo_lock);
mutex_init(&ctx->rd_mutex);

rc = kfifo_alloc(&ctx->async_msg_fifo,
sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE,
GFP_KERNEL);
if (rc)
goto out_mbox_free;

INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);

ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev,
"apm_xgene",
ctx,
Expand All @@ -697,17 +723,22 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
goto out;
}

/*
* Schedule the bottom handler if there is a pending message.
*/
schedule_work(&ctx->workq);

dev_info(&pdev->dev, "APM X-Gene SoC HW monitor driver registered\n");

return 0;

out:
kfifo_free(&ctx->async_msg_fifo);
out_mbox_free:
if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan);
else
pcc_mbox_free_channel(ctx->mbox_chan);
out_mbox_free:
kfifo_free(&ctx->async_msg_fifo);

return rc;
}
Expand Down

0 comments on commit 2ca492e

Please sign in to comment.