@@ -417,17 +417,45 @@ static const struct of_device_id plic_match[] = {
417
417
{}
418
418
};
419
419
420
+ static int plic_parse_context_parent (struct platform_device * pdev , u32 context ,
421
+ u32 * parent_hwirq , int * parent_cpu )
422
+ {
423
+ struct device * dev = & pdev -> dev ;
424
+ struct of_phandle_args parent ;
425
+ unsigned long hartid ;
426
+ int rc ;
427
+
428
+ /*
429
+ * Currently, only OF fwnode is supported so extend this
430
+ * function for ACPI support.
431
+ */
432
+ if (!is_of_node (dev -> fwnode ))
433
+ return - EINVAL ;
434
+
435
+ rc = of_irq_parse_one (to_of_node (dev -> fwnode ), context , & parent );
436
+ if (rc )
437
+ return rc ;
438
+
439
+ rc = riscv_of_parent_hartid (parent .np , & hartid );
440
+ if (rc )
441
+ return rc ;
442
+
443
+ * parent_hwirq = parent .args [0 ];
444
+ * parent_cpu = riscv_hartid_to_cpuid (hartid );
445
+ return 0 ;
446
+ }
447
+
420
448
static int plic_probe (struct platform_device * pdev )
421
449
{
422
- int error = 0 , nr_contexts , nr_handlers = 0 , i ;
450
+ int error = 0 , nr_contexts , nr_handlers = 0 , cpu , i ;
423
451
struct device * dev = & pdev -> dev ;
424
452
unsigned long plic_quirks = 0 ;
425
453
struct plic_handler * handler ;
454
+ u32 nr_irqs , parent_hwirq ;
426
455
struct irq_domain * domain ;
427
456
struct plic_priv * priv ;
457
+ irq_hw_number_t hwirq ;
428
458
bool cpuhp_setup ;
429
- unsigned int cpu ;
430
- u32 nr_irqs ;
431
459
432
460
if (is_of_node (dev -> fwnode )) {
433
461
const struct of_device_id * id ;
@@ -463,21 +491,17 @@ static int plic_probe(struct platform_device *pdev)
463
491
return - EINVAL ;
464
492
465
493
for (i = 0 ; i < nr_contexts ; i ++ ) {
466
- struct of_phandle_args parent ;
467
- irq_hw_number_t hwirq ;
468
- int cpu ;
469
- unsigned long hartid ;
470
-
471
- if (of_irq_parse_one (to_of_node (dev -> fwnode ), i , & parent )) {
472
- dev_err (dev , "failed to parse parent for context %d.\n" , i );
494
+ error = plic_parse_context_parent (pdev , i , & parent_hwirq , & cpu );
495
+ if (error ) {
496
+ dev_warn (dev , "hwirq for context%d not found\n" , i );
473
497
continue ;
474
498
}
475
499
476
500
/*
477
501
* Skip contexts other than external interrupts for our
478
502
* privilege level.
479
503
*/
480
- if (parent . args [ 0 ] != RV_IRQ_EXT ) {
504
+ if (parent_hwirq != RV_IRQ_EXT ) {
481
505
/* Disable S-mode enable bits if running in M-mode. */
482
506
if (IS_ENABLED (CONFIG_RISCV_M_MODE )) {
483
507
void __iomem * enable_base = priv -> regs +
@@ -490,13 +514,6 @@ static int plic_probe(struct platform_device *pdev)
490
514
continue ;
491
515
}
492
516
493
- error = riscv_of_parent_hartid (parent .np , & hartid );
494
- if (error < 0 ) {
495
- dev_warn (dev , "failed to parse hart ID for context %d.\n" , i );
496
- continue ;
497
- }
498
-
499
- cpu = riscv_hartid_to_cpuid (hartid );
500
517
if (cpu < 0 ) {
501
518
dev_warn (dev , "Invalid cpuid for context %d\n" , i );
502
519
continue ;
@@ -534,7 +551,7 @@ static int plic_probe(struct platform_device *pdev)
534
551
handler -> enable_save = devm_kcalloc (dev , DIV_ROUND_UP (nr_irqs , 32 ),
535
552
sizeof (* handler -> enable_save ), GFP_KERNEL );
536
553
if (!handler -> enable_save )
537
- return - ENOMEM ;
554
+ goto fail_cleanup_contexts ;
538
555
done :
539
556
for (hwirq = 1 ; hwirq <= nr_irqs ; hwirq ++ ) {
540
557
plic_toggle (handler , hwirq , 0 );
@@ -547,7 +564,7 @@ static int plic_probe(struct platform_device *pdev)
547
564
priv -> irqdomain = irq_domain_add_linear (to_of_node (dev -> fwnode ), nr_irqs + 1 ,
548
565
& plic_irqdomain_ops , priv );
549
566
if (WARN_ON (!priv -> irqdomain ))
550
- return - ENOMEM ;
567
+ goto fail_cleanup_contexts ;
551
568
552
569
/*
553
570
* We can have multiple PLIC instances so setup cpuhp state
@@ -575,6 +592,22 @@ static int plic_probe(struct platform_device *pdev)
575
592
dev_info (dev , "mapped %d interrupts with %d handlers for %d contexts.\n" ,
576
593
nr_irqs , nr_handlers , nr_contexts );
577
594
return 0 ;
595
+
596
+ fail_cleanup_contexts :
597
+ for (i = 0 ; i < nr_contexts ; i ++ ) {
598
+ if (plic_parse_context_parent (pdev , i , & parent_hwirq , & cpu ))
599
+ continue ;
600
+ if (parent_hwirq != RV_IRQ_EXT || cpu < 0 )
601
+ continue ;
602
+
603
+ handler = per_cpu_ptr (& plic_handlers , cpu );
604
+ handler -> present = false;
605
+ handler -> hart_base = NULL ;
606
+ handler -> enable_base = NULL ;
607
+ handler -> enable_save = NULL ;
608
+ handler -> priv = NULL ;
609
+ }
610
+ return - ENOMEM ;
578
611
}
579
612
580
613
static struct platform_driver plic_driver = {
0 commit comments