aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mailbox/pcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mailbox/pcc.c')
-rw-r--r--drivers/mailbox/pcc.c119
1 files changed, 32 insertions, 87 deletions
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index deaea9d423a7..ed635f7d3f60 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -86,15 +86,15 @@ struct pcc_chan_reg {
* struct pcc_chan_info - PCC channel specific information
*
* @chan: PCC channel information with Shared Memory Region info
- * @db_vaddr: cached virtual address for doorbell register
- * @plat_irq_ack_vaddr: cached virtual address for platform interrupt
- * acknowledge register
+ * @db: PCC register bundle for the doorbell register
+ * @plat_irq_ack: PCC register bundle for the platform interrupt acknowledge
+ * register
* @plat_irq: platform interrupt
*/
struct pcc_chan_info {
struct pcc_mbox_chan chan;
- void __iomem *db_vaddr;
- void __iomem *plat_irq_ack_vaddr;
+ struct pcc_chan_reg db;
+ struct pcc_chan_reg plat_irq_ack;
int plat_irq;
};
@@ -242,40 +242,15 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags)
*/
static irqreturn_t pcc_mbox_irq(int irq, void *p)
{
- struct acpi_generic_address *doorbell_ack;
- struct acpi_pcct_hw_reduced *pcct_ss;
struct pcc_chan_info *pchan;
struct mbox_chan *chan = p;
- u64 doorbell_ack_preserve;
- u64 doorbell_ack_write;
- u64 doorbell_ack_val;
- int ret;
- pcct_ss = chan->con_priv;
+ pchan = chan->con_priv;
- mbox_chan_received_data(chan, NULL);
+ if (pcc_chan_reg_read_modify_write(&pchan->plat_irq_ack))
+ return IRQ_NONE;
- if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
- struct acpi_pcct_hw_reduced_type2 *pcct2_ss = chan->con_priv;
- u32 id = chan - pcc_mbox_channels;
-
- pchan = chan_info + id;
- doorbell_ack = &pcct2_ss->platform_ack_register;
- doorbell_ack_preserve = pcct2_ss->ack_preserve_mask;
- doorbell_ack_write = pcct2_ss->ack_write_mask;
-
- ret = read_register(pchan->plat_irq_ack_vaddr,
- &doorbell_ack_val, doorbell_ack->bit_width);
- if (ret)
- return IRQ_NONE;
-
- ret = write_register(pchan->plat_irq_ack_vaddr,
- (doorbell_ack_val & doorbell_ack_preserve)
- | doorbell_ack_write,
- doorbell_ack->bit_width);
- if (ret)
- return IRQ_NONE;
- }
+ mbox_chan_received_data(chan, NULL);
return IRQ_HANDLED;
}
@@ -381,42 +356,9 @@ EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
*/
static int pcc_send_data(struct mbox_chan *chan, void *data)
{
- struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv;
- struct acpi_generic_address *doorbell;
- struct pcc_chan_info *pchan;
- u64 doorbell_preserve;
- u64 doorbell_val;
- u64 doorbell_write;
- u32 id = chan - pcc_mbox_channels;
- int ret = 0;
+ struct pcc_chan_info *pchan = chan->con_priv;
- if (id >= pcc_mbox_ctrl.num_chans) {
- pr_debug("pcc_send_data: Invalid mbox_chan passed\n");
- return -ENOENT;
- }
-
- pchan = chan_info + id;
- doorbell = &pcct_ss->doorbell_register;
- doorbell_preserve = pcct_ss->preserve_mask;
- doorbell_write = pcct_ss->write_mask;
-
- /* Sync notification from OS to Platform. */
- if (pchan->db_vaddr) {
- ret = read_register(pchan->db_vaddr, &doorbell_val,
- doorbell->bit_width);
- if (ret)
- return ret;
- ret = write_register(pchan->db_vaddr,
- (doorbell_val & doorbell_preserve)
- | doorbell_write, doorbell->bit_width);
- } else {
- ret = acpi_read(&doorbell_val, doorbell);
- if (ret)
- return ret;
- ret = acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
- doorbell);
- }
- return ret;
+ return pcc_chan_reg_read_modify_write(&pchan->db);
}
static const struct mbox_chan_ops pcc_chan_ops = {
@@ -484,6 +426,7 @@ pcc_chan_reg_init(struct pcc_chan_reg *reg, struct acpi_generic_address *gas,
static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
struct acpi_subtable_header *pcct_entry)
{
+ int ret = 0;
struct acpi_pcct_hw_reduced *pcct_ss;
if (pcct_entry->type < ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE ||
@@ -502,16 +445,14 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss;
- pchan->plat_irq_ack_vaddr =
- acpi_os_ioremap(pcct2_ss->platform_ack_register.address,
- pcct2_ss->platform_ack_register.bit_width / 8);
- if (!pchan->plat_irq_ack_vaddr) {
- pr_err("Failed to ioremap PCC ACK register\n");
- return -ENOMEM;
- }
+ ret = pcc_chan_reg_init(&pchan->plat_irq_ack,
+ &pcct2_ss->platform_ack_register,
+ pcct2_ss->ack_preserve_mask,
+ pcct2_ss->ack_write_mask, 0,
+ "PLAT IRQ ACK");
}
- return 0;
+ return ret;
}
/**
@@ -520,20 +461,22 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
* @pchan: Pointer to the PCC channel info structure.
* @pcct_entry: Pointer to the ACPI subtable header.
*
+ * Return: 0 for Success, else errno.
*/
-static void pcc_parse_subspace_db_reg(struct pcc_chan_info *pchan,
- struct acpi_subtable_header *pcct_entry)
+static int pcc_parse_subspace_db_reg(struct pcc_chan_info *pchan,
+ struct acpi_subtable_header *pcct_entry)
{
+ int ret = 0;
+
struct acpi_pcct_subspace *pcct_ss;
- struct acpi_generic_address *db_reg;
pcct_ss = (struct acpi_pcct_subspace *)pcct_entry;
- /* If doorbell is in system memory cache the virt address */
- db_reg = &pcct_ss->doorbell_register;
- if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- pchan->db_vaddr = acpi_os_ioremap(db_reg->address,
- db_reg->bit_width / 8);
+ ret = pcc_chan_reg_init(&pchan->db,
+ &pcct_ss->doorbell_register,
+ pcct_ss->preserve_mask,
+ pcct_ss->write_mask, 0, "Doorbell");
+ return ret;
}
/**
@@ -622,8 +565,8 @@ static int __init acpi_pcc_probe(void)
for (i = 0; i < count; i++) {
struct pcc_chan_info *pchan = chan_info + i;
- pcc_mbox_channels[i].con_priv = pcct_entry;
+ pcc_mbox_channels[i].con_priv = pchan;
pchan->chan.mchan = &pcc_mbox_channels[i];
if (pcc_mbox_ctrl.txdone_irq) {
@@ -631,7 +574,9 @@ static int __init acpi_pcc_probe(void)
if (rc < 0)
goto err;
}
- pcc_parse_subspace_db_reg(pchan, pcct_entry);
+ rc = pcc_parse_subspace_db_reg(pchan, pcct_entry);
+ if (rc < 0)
+ goto err;
pcc_parse_subspace_shmem(pchan, pcct_entry);