@@ -91,6 +91,14 @@ struct pcc_chan_reg {
91
91
* @cmd_update: PCC register bundle for the command complete update register
92
92
* @error: PCC register bundle for the error status register
93
93
* @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.
94
102
*/
95
103
struct pcc_chan_info {
96
104
struct pcc_mbox_chan chan ;
@@ -100,12 +108,17 @@ struct pcc_chan_info {
100
108
struct pcc_chan_reg cmd_update ;
101
109
struct pcc_chan_reg error ;
102
110
int plat_irq ;
111
+ u8 type ;
112
+ unsigned int plat_irq_flags ;
113
+ bool chan_in_use ;
103
114
};
104
115
105
116
#define to_pcc_chan_info (c ) container_of(c, struct pcc_chan_info, chan)
106
117
static struct pcc_chan_info * chan_info ;
107
118
static int pcc_chan_count ;
108
119
120
+ static int pcc_send_data (struct mbox_chan * chan , void * data );
121
+
109
122
/*
110
123
* PCC can be used with perf critical drivers such as CPPC
111
124
* So it makes sense to locally cache the virtual address and
@@ -221,6 +234,41 @@ static int pcc_map_interrupt(u32 interrupt, u32 flags)
221
234
return acpi_register_gsi (NULL , interrupt , trigger , polarity );
222
235
}
223
236
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
+
224
272
/**
225
273
* pcc_mbox_irq - PCC mailbox interrupt handler
226
274
* @irq: interrupt number
@@ -236,16 +284,12 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
236
284
int ret ;
237
285
238
286
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 )
242
289
return IRQ_NONE ;
243
290
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 ;
249
293
250
294
ret = pcc_chan_reg_read (& pchan -> error , & val );
251
295
if (ret )
@@ -262,6 +306,16 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
262
306
263
307
mbox_chan_received_data (chan , NULL );
264
308
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
+
265
319
return IRQ_HANDLED ;
266
320
}
267
321
@@ -340,7 +394,11 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
340
394
if (ret )
341
395
return ret ;
342
396
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 ;
344
402
}
345
403
346
404
/**
@@ -353,11 +411,14 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
353
411
static int pcc_startup (struct mbox_chan * chan )
354
412
{
355
413
struct pcc_chan_info * pchan = chan -> con_priv ;
414
+ unsigned long irqflags ;
356
415
int rc ;
357
416
358
417
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 );
361
422
if (unlikely (rc )) {
362
423
dev_err (chan -> mbox -> dev , "failed to register PCC interrupt %d\n" ,
363
424
pchan -> plat_irq );
@@ -463,6 +524,7 @@ static int pcc_parse_subspace_irq(struct pcc_chan_info *pchan,
463
524
pcct_ss -> platform_interrupt );
464
525
return - EINVAL ;
465
526
}
527
+ pchan -> plat_irq_flags = pcct_ss -> flags ;
466
528
467
529
if (pcct_ss -> header .type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 ) {
468
530
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,
484
546
"PLAT IRQ ACK" );
485
547
}
486
548
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
+
487
555
return ret ;
488
556
}
489
557
@@ -698,6 +766,7 @@ static int pcc_mbox_probe(struct platform_device *pdev)
698
766
699
767
pcc_parse_subspace_shmem (pchan , pcct_entry );
700
768
769
+ pchan -> type = pcct_entry -> type ;
701
770
pcct_entry = (struct acpi_subtable_header * )
702
771
((unsigned long ) pcct_entry + pcct_entry -> length );
703
772
}
0 commit comments