@@ -91,6 +91,14 @@ struct pcc_chan_reg {
9191 * @cmd_update: PCC register bundle for the command complete update register
9292 * @error: PCC register bundle for the error status register
9393 * @plat_irq: platform interrupt
94+ * @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.
94102 */
95103struct pcc_chan_info {
96104 struct pcc_mbox_chan chan ;
@@ -100,12 +108,17 @@ struct pcc_chan_info {
100108 struct pcc_chan_reg cmd_update ;
101109 struct pcc_chan_reg error ;
102110 int plat_irq ;
111+ u8 type ;
112+ unsigned int plat_irq_flags ;
113+ bool chan_in_use ;
103114};
104115
105116#define to_pcc_chan_info (c ) container_of(c, struct pcc_chan_info, chan)
106117static struct pcc_chan_info * chan_info ;
107118static int pcc_chan_count ;
108119
120+ static int pcc_send_data (struct mbox_chan * chan , void * data );
121+
109122/*
110123 * PCC can be used with perf critical drivers such as CPPC
111124 * So it makes sense to locally cache the virtual address and
@@ -221,6 +234,41 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags)
221234 return acpi_register_gsi (NULL , interrupt , trigger , polarity );
222235}
223236
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+
243+ static bool pcc_mbox_cmd_complete_check (struct pcc_chan_info * pchan )
244+ {
245+ u64 val ;
246+ int ret ;
247+
248+ ret = pcc_chan_reg_read (& pchan -> cmd_complete , & val );
249+ if (ret )
250+ return false;
251+
252+ if (!pchan -> cmd_complete .gas )
253+ return true;
254+
255+ /*
256+ * Judge if the channel respond the interrupt based on the value of
257+ * command complete.
258+ */
259+ val &= pchan -> cmd_complete .status_mask ;
260+
261+ /*
262+ * If this is PCC slave subspace channel, and the command complete
263+ * bit 0 indicates that Platform is sending a notification and OSPM
264+ * needs to respond this interrupt to process this command.
265+ */
266+ if (pchan -> type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE )
267+ return !val ;
268+
269+ return !!val ;
270+ }
271+
224272/**
225273 * pcc_mbox_irq - PCC mailbox interrupt handler
226274 * @irq: interrupt number
@@ -236,16 +284,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
236284 int ret ;
237285
238286 pchan = chan -> con_priv ;
239-
240- ret = pcc_chan_reg_read (& pchan -> cmd_complete , & val );
241- if (ret )
287+ if (pchan -> type == ACPI_PCCT_TYPE_EXT_PCC_MASTER_SUBSPACE &&
288+ !pchan -> chan_in_use )
242289 return IRQ_NONE ;
243290
244- if (val ) { /* Ensure GAS exists and value is non-zero */
245- val &= pchan -> cmd_complete .status_mask ;
246- if (!val )
247- return IRQ_NONE ;
248- }
291+ if (!pcc_mbox_cmd_complete_check (pchan ))
292+ return IRQ_NONE ;
249293
250294 ret = pcc_chan_reg_read (& pchan -> error , & val );
251295 if (ret )
@@ -262,6 +306,16 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
262306
263307 mbox_chan_received_data (chan , NULL );
264308
309+ /*
310+ * The PCC slave subspace channel needs to set the command complete bit
311+ * and ring doorbell after processing message.
312+ *
313+ * The PCC master subspace channel clears chan_in_use to free channel.
314+ */
315+ if (pchan -> type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE )
316+ pcc_send_data (chan , NULL );
317+ pchan -> chan_in_use = false;
318+
265319 return IRQ_HANDLED ;
266320}
267321
@@ -340,7 +394,11 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
340394 if (ret )
341395 return ret ;
342396
343- 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 ;
344402}
345403
346404/**
@@ -353,11 +411,14 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
353411static int pcc_startup (struct mbox_chan * chan )
354412{
355413 struct pcc_chan_info * pchan = chan -> con_priv ;
414+ unsigned long irqflags ;
356415 int rc ;
357416
358417 if (pchan -> plat_irq > 0 ) {
359- rc = devm_request_irq (chan -> mbox -> dev , pchan -> plat_irq , pcc_mbox_irq , 0 ,
360- 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 );
361422 if (unlikely (rc )) {
362423 dev_err (chan -> mbox -> dev , "failed to register PCC interrupt %d\n" ,
363424 pchan -> plat_irq );
@@ -463,6 +524,7 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
463524 pcct_ss -> platform_interrupt );
464525 return - EINVAL ;
465526 }
527+ pchan -> plat_irq_flags = pcct_ss -> flags ;
466528
467529 if (pcct_ss -> header .type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 ) {
468530 struct acpi_pcct_hw_reduced_type2 * pcct2_ss = (void * )pcct_ss ;
@@ -484,6 +546,12 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
484546 "PLAT IRQ ACK" );
485547 }
486548
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+
487555 return ret ;
488556}
489557
@@ -698,6 +766,7 @@ static int pcc_mbox_probe(struct platform_device *pdev)
698766
699767 pcc_parse_subspace_shmem (pchan , pcct_entry );
700768
769+ pchan -> type = pcct_entry -> type ;
701770 pcct_entry = (struct acpi_subtable_header * )
702771 ((unsigned long ) pcct_entry + pcct_entry -> length );
703772 }
0 commit comments