diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h index e31f48a4..cbfcd3fd 100644 --- a/include/sbi_utils/irqchip/aplic.h +++ b/include/sbi_utils/irqchip/aplic.h @@ -33,6 +33,7 @@ struct aplic_delegate_data { struct aplic_data { /* Private members */ struct sbi_irqchip_device irqchip; + struct sbi_dlist node; /* Public members */ unsigned long addr; unsigned long size; @@ -48,4 +49,6 @@ struct aplic_data { int aplic_cold_irqchip_init(struct aplic_data *aplic); +void aplic_reinit_all(void); + #endif diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c index efaaf0ca..8d0db168 100644 --- a/lib/utils/irqchip/aplic.c +++ b/lib/utils/irqchip/aplic.c @@ -115,6 +115,90 @@ #define APLIC_DISABLE_ITHRESHOLD 1 #define APLIC_ENABLE_ITHRESHOLD 0 +static SBI_LIST_HEAD(aplic_list); +static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg, + void *msicfgaddr, void *msicfgaddrH); + +static void aplic_init(struct aplic_data *aplic) +{ + struct aplic_delegate_data *deleg; + u32 i, j, tmp; + int locked; + + /* Set domain configuration to 0 */ + writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG)); + + /* Disable all interrupts */ + for (i = 0; i <= aplic->num_source; i += 32) + writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE + + (i / 32) * sizeof(u32))); + + /* Set interrupt type and priority for all interrupts */ + for (i = 1; i <= aplic->num_source; i++) { + /* Set IRQ source configuration to 0 */ + writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE + + (i - 1) * sizeof(u32))); + /* Set IRQ target hart index and priority to 1 */ + writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr + + APLIC_TARGET_BASE + + (i - 1) * sizeof(u32))); + } + + /* Configure IRQ delegation */ + for (i = 0; i < APLIC_MAX_DELEGATE; i++) { + deleg = &aplic->delegate[i]; + if (!deleg->first_irq || !deleg->last_irq) + continue; + if (aplic->num_source < deleg->first_irq || + aplic->num_source < deleg->last_irq) + continue; + if (deleg->child_index > APLIC_SOURCECFG_CHILDIDX_MASK) + continue; + if (deleg->first_irq > deleg->last_irq) { + tmp = deleg->first_irq; + deleg->first_irq = deleg->last_irq; + deleg->last_irq = tmp; + } + for (j = deleg->first_irq; j <= deleg->last_irq; j++) + writel(APLIC_SOURCECFG_D | deleg->child_index, + (void *)(aplic->addr + APLIC_SOURCECFG_BASE + + (j - 1) * sizeof(u32))); + } + + /* Default initialization of IDC structures */ + for (i = 0; i < aplic->num_idc; i++) { + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE + + i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY)); + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE + + i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE)); + writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr + + APLIC_IDC_BASE + + (i * APLIC_IDC_SIZE) + + APLIC_IDC_ITHRESHOLD)); + } + + /* MSI configuration */ + locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L; + if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) { + aplic_writel_msicfg(&aplic->msicfg_mmode, + (void *)(aplic->addr + APLIC_MMSICFGADDR), + (void *)(aplic->addr + APLIC_MMSICFGADDRH)); + } + if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) { + aplic_writel_msicfg(&aplic->msicfg_smode, + (void *)(aplic->addr + APLIC_SMSICFGADDR), + (void *)(aplic->addr + APLIC_SMSICFGADDRH)); + } +} + +void aplic_reinit_all(void) +{ + struct aplic_data *aplic; + + sbi_list_for_each_entry(aplic, &aplic_list, node) + aplic_init(aplic); +} + static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg, void *msicfgaddr, void *msicfgaddrH) { @@ -163,10 +247,9 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg) int aplic_cold_irqchip_init(struct aplic_data *aplic) { - int rc, locked; - u32 i, j, tmp; + int rc; struct aplic_delegate_data *deleg; - u32 first_deleg_irq, last_deleg_irq; + u32 first_deleg_irq, last_deleg_irq, i; /* Sanity checks */ if (!aplic || @@ -184,82 +267,24 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic) return rc; } - /* Set domain configuration to 0 */ - writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG)); - - /* Disable all interrupts */ - for (i = 0; i <= aplic->num_source; i += 32) - writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE + - (i / 32) * sizeof(u32))); - - /* Set interrupt type and priority for all interrupts */ - for (i = 1; i <= aplic->num_source; i++) { - /* Set IRQ source configuration to 0 */ - writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE + - (i - 1) * sizeof(u32))); - /* Set IRQ target hart index and priority to 1 */ - writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr + - APLIC_TARGET_BASE + - (i - 1) * sizeof(u32))); - } - - /* Configure IRQ delegation */ - first_deleg_irq = -1U; - last_deleg_irq = 0; - for (i = 0; i < APLIC_MAX_DELEGATE; i++) { - deleg = &aplic->delegate[i]; - if (!deleg->first_irq || !deleg->last_irq) - continue; - if (aplic->num_source < deleg->first_irq || - aplic->num_source < deleg->last_irq) - continue; - if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index) - continue; - if (deleg->first_irq > deleg->last_irq) { - tmp = deleg->first_irq; - deleg->first_irq = deleg->last_irq; - deleg->last_irq = tmp; - } - if (deleg->first_irq < first_deleg_irq) - first_deleg_irq = deleg->first_irq; - if (last_deleg_irq < deleg->last_irq) - last_deleg_irq = deleg->last_irq; - for (j = deleg->first_irq; j <= deleg->last_irq; j++) - writel(APLIC_SOURCECFG_D | deleg->child_index, - (void *)(aplic->addr + APLIC_SOURCECFG_BASE + - (j - 1) * sizeof(u32))); - } - - /* Default initialization of IDC structures */ - for (i = 0; i < aplic->num_idc; i++) { - writel(0, (void *)(aplic->addr + APLIC_IDC_BASE + - i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY)); - writel(0, (void *)(aplic->addr + APLIC_IDC_BASE + - i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE)); - writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr + - APLIC_IDC_BASE + - (i * APLIC_IDC_SIZE) + - APLIC_IDC_ITHRESHOLD)); - } - - /* MSI configuration */ - locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L; - if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) { - aplic_writel_msicfg(&aplic->msicfg_mmode, - (void *)(aplic->addr + APLIC_MMSICFGADDR), - (void *)(aplic->addr + APLIC_MMSICFGADDRH)); - } - if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) { - aplic_writel_msicfg(&aplic->msicfg_smode, - (void *)(aplic->addr + APLIC_SMSICFGADDR), - (void *)(aplic->addr + APLIC_SMSICFGADDRH)); - } + /* Init the APLIC registers */ + aplic_init(aplic); /* * Add APLIC region to the root domain if: * 1) It targets M-mode of any HART directly or via MSIs * 2) All interrupts are delegated to some child APLIC */ + first_deleg_irq = -1U; + last_deleg_irq = 0; + for (i = 0; i < APLIC_MAX_DELEGATE; i++) { + deleg = &aplic->delegate[i]; + if (deleg->first_irq < first_deleg_irq) + first_deleg_irq = deleg->first_irq; + if (last_deleg_irq < deleg->last_irq) + last_deleg_irq = deleg->last_irq; + } + if (aplic->targets_mmode || ((first_deleg_irq < last_deleg_irq) && (last_deleg_irq == aplic->num_source) && @@ -275,5 +300,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic) /* Register irqchip device */ sbi_irqchip_add_device(&aplic->irqchip); + /* Attach to the aplic list */ + sbi_list_add_tail(&aplic->node, &aplic_list); + return 0; }