Skip to content

Commit 3db174e

Browse files
LiHuiSong1sudeep-holla
authored andcommitted
mailbox: pcc: Support shared interrupt for multiple subspaces
If the platform acknowledge interrupt is level triggered, then it can be shared by multiple subspaces provided each one has a unique platform interrupt ack preserve and ack set masks. If it can be shared, then we can request the irq with IRQF_SHARED and IRQF_ONESHOT flags. The first one indicating it can be shared and the latter one to keep the interrupt disabled until the hardirq handler finished. Further, since there is no way to detect if the interrupt is for a given channel as the interrupt ack preserve and ack set masks are for clearing the interrupt and not for reading the status(in case Irq Ack register may be write-only on some platforms), we need a way to identify if the given channel is in use and expecting the interrupt. PCC type0, type1 and type5 do not support shared level triggered interrupt. The methods of determining whether a given channel for remaining types should respond to an interrupt are as follows: - type2: Whether the interrupt belongs to a given channel is only determined by the status field in Generic Communications Channel Shared Memory Region, which is done in rx_callback of PCC client. - type3: This channel checks chan_in_use flag first and then checks the command complete bit(value '1' indicates that the command has been completed). - type4: Platform ensure that the default value of the command complete bit corresponding to the type4 channel is '1'. This command complete bit is '0' when receive a platform notification. The new field, 'chan_in_use' is used by the type only support the communication from OSPM to Platform (like type3) and should be completely ignored by other types so as to avoid too many type unnecessary checks in IRQ handler. Signed-off-by: Huisong Li <[email protected]> Reviewed-by: Hanjun Guo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sudeep Holla <[email protected]>
1 parent 60c40b0 commit 3db174e

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

drivers/mailbox/pcc.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ struct pcc_chan_reg {
9292
* @error: PCC register bundle for the error status register
9393
* @plat_irq: platform interrupt
9494
* @type: PCC subspace type
95+
* @plat_irq_flags: platform interrupt flags
96+
* @chan_in_use: this flag is used just to check if the interrupt needs
97+
* handling when it is shared. Since only one transfer can occur
98+
* at a time and mailbox takes care of locking, this flag can be
99+
* accessed without a lock. Note: the type only support the
100+
* communication from OSPM to Platform, like type3, use it, and
101+
* other types completely ignore it.
95102
*/
96103
struct pcc_chan_info {
97104
struct pcc_mbox_chan chan;
@@ -102,6 +109,8 @@ struct pcc_chan_info {
102109
struct pcc_chan_reg error;
103110
int plat_irq;
104111
u8 type;
112+
unsigned int plat_irq_flags;
113+
bool chan_in_use;
105114
};
106115

107116
#define to_pcc_chan_info(c) container_of(c, struct pcc_chan_info, chan)
@@ -225,6 +234,12 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags)
225234
return acpi_register_gsi(NULL, interrupt, trigger, polarity);
226235
}
227236

237+
static bool pcc_chan_plat_irq_can_be_shared(struct pcc_chan_info *pchan)
238+
{
239+
return (pchan->plat_irq_flags & ACPI_PCCT_INTERRUPT_MODE) ==
240+
ACPI_LEVEL_SENSITIVE;
241+
}
242+
228243
static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan)
229244
{
230245
u64 val;
@@ -242,6 +257,7 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan)
242257
* command complete.
243258
*/
244259
val &= pchan->cmd_complete.status_mask;
260+
245261
/*
246262
* If this is PCC slave subspace channel, and the command complete
247263
* bit 0 indicates that Platform is sending a notification and OSPM
@@ -268,6 +284,10 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
268284
int ret;
269285

270286
pchan = chan->con_priv;
287+
if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE &&
288+
!pchan->chan_in_use)
289+
return IRQ_NONE;
290+
271291
if (!pcc_mbox_cmd_complete_check(pchan))
272292
return IRQ_NONE;
273293

@@ -289,9 +309,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
289309
/*
290310
* The PCC slave subspace channel needs to set the command complete bit
291311
* and ring doorbell after processing message.
312+
*
313+
* The PCC master subspace channel clears chan_in_use to free channel.
292314
*/
293315
if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE)
294316
pcc_send_data(chan, NULL);
317+
pchan->chan_in_use = false;
295318

296319
return IRQ_HANDLED;
297320
}
@@ -371,7 +394,11 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
371394
if (ret)
372395
return ret;
373396

374-
return pcc_chan_reg_read_modify_write(&pchan->db);
397+
ret = pcc_chan_reg_read_modify_write(&pchan->db);
398+
if (!ret && pchan->plat_irq > 0)
399+
pchan->chan_in_use = true;
400+
401+
return ret;
375402
}
376403

377404
/**
@@ -384,11 +411,14 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
384411
static int pcc_startup(struct mbox_chan *chan)
385412
{
386413
struct pcc_chan_info *pchan = chan->con_priv;
414+
unsigned long irqflags;
387415
int rc;
388416

389417
if (pchan->plat_irq > 0) {
390-
rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq, 0,
391-
MBOX_IRQ_NAME, chan);
418+
irqflags = pcc_chan_plat_irq_can_be_shared(pchan) ?
419+
IRQF_SHARED | IRQF_ONESHOT : 0;
420+
rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq,
421+
irqflags, MBOX_IRQ_NAME, chan);
392422
if (unlikely(rc)) {
393423
dev_err(chan->mbox->dev, "failed to register PCC interrupt %d\n",
394424
pchan->plat_irq);
@@ -494,6 +524,7 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
494524
pcct_ss->platform_interrupt);
495525
return -EINVAL;
496526
}
527+
pchan->plat_irq_flags = pcct_ss->flags;
497528

498529
if (pcct_ss->header.type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) {
499530
struct acpi_pcct_hw_reduced_type2 *pcct2_ss = (void *)pcct_ss;
@@ -515,6 +546,12 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
515546
"PLAT IRQ ACK");
516547
}
517548

549+
if (pcc_chan_plat_irq_can_be_shared(pchan) &&
550+
!pchan->plat_irq_ack.gas) {
551+
pr_err("PCC subspace has level IRQ with no ACK register\n");
552+
return -EINVAL;
553+
}
554+
518555
return ret;
519556
}
520557

0 commit comments

Comments
 (0)