in xgene-hwmon.c [615:758]
static int xgene_hwmon_probe(struct platform_device *pdev)
{
struct xgene_hwmon_dev *ctx;
struct mbox_client *cl;
int rc;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->dev = &pdev->dev;
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)
return -ENOMEM;
INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);
/* Request mailbox channel */
cl->dev = &pdev->dev;
cl->tx_done = xgene_hwmon_tx_done;
cl->tx_block = false;
cl->tx_tout = MBOX_OP_TIMEOUTMS;
cl->knows_txdone = false;
if (acpi_disabled) {
cl->rx_callback = xgene_hwmon_rx_cb;
ctx->mbox_chan = mbox_request_channel(cl, 0);
if (IS_ERR(ctx->mbox_chan)) {
dev_err(&pdev->dev,
"SLIMpro mailbox channel request failed\n");
rc = -ENODEV;
goto out_mbox_free;
}
} else {
struct pcc_mbox_chan *pcc_chan;
const struct acpi_device_id *acpi_id;
int version;
acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
&pdev->dev);
if (!acpi_id) {
rc = -EINVAL;
goto out_mbox_free;
}
version = (int)acpi_id->driver_data;
if (device_property_read_u32(&pdev->dev, "pcc-channel",
&ctx->mbox_idx)) {
dev_err(&pdev->dev, "no pcc-channel property\n");
rc = -ENODEV;
goto out_mbox_free;
}
cl->rx_callback = xgene_hwmon_pcc_rx_cb;
pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx);
if (IS_ERR(pcc_chan)) {
dev_err(&pdev->dev,
"PPC channel request failed\n");
rc = -ENODEV;
goto out_mbox_free;
}
ctx->pcc_chan = pcc_chan;
ctx->mbox_chan = pcc_chan->mchan;
if (!ctx->mbox_chan->mbox->txdone_irq) {
dev_err(&pdev->dev, "PCC IRQ not supported\n");
rc = -ENODEV;
goto out;
}
/*
* This is the shared communication region
* for the OS and Platform to communicate over.
*/
ctx->comm_base_addr = pcc_chan->shmem_base_addr;
if (ctx->comm_base_addr) {
if (version == XGENE_HWMON_V2)
ctx->pcc_comm_addr = (void __force *)ioremap(
ctx->comm_base_addr,
pcc_chan->shmem_size);
else
ctx->pcc_comm_addr = memremap(
ctx->comm_base_addr,
pcc_chan->shmem_size,
MEMREMAP_WB);
} else {
dev_err(&pdev->dev, "Failed to get PCC comm region\n");
rc = -ENODEV;
goto out;
}
if (!ctx->pcc_comm_addr) {
dev_err(&pdev->dev,
"Failed to ioremap PCC comm region\n");
rc = -ENOMEM;
goto out;
}
/*
* pcc_chan->latency is just a Nominal value. In reality
* the remote processor could be much slower to reply.
* So add an arbitrary amount of wait on top of Nominal.
*/
ctx->usecs_lat = PCC_NUM_RETRIES * pcc_chan->latency;
}
ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev,
"apm_xgene",
ctx,
xgene_hwmon_groups);
if (IS_ERR(ctx->hwmon_dev)) {
dev_err(&pdev->dev, "Failed to register HW monitor device\n");
rc = PTR_ERR(ctx->hwmon_dev);
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:
if (acpi_disabled)
mbox_free_channel(ctx->mbox_chan);
else
pcc_mbox_free_channel(ctx->pcc_chan);
out_mbox_free:
kfifo_free(&ctx->async_msg_fifo);
return rc;
}