/* Write signature for subspace */
WRITE_ONCE(generic_comm_base->signature,
cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx));
/* Write to the shared command region */
WRITE_ONCE(generic_comm_base->command,
cpu_to_le16(MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR));
/* Flip CMD COMPLETE bit */
val = le16_to_cpu(READ_ONCE(generic_comm_base->status));
val &= ~PCC_STATUS_CMD_COMPLETE;
WRITE_ONCE(generic_comm_base->status, cpu_to_le16(val));
/* Copy the message to the PCC comm space */ for (i = 0; i < sizeof(struct slimpro_resp_msg) / 4; i++)
WRITE_ONCE(ptr[i], cpu_to_le32(msg[i]));
/* Ring the doorbell */
rc = mbox_send_message(ctx->mbox_chan, msg); if (rc < 0) {
dev_err(ctx->dev, "Mailbox send error %d\n", rc); goto err;
} if (!wait_for_completion_timeout(&ctx->rd_complete,
usecs_to_jiffies(ctx->usecs_lat))) {
dev_err(ctx->dev, "Mailbox operation timed out\n");
rc = -ETIMEDOUT; goto err;
}
/* Check for error message */ if (MSG_TYPE(ctx->sync_msg.msg) == MSG_TYPE_ERR) {
rc = -EINVAL; goto err;
}
/* * This function is called to process async work queue
*/ staticvoid xgene_hwmon_evt_work(struct work_struct *work)
{ struct slimpro_resp_msg amsg; struct xgene_hwmon_dev *ctx; int ret;
ctx = container_of(work, struct xgene_hwmon_dev, workq); while (kfifo_out_spinlocked(&ctx->async_msg_fifo, &amsg, sizeof(struct slimpro_resp_msg),
&ctx->kfifo_lock)) { /* * If PCC, send a consumer command to Platform to get info * If Slimpro Mailbox, get message from specific FIFO
*/ if (!acpi_disabled) {
ret = xgene_hwmon_get_notification_msg(ctx,
(u32 *)&amsg); if (ret < 0) continue;
}
if (MSG_TYPE(amsg.msg) == MSG_TYPE_PWRMGMT)
xgene_hwmon_process_pwrmsg(ctx, &amsg);
}
}
staticint 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
*/ staticvoid xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
{ struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl);
/* * 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: * msg[0] is the return code of the operation * msg[1] is the first parameter word * msg[2] is the second parameter word * * As message only supports dword size, just assign it.
*/
/* Operation waiting for response */
complete(&ctx->rd_complete);
return;
}
/* Enqueue to the FIFO */
kfifo_in_spinlocked(&ctx->async_msg_fifo, msg, sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock); /* Schedule the bottom handler */
schedule_work(&ctx->workq);
}
/* * This function is called when the PCC Mailbox received a message
*/ staticvoid xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
{ struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl); struct acpi_pcct_shared_memory __iomem *generic_comm_base =
ctx->pcc_chan->shmem; 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,
PCC_STATUS_SCI_DOORBELL)) return;
/* * Response message format: * msg[0] is the return code of the operation * msg[1] is the first parameter word * msg[2] is the second parameter word * * As message only supports dword size, just assign it.
*/
/* Operation waiting for response */
complete(&ctx->rd_complete);
return;
}
}
/* * Platform notifies interrupt to OSPM. * OPSM schedules a consumer command to get this information * in a workqueue. Platform must wait until OSPM has issued * a consumer command that serves this notification.
*/
/* Enqueue to the FIFO */
kfifo_in_spinlocked(&ctx->async_msg_fifo, &amsg, sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock); /* Schedule the bottom handler */
schedule_work(&ctx->workq);
}
staticvoid xgene_hwmon_tx_done(struct mbox_client *cl, void *msg, int ret)
{ if (ret) {
dev_dbg(cl->dev, "TX did not complete: CMD sent:%x, ret:%d\n",
*(u16 *)msg, ret);
} else {
dev_dbg(cl->dev, "TX completed. CMD sent:%x, ret:%d\n",
*(u16 *)msg, ret);
}
}
if (!ctx->mbox_chan->mbox->txdone_irq) {
dev_err(&pdev->dev, "PCC IRQ not supported\n");
rc = -ENODEV; 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.