lib: utils: irqchip: implement APLIC hwirq operation hooks
PATCH v2 1/3 lib: utils: irqchip: implement APLIC hwirq operation hooks
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register process_hwirqs() only for the M-mode direct-mode provider.
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)
lib/utils/irqchip/aplic.c +227 -0
@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;
@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic)) + aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc;
Signature · 7 lines
2.25.1 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
PATCH v2 2/3 lib: utils: irqchip: add QEMU virt test for APLIC wired IRQs
From: Raymond Mao <[email protected]>
Add a QEMU virt specific test hook for validating APLIC wired external interrupt handling.
When APLIC_QEMU_WIRED_TEST is enabled, keep the test path limited to hwirq 10 and only register it when the current APLIC instance is the M-mode direct-mode provider and that interrupt is not delegated to a child domain.
This keeps the test path compatible with the generic APLIC changes while still allowing a DT overlay to expose an M-mode wired IRQ on QEMU virt.
--- Makefile | 3 ++ lib/utils/irqchip/aplic.c | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+)
Makefile +3 -0
@@ -399,6 +399,9 @@ CFLAGS += $(GENFLAGS) CFLAGS += $(platform-cflags-y) CFLAGS += -fPIE -pie CFLAGS += $(firmware-cflags-y) +ifeq ($(APLIC_QEMU_WIRED_TEST),y) +CFLAGS += -DAPLIC_QEMU_WIRED_TEST +endif CPPFLAGS += $(GENFLAGS) CPPFLAGS += $(platform-cppflags-y)
lib/utils/irqchip/aplic.c +62 -0
86 lines not on this page · raw message
Signature · 7 lines
2.25.1 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
PATCH v2 3/3 platform: generic: virt: add APLIC M-mode IRQ test overlay
In reply to Raymond MaoFrom: Raymond Mao <[email protected]>
Stock QEMU virt,aia=aplic delegates all wired IRQs from the M-mode APLIC to its child S-mode APLIC, which prevents the local APLIC_QEMU_WIRED_TEST path from exercising M-mode wired IRQ delivery.
Add a DT overlay that changes the M-mode APLIC delegation ranges from 1..96 to 1..9 and 11..96, leaving hwirq 10 local to the M-mode APLIC. This matches the local test path, which uses UART RX on hwirq 10.
The overlay is intended to be applied on top of a base DTB dumped from the same QEMU virt,aia=aplic command line, so the embedded child phandle matches that dumped base DTB.
Usage:
- dump the base DTB from the target QEMU command line
- compile this file as a DT overlay and apply it to the dumped base DTB
- boot QEMU with the merged DTB and APLIC_QEMU_WIRED_TEST=y to verify M-mode wired IRQ delivery
--- .../virt/aplic_mmode_wired_irq_test.dts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 platform/generic/virt/aplic_mmode_wired_irq_test.dts
platform/generic/virt/aplic_mmode_wired_irq_test.dts new file +28 -0
@@ -0,0 +1,28 @@ +/dts-v1/; +/plugin/; + +/ { + fragment@0 { + target-path = "/soc/interrupt-controller@c000000"; + __overlay__ { + /* + * Stock QEMU virt,aia=aplic delegates all wired IRQs from + * the M-mode APLIC to its child S-mode APLIC: + * + * <child-phandle 1 96> + * + * Keep hwirq 10 local to the M-mode APLIC by delegating + * only 1..9 and 11..96 to the child APLIC. This matches + * the local OpenSBI APLIC_QEMU_WIRED_TEST path, which + * exercises wired IRQ delivery via hwirq 10 (UART RX). + * + * This overlay is intended to be applied on top of a base + * DTB dumped from the same QEMU virt,aia=aplic command + * line. The child phandle value below therefore matches + * that dumped base DTB. + */ + riscv,delegate = <0x04 0x01 0x09 0x04 0x0b 0x60>; + riscv,delegation = <0x04 0x01 0x09 0x04 0x0b 0x60>; + }; + }; +};
Signature · 7 lines
2.25.1 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Hi Ray,
Quoted 6 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Quoted 7 lines
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.Signed-off-by Raymond Mao <[email protected]>
Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Regards,
Anup
Quoted 252 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +227
-1@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic)) + aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Hi Anup,
Quoted 16 lines · Anup Patel
Hi Ray,
Quoted 12 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.
Quoted 7 lines
Quoted 1 line
Signed-off-by Raymond Mao <[email protected]>Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Sorry but I didn't find Pawandeep Oza from the CC list.
But anyway, can he rebase on my commit instead of just picking changes from my patch?
Thanks and regards,
Raymond
Quoted 255 lines
Regards,
AnupQuoted 252 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +227
-1@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic)) + aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Hi Raymond,
I have already included and given due credit to you.
Co-developed-by and Signed-off-by "Raymond Mao <[email protected]>" I did look at your patch, and some of the things I have removed, besides this was written also keeping msi in mind as aplic has to incorporate both direct and msi mode - so if you look at later patches they make a way into aplic for msi mode with some irqchip fixes. so I hope that
"Co-developed-by and Signed-off-by" should be sufficient for both of us as it acknowledges your contribution fully here.
Regards,
Oza.
Quoted 295 lines · Raymond Mao
Hi Anup,
Quoted 16 lines · Anup Patel
Hi Ray,
Quoted 12 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.Quoted 7 lines
Quoted 1 line
Signed-off-by Raymond Mao <[email protected]>Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Sorry but I didn't find Pawandeep Oza from the CC list.
But anyway, can he rebase on my commit instead of just picking changes from my patch?Thanks and regards,
RaymondQuoted 247 lines
Regards,
AnupQuoted 244 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +225
-0@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic))Quoted 8 lines
Quoted 8 lines
lib/utils/irqchip/aplic.c +2
-1+ aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
--
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Hi Pawandeep,
Quoted 5 lines · Pawandeep Oza
Hi Raymond,
I have already included and given due credit to you.
Quoted 9 lines
Co-developed-by and Signed-off-by "Raymond Mao <[email protected]>" I did look at your patch, and some of the things I have removed, besides this was written also keeping msi in mind as aplic has to incorporate both direct and msi mode - so if you look at later patches they make a way into aplic for msi mode with some irqchip fixes. so I hope that
"Co-developed-by and Signed-off-by" should be sufficient for both of us as it acknowledges your contribution fully here.
Thanks for letting me know. I have follow-up VIRQ patches now pending for merging, which is based on my APLIC one.
That is why I was asking, to make sure that I still can rebase the VIRQ on it. For credits, what you mentioned sounds good to me.
Thanks and regards,
Raymond
Quoted 299 lines
Regards,
Oza.Quoted 295 lines · Raymond Mao
Hi Anup,
Quoted 16 lines · Anup Patel
Hi Ray,
Quoted 12 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.Quoted 7 lines
Quoted 1 line
Signed-off-by Raymond Mao <[email protected]>Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Sorry but I didn't find Pawandeep Oza from the CC list.
But anyway, can he rebase on my commit instead of just picking changes from my patch?Thanks and regards,
RaymondQuoted 247 lines
Regards,
AnupQuoted 244 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +225
-0@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic))Quoted 8 lines
Quoted 8 lines
lib/utils/irqchip/aplic.c +2
-1+ aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
--
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Since this is larger series, we both should be able to agree if you could rebase the virq patch on top of this series.
By the way, have you already posted the patch or yet to post it ?
Regards,
Oza.
Quoted 328 lines · Raymond Mao
Hi Pawandeep,
Quoted 5 lines · Pawandeep Oza
Hi Raymond,
I have already included and given due credit to you.
Quoted 9 lines
Co-developed-by and Signed-off-by "Raymond Mao <[email protected]>" I did look at your patch, and some of the things I have removed, besides this was written also keeping msi in mind as aplic has to incorporate both direct and msi mode - so if you look at later patches they make a way into aplic for msi mode with some irqchip fixes. so I hope that
"Co-developed-by and Signed-off-by" should be sufficient for both of us as it acknowledges your contribution fully here.Thanks for letting me know. I have follow-up VIRQ patches now pending for merging, which is based on my APLIC one.
That is why I was asking, to make sure that I still can rebase the VIRQ on it. For credits, what you mentioned sounds good to me.Thanks and regards,
RaymondQuoted 299 lines
Regards,
Oza.Quoted 295 lines · Raymond Mao
Hi Anup,
Quoted 16 lines · Anup Patel
Hi Ray,
Quoted 12 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.Quoted 7 lines
Quoted 1 line
Signed-off-by Raymond Mao <[email protected]>Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Sorry but I didn't find Pawandeep Oza from the CC list.
But anyway, can he rebase on my commit instead of just picking changes from my patch?Thanks and regards,
RaymondQuoted 247 lines
Regards,
AnupQuoted 244 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +225
-0@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic))Quoted 8 lines
Quoted 8 lines
lib/utils/irqchip/aplic.c +2
-1+ aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
--
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi
Hi Pawandeep,
Quoted 5 lines · Pawandeep Oza
Since this is larger series, we both should be able to agree if you could rebase the virq patch on top of this series.
By the way, have you already posted the patch or yet to post it ?
They were already posted at:
https://lore.kernel.org/opensbi/[email protected]/
Raymond
Quoted 332 lines
Regards,
Oza.Quoted 328 lines · Raymond Mao
Hi Pawandeep,
Quoted 5 lines · Pawandeep Oza
Hi Raymond,
I have already included and given due credit to you.
Quoted 9 lines
Co-developed-by and Signed-off-by "Raymond Mao <[email protected]>" I did look at your patch, and some of the things I have removed, besides this was written also keeping msi in mind as aplic has to incorporate both direct and msi mode - so if you look at later patches they make a way into aplic for msi mode with some irqchip fixes. so I hope that
"Co-developed-by and Signed-off-by" should be sufficient for both of us as it acknowledges your contribution fully here.Thanks for letting me know. I have follow-up VIRQ patches now pending for merging, which is based on my APLIC one.
That is why I was asking, to make sure that I still can rebase the VIRQ on it. For credits, what you mentioned sounds good to me.Thanks and regards,
RaymondQuoted 299 lines
Regards,
Oza.Quoted 295 lines · Raymond Mao
Hi Anup,
Quoted 16 lines · Anup Patel
Hi Ray,
Quoted 12 lines · Raymond Mao
From: Raymond Mao <[email protected]>
Implement the APLIC hardware interrupt hooks used by the generic irqchip framework for M-mode direct-mode wired interrupts.
Program a minimal APLIC direct-mode configuration during hwirq setup and claim external interrupts via IDC.CLAIMI. Add the helper logic needed to derive the source ID from CLAIMI, map hart index to IDC index, skip delegated interrupts, and register
process_hwirqs()only for the M-mode direct-mode provider.Quoted 7 lines
Quoted 1 line
Signed-off-by Raymond Mao <[email protected]>Pawandeep Oza (CC'ed) has developed functionally complete IMSIC and APLIC drivers for OpenSBI which supports both MSI-mode and Direct-mode of APLIC. He did include some of your changes from this patch. He will send-out his series pretty soon so stay tuned.
Sorry but I didn't find Pawandeep Oza from the CC list.
But anyway, can he rebase on my commit instead of just picking changes from my patch?Thanks and regards,
RaymondQuoted 247 lines
Regards,
AnupQuoted 244 lines
--- lib/utils/irqchip/aplic.c | 227 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+)lib/utils/irqchip/aplic.c +225
-0@@ -245,6 +245,220 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)return 0 ; } +static inline void *aplic_idc_base (unsigned long aplic_addr,u32 idc_index) +{ +return (void *)(aplic_addr +APLIC_IDC_BASE + + (unsigned long )idc_index *APLIC_IDC_SIZE ); +} + +static inline struct aplic_data *aplic_irqchip_to_data (struct sbi_irqchip_device *chip) +{ + return container_of(chip, struct aplic_data, irqchip); +} + +static bool aplic_hwirq_delegated (const struct aplic_data *aplic,u32 hwirq) +{ +u32 i; + +for (i =0 ; i <APLIC_MAX_DELEGATE ; i++) { +const struct aplic_delegate_data *deleg = &aplic->delegate[i]; + +if (!deleg->first_irq || !deleg->last_irq) +continue ; +if (deleg->first_irq <= hwirq && hwirq <= deleg->last_irq) +return true; + } + +return false; +} + +static bool aplic_mmode_direct (const struct aplic_data *aplic) +{ +return aplic->targets_mmode && aplic->num_idc; +} + +static int aplic_hartindex_to_idc_index (const struct aplic_data *aplic, +u32 hartindex) +{ +u32 i; + +if (!aplic->num_idc) +return SBI_ENODEV ; + +if (aplic->idc_map) { +for (i =0 ; i < aplic->num_idc; i++) { +if (aplic->idc_map[i] == hartindex) +return i; + } + +return SBI_ENODEV ; + } + +if (hartindex < aplic->num_idc) +return hartindex; + +return SBI_ENODEV ; +} + +static int aplic_hwirq_target_idc_index (struct sbi_irqchip_device *chip) +{ +u32 hartindex =current_hartindex (); + +if (!sbi_hartmask_test_hartindex (hartindex, &chip->target_harts)) { +sbi_hartmask_for_each_hartindex (hartindex, &chip->target_harts) +break ; +if (hartindex >=SBI_HARTMASK_MAX_BITS ) +return SBI_ENODEV ; + } + +return aplic_hartindex_to_idc_index (aplic_irqchip_to_data (chip), + hartindex); +} + +static u32 aplic_domaincfg_value (void ) +{ +u32 val =APLIC_DOMAINCFG_IE ; + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val |=APLIC_DOMAINCFG_BE ; +#endif + +return val; +} + +static void aplic_hwirq_mask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Disable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_CLRIENUM )); +} + +static void aplic_hwirq_unmask (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); + +if (!hwirq ||aplic_hwirq_delegated (aplic, hwirq)) +return ; + +if (!aplic->addr || hwirq > aplic->num_source) +return ; + +/* Enable source */ +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); +} + +static int aplic_hwirq_claim (struct sbi_irqchip_device *chip,u32 *hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +int idc_index; +void *idc; +u32 v, id; + +if (!hwirq) +return SBI_EINVAL ; + + idc_index =aplic_hartindex_to_idc_index (aplic,current_hartindex ()); +if (!aplic->addr || idc_index <0 ) +return SBI_ENODEV ; + + idc =aplic_idc_base (aplic->addr, idc_index); + +/* +* Read CLAIMI: returns TOPI value. +* ID==0 means spurious interrupt (spec-defined). +*/ + v =readl (idc +APLIC_IDC_CLAIMI );/* dequeue */ + + id = (v >>APLIC_IDC_TOPI_ID_SHIFT ) &APLIC_IDC_TOPI_ID_MASK ; + +/* ID==0 means spurious / no pending wired interrupt */ +if (!id) +return SBI_ENOENT ; + +/* Bound check against DT-discovered num_src */ +if (id > aplic->num_source) +return SBI_EINVAL ; + + *hwirq = id; + +return SBI_OK ; +} + +static int aplic_hwirq_setup (struct sbi_irqchip_device *chip,u32 hwirq) +{ +struct aplic_data *aplic =aplic_irqchip_to_data (chip); +unsigned long idc; +int idc_index; + +if (!hwirq || hwirq > aplic->num_source) +return SBI_EINVAL ; +if (!aplic_mmode_direct (aplic)) +return SBI_ENOTSUPP ; +if (aplic_hwirq_delegated (aplic, hwirq)) +return SBI_ENOTSUPP ; + + idc_index =aplic_hwirq_target_idc_index (chip); +if (idc_index <0 ) +return idc_index; + + idc = aplic->addr +APLIC_IDC_BASE + idc_index *APLIC_IDC_SIZE ; + +/* APLIC: sourcecfg/target/enable */ +writel (APLIC_SOURCECFG_SM_LEVEL_HIGH , + (void *)(aplic->addr +APLIC_SOURCECFG_BASE + (hwirq -1 ) *4 )); + +writel (((u32 )idc_index <<APLIC_TARGET_HART_IDX_SHIFT ) | +APLIC_DEFAULT_PRIORITY , + (void *)(aplic->addr +APLIC_TARGET_BASE + (hwirq -1 ) *4 )); + +writel (hwirq, (void *)(aplic->addr +APLIC_SETIENUM )); + +/* Direct mode for aia=aplic: DM=0 => don't set DM bit */ +writel (aplic_domaincfg_value (), (void *)(aplic->addr +APLIC_DOMAINCFG )); + +/* IDC delivery */ +writel (APLIC_ENABLE_IDELIVERY , (void *)(idc +APLIC_IDC_IDELIVERY )); +writel (APLIC_ENABLE_ITHRESHOLD , (void *)(idc +APLIC_IDC_ITHRESHOLD )); + +return SBI_OK ; +} + +static int aplic_process_hwirqs (struct sbi_irqchip_device *chip) +{ +if (!chip) +return SBI_ENODEV ; + +for (;;) { +u32 hwirq =0 ; +int rc =aplic_hwirq_claim (chip, &hwirq); + +if (rc ==SBI_ENOENT ) +break ; +if (rc) +return rc; + +if (!hwirq) +break ; + +if (hwirq > chip->num_hwirq) { +return SBI_EINVAL ; + } + + rc =sbi_irqchip_process_hwirq (chip, hwirq); +if (rc) +return rc; + } + +return SBI_OK ; +} +int aplic_cold_irqchip_init (struct aplic_data *aplic) {int rc;@@ -308,6 +522,19 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)/* Register irqchip device */ aplic->irqchip.id = aplic->unique_id; aplic->irqchip.num_hwirq = aplic->num_source +1 ; + aplic->irqchip.hwirq_mask = aplic_hwirq_mask; + aplic->irqchip.hwirq_unmask = aplic_hwirq_unmask; +/* +* Only the domain that directly injects interrupts into M-mode external +* interrupt line should provide process_hwirqs(). +* +* The other domain (e.g. S-mode) may still be registered so that its +* other ops (mask/unmask/config/etc.) can be used, but it must not +* claim to be the external interrupt line provider. +*/ +if (aplic_mmode_direct (aplic))Quoted 8 lines
Quoted 8 lines
lib/utils/irqchip/aplic.c +2
-1+ aplic->irqchip.process_hwirqs = aplic_process_hwirqs; + aplic->irqchip.hwirq_setup = aplic_hwirq_setup; rc =sbi_irqchip_add_device (&aplic->irqchip);if (rc)return rc; --2.25.1
--
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
Signature · 3 lines
opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi