diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h index 62d61304..26d1b66b 100644 --- a/include/sbi/sbi_ipi.h +++ b/include/sbi/sbi_ipi.h @@ -23,6 +23,9 @@ struct sbi_ipi_device { /** Name of the IPI device */ char name[32]; + /** Ratings of the IPI device (higher is better) */ + unsigned long rating; + /** Send IPI to a target HART index */ void (*ipi_send)(u32 hart_index); @@ -87,11 +90,11 @@ void sbi_ipi_process(void); int sbi_ipi_raw_send(u32 hartindex); -void sbi_ipi_raw_clear(void); +void sbi_ipi_raw_clear(bool all_devices); const struct sbi_ipi_device *sbi_ipi_get_device(void); -void sbi_ipi_set_device(const struct sbi_ipi_device *dev); +void sbi_ipi_add_device(const struct sbi_ipi_device *dev); int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot); diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 84a63748..663b486b 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -507,7 +507,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid) if (hstate == SBI_HSM_STATE_SUSPENDED) { init_warm_resume(scratch, hartid); } else { - sbi_ipi_raw_clear(); + sbi_ipi_raw_clear(true); init_warm_startup(scratch, hartid); } } diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 2de459b0..93018fe6 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -32,8 +34,14 @@ _Static_assert( "type of sbi_ipi_data.ipi_type has changed, please redefine SBI_IPI_EVENT_MAX" ); +struct sbi_ipi_device_node { + struct sbi_dlist head; + const struct sbi_ipi_device *dev; +}; + static unsigned long ipi_data_off; static const struct sbi_ipi_device *ipi_dev = NULL; +static SBI_LIST_HEAD(ipi_dev_node_list); static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX]; static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex, @@ -248,7 +256,7 @@ void sbi_ipi_process(void) sbi_scratch_offset_ptr(scratch, ipi_data_off); sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD); - sbi_ipi_raw_clear(); + sbi_ipi_raw_clear(false); ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0); ipi_event = 0; @@ -283,10 +291,19 @@ int sbi_ipi_raw_send(u32 hartindex) return 0; } -void sbi_ipi_raw_clear(void) +void sbi_ipi_raw_clear(bool all_devices) { - if (ipi_dev && ipi_dev->ipi_clear) - ipi_dev->ipi_clear(); + struct sbi_ipi_device_node *entry; + + if (all_devices) { + sbi_list_for_each_entry(entry, &ipi_dev_node_list, head) { + if (entry->dev->ipi_clear) + entry->dev->ipi_clear(); + } + } else { + if (ipi_dev && ipi_dev->ipi_clear) + ipi_dev->ipi_clear(); + } /* * Ensure that memory or MMIO writes after this @@ -305,12 +322,22 @@ const struct sbi_ipi_device *sbi_ipi_get_device(void) return ipi_dev; } -void sbi_ipi_set_device(const struct sbi_ipi_device *dev) +void sbi_ipi_add_device(const struct sbi_ipi_device *dev) { - if (!dev || ipi_dev) + struct sbi_ipi_device_node *entry; + + if (!dev) return; - ipi_dev = dev; + entry = sbi_zalloc(sizeof(*entry)); + if (!entry) + return; + SBI_INIT_LIST_HEAD(&entry->head); + entry->dev = dev; + sbi_list_add_tail(&entry->head, &ipi_dev_node_list); + + if (!ipi_dev || ipi_dev->rating < dev->rating) + ipi_dev = dev; } int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot) @@ -347,7 +374,7 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot) ipi_data->ipi_type = 0x00; /* Clear any pending IPIs for the current hart */ - sbi_ipi_raw_clear(); + sbi_ipi_raw_clear(true); /* Enable software interrupts */ csr_set(CSR_MIE, MIP_MSIP); diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c index 9e55078a..d4acacf0 100644 --- a/lib/utils/ipi/aclint_mswi.c +++ b/lib/utils/ipi/aclint_mswi.c @@ -62,6 +62,7 @@ static void mswi_ipi_clear(void) static struct sbi_ipi_device aclint_mswi = { .name = "aclint-mswi", + .rating = 100, .ipi_send = mswi_ipi_send, .ipi_clear = mswi_ipi_clear }; @@ -106,7 +107,7 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi) if (rc) return rc; - sbi_ipi_set_device(&aclint_mswi); + sbi_ipi_add_device(&aclint_mswi); return 0; } diff --git a/lib/utils/ipi/andes_plicsw.c b/lib/utils/ipi/andes_plicsw.c index 5d085d85..3621e3cb 100644 --- a/lib/utils/ipi/andes_plicsw.c +++ b/lib/utils/ipi/andes_plicsw.c @@ -61,6 +61,7 @@ static void plicsw_ipi_clear(void) static struct sbi_ipi_device plicsw_ipi = { .name = "andes_plicsw", + .rating = 200, .ipi_send = plicsw_ipi_send, .ipi_clear = plicsw_ipi_clear }; @@ -99,7 +100,7 @@ int plicsw_cold_ipi_init(struct plicsw_data *plicsw) if (rc) return rc; - sbi_ipi_set_device(&plicsw_ipi); + sbi_ipi_add_device(&plicsw_ipi); return 0; } diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c index 057b9fa7..d72ef794 100644 --- a/lib/utils/irqchip/imsic.c +++ b/lib/utils/irqchip/imsic.c @@ -199,6 +199,7 @@ static void imsic_ipi_send(u32 hart_index) static struct sbi_ipi_device imsic_ipi_device = { .name = "aia-imsic", + .rating = 300, .ipi_send = imsic_ipi_send }; @@ -393,7 +394,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic) sbi_irqchip_add_device(&imsic_device); /* Register IPI device */ - sbi_ipi_set_device(&imsic_ipi_device); + sbi_ipi_add_device(&imsic_ipi_device); return 0; }