/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021 Western Digital Corporation or its affiliates. * Copyright (c) 2022 Ventana Micro Systems Inc. * * Authors: * Anup Patel */ #include #include #include #include #include #include #include static int irqchip_aplic_update_idc_map(const void *fdt, int nodeoff, struct aplic_data *pd) { int i, err, count, cpu_offset, cpu_intc_offset; u32 phandle, hartid, hartindex; const fdt32_t *val; val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count); if (!val || count < sizeof(fdt32_t)) return SBI_EINVAL; count = count / sizeof(fdt32_t); for (i = 0; i < count; i += 2) { phandle = fdt32_to_cpu(val[i]); cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle); if (cpu_intc_offset < 0) continue; cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset); if (cpu_offset < 0) continue; err = fdt_parse_hart_id(fdt, cpu_offset, &hartid); if (err) continue; hartindex = sbi_hartid_to_hartindex(hartid); if (hartindex == -1U) continue; pd->idc_map[i / 2] = hartindex; } return 0; } static int irqchip_aplic_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match) { int rc; struct aplic_data *pd; pd = sbi_zalloc(sizeof(*pd)); if (!pd) return SBI_ENOMEM; rc = fdt_parse_aplic_node(fdt, nodeoff, pd); if (rc) goto fail_free_data; if (pd->num_idc) { pd->idc_map = sbi_zalloc(sizeof(*pd->idc_map) * pd->num_idc); if (!pd->idc_map) { rc = SBI_ENOMEM; goto fail_free_data; } rc = irqchip_aplic_update_idc_map(fdt, nodeoff, pd); if (rc) goto fail_free_idc_map; } rc = aplic_cold_irqchip_init(pd); if (rc) goto fail_free_idc_map; return 0; fail_free_idc_map: if (pd->num_idc) sbi_free(pd->idc_map); fail_free_data: sbi_free(pd); return rc; } static const struct fdt_match irqchip_aplic_match[] = { { .compatible = "riscv,aplic" }, { }, }; const struct fdt_driver fdt_irqchip_aplic = { .match_table = irqchip_aplic_match, .init = irqchip_aplic_cold_init, };