aboutsummaryrefslogtreecommitdiff
path: root/lib/utils
diff options
context:
space:
mode:
authorInochi Amaoto <inochiama@gmail.com>2025-05-23 16:53:48 +0800
committerAnup Patel <anup@brainfault.org>2025-06-16 09:17:28 +0530
commit6f8bcae4cb12d92e0c198ba3b7e2f56e2fbb7289 (patch)
treec6c8bc357563ab5695c0ba528de3f2eeee2894ca /lib/utils
parent771c656181c360ed351a4a96a3e25102cbc140b9 (diff)
downloadopensbi-6f8bcae4cb12d92e0c198ba3b7e2f56e2fbb7289.zip
opensbi-6f8bcae4cb12d92e0c198ba3b7e2f56e2fbb7289.tar.gz
opensbi-6f8bcae4cb12d92e0c198ba3b7e2f56e2fbb7289.tar.bz2
lib: utils/irqchip: always parse msi information for each aplic device
OpenSBI only parses MSI information of the first next level subdomain for now, which makes the root domain misconfigured in some case: 1. the msi is not enabled on the first subdomain of the root domain, but other subdomains enable MSI. 2. the root domain is set as direct mode, but its subdomains enable MSI. So it is needed to parse all child of the root domain, Otherwise, the some non-root domains are broken. As the specification says, it is safe to parse the MSI information of all its subdomain and write the msiaddrcfg register of the non root domain as they are read only. Parse the aplic MSI information recursively for all aplic device. Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Inochi Amaoto <inochiama@gmail.com> Link: https://lore.kernel.org/r/20250523085348.1690368-1-inochiama@gmail.com Signed-off-by: Anup Patel <anup@brainfault.org>
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/fdt/fdt_helper.c140
1 files changed, 71 insertions, 69 deletions
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index b2d91fd..af148fe 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -607,13 +607,59 @@ int fdt_parse_xlnx_uartlite_node(const void *fdt, int nodeoffset,
return fdt_parse_uart_node_common(fdt, nodeoffset, uart, 0, 0);
}
+static int fdt_aplic_find_imsic_node(const void *fdt, int nodeoff,
+ struct imsic_data *imsic, bool mmode)
+{
+ const fdt32_t *val;
+ int i, len, noff, rc;
+
+ val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
+ if (val && len >= sizeof(fdt32_t)) {
+ noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
+ if (noff < 0)
+ return noff;
+
+ rc = fdt_parse_imsic_node(fdt, noff, imsic);
+ if (rc)
+ return rc;
+
+ rc = imsic_data_check(imsic);
+ if (rc)
+ return rc;
+
+ if (imsic->targets_mmode == mmode) {
+ return 0;
+ }
+ } else {
+ return SBI_ENODEV;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
+ if (!val || len < sizeof(fdt32_t))
+ return SBI_ENODEV;
+
+ len /= sizeof(fdt32_t);
+
+ for (i = 0; i < len; i++) {
+ noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[i]));
+ if (noff < 0)
+ return noff;
+
+ rc = fdt_aplic_find_imsic_node(fdt, noff, imsic, mmode);
+ if (!rc)
+ break;
+ }
+
+ return rc;
+}
+
int fdt_parse_aplic_node(const void *fdt, int nodeoff, struct aplic_data *aplic)
{
bool child_found;
const fdt32_t *val;
const fdt32_t *del;
struct imsic_data imsic = { 0 };
- int i, j, d, dcnt, len, noff, rc;
+ int i, j, d, dcnt, len, rc;
uint64_t reg_addr, reg_size;
struct aplic_delegate_data *deleg;
@@ -640,78 +686,34 @@ int fdt_parse_aplic_node(const void *fdt, int nodeoff, struct aplic_data *aplic)
}
}
aplic->num_idc = len / 2;
- goto aplic_msi_parent_done;
}
- val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
- if (val && len >= sizeof(fdt32_t)) {
- noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
- if (noff < 0)
- return noff;
-
- rc = fdt_parse_imsic_node(fdt, noff, &imsic);
- if (rc)
- return rc;
-
- rc = imsic_data_check(&imsic);
- if (rc)
- return rc;
-
- aplic->targets_mmode = imsic.targets_mmode;
-
- if (imsic.targets_mmode) {
- aplic->has_msicfg_mmode = true;
- aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
- aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
- aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
- aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
- if (aplic->msicfg_mmode.hhxs <
- (2 * IMSIC_MMIO_PAGE_SHIFT))
- return SBI_EINVAL;
- aplic->msicfg_mmode.hhxs -= 24;
- aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
- } else {
- goto aplic_msi_parent_done;
- }
-
- val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
- if (!val || len < sizeof(fdt32_t))
- goto aplic_msi_parent_done;
-
- noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
- if (noff < 0)
- return noff;
-
- val = fdt_getprop(fdt, noff, "msi-parent", &len);
- if (!val || len < sizeof(fdt32_t))
- goto aplic_msi_parent_done;
-
- noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
- if (noff < 0)
- return noff;
-
- rc = fdt_parse_imsic_node(fdt, noff, &imsic);
- if (rc)
- return rc;
-
- rc = imsic_data_check(&imsic);
- if (rc)
- return rc;
+ rc = fdt_aplic_find_imsic_node(fdt, nodeoff, &imsic, true);
+ if (!rc) {
+ aplic->targets_mmode = true;
+ aplic->has_msicfg_mmode = true;
+ aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
+ aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
+ aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
+ aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
+ if (aplic->msicfg_mmode.hhxs < (2 * IMSIC_MMIO_PAGE_SHIFT))
+ return SBI_EINVAL;
+ aplic->msicfg_mmode.hhxs -= 24;
+ aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
+ }
- if (!imsic.targets_mmode) {
- aplic->has_msicfg_smode = true;
- aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
- aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
- aplic->msicfg_smode.hhxw = imsic.group_index_bits;
- aplic->msicfg_smode.hhxs = imsic.group_index_shift;
- if (aplic->msicfg_smode.hhxs <
- (2 * IMSIC_MMIO_PAGE_SHIFT))
- return SBI_EINVAL;
- aplic->msicfg_smode.hhxs -= 24;
- aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
- }
+ rc = fdt_aplic_find_imsic_node(fdt, nodeoff, &imsic, false);
+ if (!rc) {
+ aplic->has_msicfg_smode = true;
+ aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
+ aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
+ aplic->msicfg_smode.hhxw = imsic.group_index_bits;
+ aplic->msicfg_smode.hhxs = imsic.group_index_shift;
+ if (aplic->msicfg_smode.hhxs < (2 * IMSIC_MMIO_PAGE_SHIFT))
+ return SBI_EINVAL;
+ aplic->msicfg_smode.hhxs -= 24;
+ aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
}
-aplic_msi_parent_done:
for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
deleg = &aplic->delegate[d];