@@ -417,17 +417,45 @@ static const struct of_device_id plic_match[] = {
417417 {}
418418};
419419
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+
420448static int plic_probe (struct platform_device * pdev )
421449{
422- int error = 0 , nr_contexts , nr_handlers = 0 , i ;
450+ int error = 0 , nr_contexts , nr_handlers = 0 , cpu , i ;
423451 struct device * dev = & pdev -> dev ;
424452 unsigned long plic_quirks = 0 ;
425453 struct plic_handler * handler ;
454+ u32 nr_irqs , parent_hwirq ;
426455 struct irq_domain * domain ;
427456 struct plic_priv * priv ;
457+ irq_hw_number_t hwirq ;
428458 bool cpuhp_setup ;
429- unsigned int cpu ;
430- u32 nr_irqs ;
431459
432460 if (is_of_node (dev -> fwnode )) {
433461 const struct of_device_id * id ;
@@ -463,21 +491,17 @@ static int plic_probe(struct platform_device *pdev)
463491 return - EINVAL ;
464492
465493 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 );
473497 continue ;
474498 }
475499
476500 /*
477501 * Skip contexts other than external interrupts for our
478502 * privilege level.
479503 */
480- if (parent . args [ 0 ] != RV_IRQ_EXT ) {
504+ if (parent_hwirq != RV_IRQ_EXT ) {
481505 /* Disable S-mode enable bits if running in M-mode. */
482506 if (IS_ENABLED (CONFIG_RISCV_M_MODE )) {
483507 void __iomem * enable_base = priv -> regs +
@@ -490,13 +514,6 @@ static int plic_probe(struct platform_device *pdev)
490514 continue ;
491515 }
492516
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 );
500517 if (cpu < 0 ) {
501518 dev_warn (dev , "Invalid cpuid for context %d\n" , i );
502519 continue ;
@@ -534,7 +551,7 @@ static int plic_probe(struct platform_device *pdev)
534551 handler -> enable_save = devm_kcalloc (dev , DIV_ROUND_UP (nr_irqs , 32 ),
535552 sizeof (* handler -> enable_save ), GFP_KERNEL );
536553 if (!handler -> enable_save )
537- return - ENOMEM ;
554+ goto fail_cleanup_contexts ;
538555done :
539556 for (hwirq = 1 ; hwirq <= nr_irqs ; hwirq ++ ) {
540557 plic_toggle (handler , hwirq , 0 );
@@ -547,7 +564,7 @@ static int plic_probe(struct platform_device *pdev)
547564 priv -> irqdomain = irq_domain_add_linear (to_of_node (dev -> fwnode ), nr_irqs + 1 ,
548565 & plic_irqdomain_ops , priv );
549566 if (WARN_ON (!priv -> irqdomain ))
550- return - ENOMEM ;
567+ goto fail_cleanup_contexts ;
551568
552569 /*
553570 * We can have multiple PLIC instances so setup cpuhp state
@@ -575,6 +592,22 @@ static int plic_probe(struct platform_device *pdev)
575592 dev_info (dev , "mapped %d interrupts with %d handlers for %d contexts.\n" ,
576593 nr_irqs , nr_handlers , nr_contexts );
577594 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 ;
578611}
579612
580613static struct platform_driver plic_driver = {
0 commit comments