summaryrefslogtreecommitdiff
path: root/drivers/mailbox/pcc.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2024-12-02 11:53:34 +1000
committerDave Airlie <airlied@redhat.com>2024-12-02 11:53:34 +1000
commit9ee603b619a6fcc030b46012a900b67e0041b90d (patch)
tree00bf3ba8d87c6720ba1f7de62ce6ef4dd0c5c371 /drivers/mailbox/pcc.c
parent25961511c559ed13db76df3ae5ee0b7f43d209e8 (diff)
parent40384c840ea1944d7c5a392e8975ed088ecf0b37 (diff)
Merge remote-tracking branch 'drm/drm-next' into drm-tip
Diffstat (limited to 'drivers/mailbox/pcc.c')
-rw-r--r--drivers/mailbox/pcc.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 94885e411085..82102a4c5d68 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -269,6 +269,35 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan)
return !!val;
}
+static void check_and_ack(struct pcc_chan_info *pchan, struct mbox_chan *chan)
+{
+ struct acpi_pcct_ext_pcc_shared_memory pcc_hdr;
+
+ if (pchan->type != ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE)
+ return;
+ /* If the memory region has not been mapped, we cannot
+ * determine if we need to send the message, but we still
+ * need to set the cmd_update flag before returning.
+ */
+ if (pchan->chan.shmem == NULL) {
+ pcc_chan_reg_read_modify_write(&pchan->cmd_update);
+ return;
+ }
+ memcpy_fromio(&pcc_hdr, pchan->chan.shmem,
+ sizeof(struct acpi_pcct_ext_pcc_shared_memory));
+ /*
+ * The PCC slave subspace channel needs to set the command complete bit
+ * after processing message. If the PCC_ACK_FLAG is set, it should also
+ * ring the doorbell.
+ *
+ * The PCC master subspace channel clears chan_in_use to free channel.
+ */
+ if (le32_to_cpup(&pcc_hdr.flags) & PCC_ACK_FLAG_MASK)
+ pcc_send_data(chan, NULL);
+ else
+ pcc_chan_reg_read_modify_write(&pchan->cmd_update);
+}
+
/**
* pcc_mbox_irq - PCC mailbox interrupt handler
* @irq: interrupt number
@@ -306,14 +335,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
mbox_chan_received_data(chan, NULL);
- /*
- * The PCC slave subspace channel needs to set the command complete bit
- * and ring doorbell after processing message.
- *
- * The PCC master subspace channel clears chan_in_use to free channel.
- */
- if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE)
- pcc_send_data(chan, NULL);
+ check_and_ack(pchan, chan);
pchan->chan_in_use = false;
return IRQ_HANDLED;
@@ -365,14 +387,37 @@ EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan)
{
struct mbox_chan *chan = pchan->mchan;
+ struct pcc_chan_info *pchan_info;
+ struct pcc_mbox_chan *pcc_mbox_chan;
if (!chan || !chan->cl)
return;
+ pchan_info = chan->con_priv;
+ pcc_mbox_chan = &pchan_info->chan;
+ if (pcc_mbox_chan->shmem) {
+ iounmap(pcc_mbox_chan->shmem);
+ pcc_mbox_chan->shmem = NULL;
+ }
mbox_free_channel(chan);
}
EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
+int pcc_mbox_ioremap(struct mbox_chan *chan)
+{
+ struct pcc_chan_info *pchan_info;
+ struct pcc_mbox_chan *pcc_mbox_chan;
+
+ if (!chan || !chan->cl)
+ return -1;
+ pchan_info = chan->con_priv;
+ pcc_mbox_chan = &pchan_info->chan;
+ pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr,
+ pcc_mbox_chan->shmem_size);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcc_mbox_ioremap);
+
/**
* pcc_send_data - Called from Mailbox Controller code. Used
* here only to ring the channel doorbell. The PCC client