From 5f762d14f0473dec97ee248e53d29b78be8a833e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 15 Jan 2020 12:44:10 +0530 Subject: lib: Introduce sbi_ipi_event_create/destroy() APIs This patch introduces sbi_ipi_event_create/destroy() APIs and struct sbi_ipi_event_ops for creating/destroying IPI events at runtime based of event operations. This new APIs will help platform code and utils code to create custom IPI events which are not part of generic OpenSBI library. Signed-off-by: Anup Patel Reviewed-by: Atish Patra --- lib/sbi/sbi_ipi.c | 113 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 27 deletions(-) (limited to 'lib/sbi/sbi_ipi.c') diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 68c3584..42868c5 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -26,34 +26,43 @@ struct sbi_ipi_data { static unsigned long ipi_data_off; -static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event, - void *data) +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_hartid, + u32 event, void *data) { int ret; struct sbi_scratch *remote_scratch = NULL; const struct sbi_platform *plat = sbi_platform_ptr(scratch); struct sbi_ipi_data *ipi_data; + const struct sbi_ipi_event_ops *ipi_ops; - if (sbi_platform_hart_disabled(plat, hartid)) - return -1; + if ((SBI_IPI_EVENT_MAX <= event) || + !ipi_ops_array[event] || + sbi_platform_hart_disabled(plat, remote_hartid)) + return SBI_EINVAL; + ipi_ops = ipi_ops_array[event]; /* * Set IPI type on remote hart's scratch area and * trigger the interrupt */ - remote_scratch = sbi_hart_id_to_scratch(scratch, hartid); + remote_scratch = sbi_hart_id_to_scratch(scratch, remote_hartid); ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off); - if (event == SBI_IPI_EVENT_FENCE) { - ret = sbi_tlb_fifo_update(remote_scratch, hartid, data); + + if (ipi_ops->update) { + ret = ipi_ops->update(scratch, remote_scratch, + remote_hartid, data); if (ret < 0) return ret; } + atomic_raw_set_bit(event, &ipi_data->ipi_type); smp_wmb(); - sbi_platform_ipi_send(plat, hartid); + sbi_platform_ipi_send(plat, remote_hartid); - if (event == SBI_IPI_EVENT_FENCE) - sbi_tlb_fifo_sync(scratch); + if (ipi_ops->sync) + ipi_ops->sync(scratch); return 0; } @@ -101,10 +110,47 @@ int sbi_ipi_send_many(struct sbi_scratch *scratch, ulong hmask, ulong hbase, return 0; } +int sbi_ipi_event_create(const struct sbi_ipi_event_ops *ops) +{ + int i, ret = SBI_ENOSPC; + + if (!ops || !ops->process) + return SBI_EINVAL; + + for (i = 0; i < SBI_IPI_EVENT_MAX; i++) { + if (!ipi_ops_array[i]) { + ret = i; + ipi_ops_array[i] = ops; + break; + } + } + + return ret; +} + +void sbi_ipi_event_destroy(u32 event) +{ + if (SBI_IPI_EVENT_MAX <= event) + return; + + ipi_ops_array[event] = NULL; +} + +static void sbi_ipi_process_smode(struct sbi_scratch *scratch) +{ + csr_set(CSR_MIP, MIP_SSIP); +} + +static struct sbi_ipi_event_ops ipi_smode_ops = { + .name = "IPI_SMODE", + .process = sbi_ipi_process_smode, +}; + +static u32 ipi_smode_event = SBI_IPI_EVENT_MAX; + int sbi_ipi_send_smode(struct sbi_scratch *scratch, ulong hmask, ulong hbase) { - return sbi_ipi_send_many(scratch, hmask, hbase, - SBI_IPI_EVENT_SOFT, NULL); + return sbi_ipi_send_many(scratch, hmask, hbase, ipi_smode_event, NULL); } void sbi_ipi_clear_smode(struct sbi_scratch *scratch) @@ -112,16 +158,28 @@ void sbi_ipi_clear_smode(struct sbi_scratch *scratch) csr_clear(CSR_MIP, MIP_SSIP); } +static void sbi_ipi_process_halt(struct sbi_scratch *scratch) +{ + sbi_exit(scratch); +} + +static struct sbi_ipi_event_ops ipi_halt_ops = { + .name = "IPI_HALT", + .process = sbi_ipi_process_halt, +}; + +static u32 ipi_halt_event = SBI_IPI_EVENT_MAX; + int sbi_ipi_send_halt(struct sbi_scratch *scratch, ulong hmask, ulong hbase) { - return sbi_ipi_send_many(scratch, hmask, hbase, - SBI_IPI_EVENT_HALT, NULL); + return sbi_ipi_send_many(scratch, hmask, hbase, ipi_halt_event, NULL); } void sbi_ipi_process(struct sbi_scratch *scratch) { unsigned long ipi_type; unsigned int ipi_event; + const struct sbi_ipi_event_ops *ipi_ops; const struct sbi_platform *plat = sbi_platform_ptr(scratch); struct sbi_ipi_data *ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off); @@ -135,19 +193,9 @@ void sbi_ipi_process(struct sbi_scratch *scratch) if (!(ipi_type & 1UL)) goto skip; - switch (ipi_event) { - case SBI_IPI_EVENT_SOFT: - csr_set(CSR_MIP, MIP_SSIP); - break; - case SBI_IPI_EVENT_FENCE: - sbi_tlb_fifo_process(scratch); - break; - case SBI_IPI_EVENT_HALT: - sbi_exit(scratch); - break; - default: - break; - }; + ipi_ops = ipi_ops_array[ipi_event]; + if (ipi_ops && ipi_ops->process) + ipi_ops->process(scratch); skip: ipi_type = ipi_type >> 1; @@ -165,9 +213,20 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot) "IPI_DATA"); if (!ipi_data_off) return SBI_ENOMEM; + ret = sbi_ipi_event_create(&ipi_smode_ops); + if (ret < 0) + return ret; + ipi_smode_event = ret; + ret = sbi_ipi_event_create(&ipi_halt_ops); + if (ret < 0) + return ret; + ipi_halt_event = ret; } else { if (!ipi_data_off) return SBI_ENOMEM; + if (SBI_IPI_EVENT_MAX <= ipi_smode_event || + SBI_IPI_EVENT_MAX <= ipi_halt_event) + return SBI_ENOSPC; } ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off); -- cgit v1.2.3