mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-05-23 14:21:32 +01:00
lib: sbi_irqchip: Add support for registering MSI handlers
Some of the drivers (such as APLIC) require capability to registers MSI handlers from the parent interrupt controller (such as IMSIC) so add sbi_irqchip_register_msi_handler() for this purpose. Link: https://lore.kernel.org/r/20260423052339.356900-7-anup.patel@oss.qualcomm.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -16,6 +16,13 @@
|
|||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
|
|
||||||
|
/** irqchip message signalled interrupt (MSI) */
|
||||||
|
struct sbi_irqchip_msi_msg {
|
||||||
|
u32 address_lo;
|
||||||
|
u32 address_hi;
|
||||||
|
u32 data;
|
||||||
|
};
|
||||||
|
|
||||||
/** irqchip hardware device */
|
/** irqchip hardware device */
|
||||||
struct sbi_irqchip_device {
|
struct sbi_irqchip_device {
|
||||||
/** Node in the list of irqchip devices (private) */
|
/** Node in the list of irqchip devices (private) */
|
||||||
@@ -109,6 +116,18 @@ int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
|
|||||||
/** Set hardware interrupt affinity */
|
/** Set hardware interrupt affinity */
|
||||||
int sbi_irqchip_set_affinity(struct sbi_irqchip_device *chip, u32 hwirq, u32 hart_index);
|
int sbi_irqchip_set_affinity(struct sbi_irqchip_device *chip, u32 hwirq, u32 hart_index);
|
||||||
|
|
||||||
|
/** Write MSI message to the hardware interrupt handler */
|
||||||
|
int sbi_irqchip_write_msi(struct sbi_irqchip_device *chip, u32 hwirq,
|
||||||
|
const struct sbi_irqchip_msi_msg *msg);
|
||||||
|
|
||||||
|
/** Register a hardware MSI handler */
|
||||||
|
int sbi_irqchip_register_msi(struct sbi_irqchip_device *chip, u32 num_hwirq,
|
||||||
|
void (*write_msi)(u32 hwirq,
|
||||||
|
const struct sbi_irqchip_msi_msg *msg,
|
||||||
|
void *priv),
|
||||||
|
int (*callback)(u32 hwirq, void *priv), void *priv,
|
||||||
|
u32 *out_first_hwirq);
|
||||||
|
|
||||||
/** Register a hardware interrupt handler */
|
/** Register a hardware interrupt handler */
|
||||||
int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
||||||
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
||||||
|
|||||||
+69
-2
@@ -35,6 +35,9 @@ struct sbi_irqchip_handler {
|
|||||||
/** Number of consecutive hardware IRQs handled by this handler */
|
/** Number of consecutive hardware IRQs handled by this handler */
|
||||||
u32 num_hwirq;
|
u32 num_hwirq;
|
||||||
|
|
||||||
|
/** Write MSI function of this handler */
|
||||||
|
void (*write_msi)(u32 hwirq, const struct sbi_irqchip_msi_msg *msg, void *priv);
|
||||||
|
|
||||||
/** Callback function of this handler */
|
/** Callback function of this handler */
|
||||||
int (*callback)(u32 hwirq, void *priv);
|
int (*callback)(u32 hwirq, void *priv);
|
||||||
|
|
||||||
@@ -141,6 +144,24 @@ int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sbi_irqchip_write_msi(struct sbi_irqchip_device *chip, u32 hwirq,
|
||||||
|
const struct sbi_irqchip_msi_msg *msg)
|
||||||
|
{
|
||||||
|
struct sbi_irqchip_handler *h;
|
||||||
|
|
||||||
|
if (!chip || chip->num_hwirq <= hwirq || !msg)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
h = sbi_irqchip_find_handler(chip, hwirq);
|
||||||
|
if (!h)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
if (!h->write_msi)
|
||||||
|
return SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
h->write_msi(hwirq, msg, h->priv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
|
int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
|
||||||
u32 *out_hart_index)
|
u32 *out_hart_index)
|
||||||
{
|
{
|
||||||
@@ -215,6 +236,9 @@ static int __sbi_irqchip_handler_set_affinity(struct sbi_irqchip_device *chip,
|
|||||||
|
|
||||||
static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
||||||
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
||||||
|
void (*write_msi)(u32 hwirq,
|
||||||
|
const struct sbi_irqchip_msi_msg *msg,
|
||||||
|
void *priv),
|
||||||
int (*callback)(u32 hwirq, void *priv), void *priv)
|
int (*callback)(u32 hwirq, void *priv), void *priv)
|
||||||
{
|
{
|
||||||
struct sbi_irqchip_handler *h, *th, *nh;
|
struct sbi_irqchip_handler *h, *th, *nh;
|
||||||
@@ -232,6 +256,7 @@ static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
|||||||
return SBI_ENOMEM;
|
return SBI_ENOMEM;
|
||||||
h->first_hwirq = first_hwirq;
|
h->first_hwirq = first_hwirq;
|
||||||
h->num_hwirq = num_hwirq;
|
h->num_hwirq = num_hwirq;
|
||||||
|
h->write_msi = write_msi;
|
||||||
h->callback = callback;
|
h->callback = callback;
|
||||||
h->priv = priv;
|
h->priv = priv;
|
||||||
|
|
||||||
@@ -281,6 +306,48 @@ static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sbi_irqchip_register_msi(struct sbi_irqchip_device *chip, u32 num_hwirq,
|
||||||
|
void (*write_msi)(u32 hwirq,
|
||||||
|
const struct sbi_irqchip_msi_msg *msg,
|
||||||
|
void *priv),
|
||||||
|
int (*callback)(u32 hwirq, void *priv), void *priv,
|
||||||
|
u32 *out_first_hwirq)
|
||||||
|
{
|
||||||
|
struct sbi_irqchip_handler *h;
|
||||||
|
bool found;
|
||||||
|
u32 hwirq;
|
||||||
|
|
||||||
|
if (!chip || !chip->hwirq_set_affinity || !num_hwirq ||
|
||||||
|
!write_msi || !callback || !out_first_hwirq)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
if (chip->num_hwirq < num_hwirq)
|
||||||
|
return SBI_EBAD_RANGE;
|
||||||
|
|
||||||
|
hwirq = 0;
|
||||||
|
found = false;
|
||||||
|
sbi_list_for_each_entry(h, &chip->handler_list, node) {
|
||||||
|
if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq)) {
|
||||||
|
hwirq = h->first_hwirq + h->num_hwirq;
|
||||||
|
} else if (hwirq < h->first_hwirq) {
|
||||||
|
if (h->first_hwirq - hwirq < num_hwirq) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
hwirq = h->first_hwirq + h->num_hwirq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found && !hwirq)
|
||||||
|
found = true;
|
||||||
|
if (!found)
|
||||||
|
return SBI_ENOSPC;
|
||||||
|
*out_first_hwirq = hwirq;
|
||||||
|
|
||||||
|
return __sbi_irqchip_register_handler(chip, *out_first_hwirq,
|
||||||
|
num_hwirq, SBI_HWIRQ_FLAGS_NONE,
|
||||||
|
write_msi, callback, priv);
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
||||||
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
|
||||||
int (*callback)(u32 hwirq, void *priv), void *priv)
|
int (*callback)(u32 hwirq, void *priv), void *priv)
|
||||||
@@ -292,7 +359,7 @@ int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
|
|||||||
return SBI_EBAD_RANGE;
|
return SBI_EBAD_RANGE;
|
||||||
|
|
||||||
return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq, hwirq_flags,
|
return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq, hwirq_flags,
|
||||||
callback, priv);
|
NULL, callback, priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
|
int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
|
||||||
@@ -305,7 +372,7 @@ int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
|
|||||||
return SBI_EBAD_RANGE;
|
return SBI_EBAD_RANGE;
|
||||||
|
|
||||||
return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq,
|
return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq,
|
||||||
SBI_HWIRQ_FLAGS_NONE, NULL, NULL);
|
SBI_HWIRQ_FLAGS_NONE, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
|
int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
|
||||||
|
|||||||
Reference in New Issue
Block a user