summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mailbox/pcc.c107
1 files changed, 54 insertions, 53 deletions
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 23391e224a68..588d2207edf9 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -64,12 +64,20 @@
static struct mbox_chan *pcc_mbox_channels;
-/* Array of cached virtual address for doorbell registers */
-static void __iomem **pcc_doorbell_vaddr;
-/* Array of cached virtual address for doorbell ack registers */
-static void __iomem **pcc_doorbell_ack_vaddr;
-/* Array of doorbell interrupts */
-static int *pcc_doorbell_irq;
+/**
+ * struct pcc_chan_info - PCC channel specific information
+ *
+ * @db_vaddr: cached virtual address for doorbell register
+ * @db_ack_vaddr: cached virtual address for doorbell ack register
+ * @db_irq: doorbell interrupt
+ */
+struct pcc_chan_info {
+ void __iomem *db_vaddr;
+ void __iomem *db_ack_vaddr;
+ int db_irq;
+};
+
+static struct pcc_chan_info *chan_info;
static struct mbox_controller pcc_mbox_ctrl = {};
/**
@@ -183,6 +191,7 @@ 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;
@@ -197,17 +206,17 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
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(pcc_doorbell_ack_vaddr[id],
- &doorbell_ack_val,
- doorbell_ack->bit_width);
+ ret = read_register(pchan->db_ack_vaddr,
+ &doorbell_ack_val, doorbell_ack->bit_width);
if (ret)
return IRQ_NONE;
- ret = write_register(pcc_doorbell_ack_vaddr[id],
+ ret = write_register(pchan->db_ack_vaddr,
(doorbell_ack_val & doorbell_ack_preserve)
| doorbell_ack_write,
doorbell_ack->bit_width);
@@ -232,8 +241,9 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
* ERR_PTR.
*/
struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
- int subspace_id)
+ int subspace_id)
{
+ struct pcc_chan_info *pchan;
struct device *dev = pcc_mbox_ctrl.dev;
struct mbox_chan *chan;
unsigned long flags;
@@ -251,6 +261,7 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
dev_err(dev, "Channel not found for idx: %d\n", subspace_id);
return ERR_PTR(-EBUSY);
}
+ pchan = chan_info + subspace_id;
spin_lock_irqsave(&chan->lock, flags);
chan->msg_free = 0;
@@ -264,14 +275,14 @@ struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
spin_unlock_irqrestore(&chan->lock, flags);
- if (pcc_doorbell_irq[subspace_id] > 0) {
+ if (pchan->db_irq > 0) {
int rc;
- rc = devm_request_irq(dev, pcc_doorbell_irq[subspace_id],
- pcc_mbox_irq, 0, MBOX_IRQ_NAME, chan);
+ rc = devm_request_irq(dev, pchan->db_irq, pcc_mbox_irq, 0,
+ MBOX_IRQ_NAME, chan);
if (unlikely(rc)) {
dev_err(dev, "failed to register PCC interrupt %d\n",
- pcc_doorbell_irq[subspace_id]);
+ pchan->db_irq);
pcc_mbox_free_channel(chan);
chan = ERR_PTR(rc);
}
@@ -290,6 +301,7 @@ EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
void pcc_mbox_free_channel(struct mbox_chan *chan)
{
u32 id = chan - pcc_mbox_channels;
+ struct pcc_chan_info *pchan;
unsigned long flags;
if (!chan || !chan->cl)
@@ -300,8 +312,9 @@ void pcc_mbox_free_channel(struct mbox_chan *chan)
return;
}
- if (pcc_doorbell_irq[id] > 0)
- devm_free_irq(chan->mbox->dev, pcc_doorbell_irq[id], chan);
+ pchan = chan_info + id;
+ if (pchan->db_irq > 0)
+ devm_free_irq(chan->mbox->dev, pchan->db_irq, chan);
spin_lock_irqsave(&chan->lock, flags);
chan->cl = NULL;
@@ -329,6 +342,7 @@ 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;
@@ -340,19 +354,20 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
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 (pcc_doorbell_vaddr[id]) {
- ret = read_register(pcc_doorbell_vaddr[id], &doorbell_val,
- doorbell->bit_width);
+ if (pchan->db_vaddr) {
+ ret = read_register(pchan->db_vaddr, &doorbell_val,
+ doorbell->bit_width);
if (ret)
return ret;
- ret = write_register(pcc_doorbell_vaddr[id],
- (doorbell_val & doorbell_preserve) | doorbell_write,
- doorbell->bit_width);
+ ret = write_register(pchan->db_vaddr,
+ (doorbell_val & doorbell_preserve)
+ | doorbell_write, doorbell->bit_width);
} else {
ret = acpi_read(&doorbell_val, doorbell);
if (ret)
@@ -398,12 +413,13 @@ static int parse_pcc_subspace(union acpi_subtable_headers *header,
*
* This gets called for each entry in the PCC table.
*/
-static int pcc_parse_subspace_irq(int id,
- struct acpi_pcct_hw_reduced *pcct_ss)
+static int pcc_parse_subspace_irq(int id, struct acpi_pcct_hw_reduced *pcct_ss)
{
- pcc_doorbell_irq[id] = pcc_map_interrupt(pcct_ss->platform_interrupt,
- (u32)pcct_ss->flags);
- if (pcc_doorbell_irq[id] <= 0) {
+ struct pcc_chan_info *pchan = chan_info + id;
+
+ pchan->db_irq = pcc_map_interrupt(pcct_ss->platform_interrupt,
+ (u32)pcct_ss->flags);
+ if (pchan->db_irq <= 0) {
pr_err("PCC GSI %d not registered\n",
pcct_ss->platform_interrupt);
return -EINVAL;
@@ -413,10 +429,10 @@ static int pcc_parse_subspace_irq(int id,
== ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss;
- pcc_doorbell_ack_vaddr[id] = acpi_os_ioremap(
- pcct2_ss->platform_ack_register.address,
- pcct2_ss->platform_ack_register.bit_width / 8);
- if (!pcc_doorbell_ack_vaddr[id]) {
+ pchan->db_ack_vaddr =
+ acpi_os_ioremap(pcct2_ss->platform_ack_register.address,
+ pcct2_ss->platform_ack_register.bit_width / 8);
+ if (!pchan->db_ack_vaddr) {
pr_err("Failed to ioremap PCC ACK register\n");
return -ENOMEM;
}
@@ -474,24 +490,12 @@ static int __init acpi_pcc_probe(void)
goto err_put_pcct;
}
- pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL);
- if (!pcc_doorbell_vaddr) {
+ chan_info = kcalloc(count, sizeof(*chan_info), GFP_KERNEL);
+ if (!chan_info) {
rc = -ENOMEM;
goto err_free_mbox;
}
- pcc_doorbell_ack_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL);
- if (!pcc_doorbell_ack_vaddr) {
- rc = -ENOMEM;
- goto err_free_db_vaddr;
- }
-
- pcc_doorbell_irq = kcalloc(count, sizeof(int), GFP_KERNEL);
- if (!pcc_doorbell_irq) {
- rc = -ENOMEM;
- goto err_free_db_ack_vaddr;
- }
-
/* Point to the first PCC subspace entry */
pcct_entry = (struct acpi_subtable_header *) (
(unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));
@@ -501,6 +505,7 @@ static int __init acpi_pcc_probe(void)
pcc_mbox_ctrl.txdone_irq = true;
for (i = 0; i < count; i++) {
+ struct pcc_chan_info *pchan = chan_info + i;
struct acpi_generic_address *db_reg;
struct acpi_pcct_subspace *pcct_ss;
pcc_mbox_channels[i].con_priv = pcct_entry;
@@ -522,8 +527,8 @@ static int __init acpi_pcc_probe(void)
/* 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)
- pcc_doorbell_vaddr[i] = acpi_os_ioremap(db_reg->address,
- db_reg->bit_width/8);
+ pchan->db_vaddr = acpi_os_ioremap(db_reg->address,
+ db_reg->bit_width / 8);
pcct_entry = (struct acpi_subtable_header *)
((unsigned long) pcct_entry + pcct_entry->length);
}
@@ -535,11 +540,7 @@ static int __init acpi_pcc_probe(void)
return 0;
err:
- kfree(pcc_doorbell_irq);
-err_free_db_ack_vaddr:
- kfree(pcc_doorbell_ack_vaddr);
-err_free_db_vaddr:
- kfree(pcc_doorbell_vaddr);
+ kfree(chan_info);
err_free_mbox:
kfree(pcc_mbox_channels);
err_put_pcct: