mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-07-26 15:51:38 +01:00
lib: utils/irqchip/imsic: track IRQ enable state and restore EIE on warm init
Add an irq_state field to struct sbi_irqchip_hwirq_data with a single IRQ_ENABLED flag (bit 0) to track whether a hardware interrupt has been enabled via the irqchip framework. Set IRQ_ENABLED in sbi_irqchip_unmask_hwirq() when the unmask callback is invoked. Add sbi_irqchip_get_irq_state() as a private inline accessor and expose sbi_irqchip_is_irq_enabled() as a public API for drivers to query the enabled state of a hardware interrupt by chip pointer and hwirq number. Refactor imsic_local_eix_update() to operate on a single interrupt ID instead of a base+count range, simplifying the CSR bit manipulation to a direct BIT(id) write without the inner loop. Update all call sites accordingly. Use sbi_irqchip_is_irq_enabled() in imsic_warm_irqchip_init() to restore per-EIID EIE CSR state on warm boot and HSM resume based on the saved irq_state, replacing the previous blanket disable of all interrupts. This ensures that EIIDs enabled during hotplug/warminit cycle are correctly re-enabled on the resuming hart without requiring software to re-register or re-unmask each interrupt. Signed-off-by: Oza Pawandeep <pawandeep.oza@oss.qualcomm.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260721214833.687361-6-pawandeep.oza@oss.qualcomm.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
committed by
Anup Patel
parent
193b1d9e7e
commit
b2ead3b037
@@ -168,4 +168,8 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
|
|||||||
/** Exit interrupt controllers */
|
/** Exit interrupt controllers */
|
||||||
void sbi_irqchip_exit(struct sbi_scratch *scratch);
|
void sbi_irqchip_exit(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
/** Check if the interrupt is enabled */
|
||||||
|
bool sbi_irqchip_is_hwirq_enabled(struct sbi_irqchip_device *chip,
|
||||||
|
u32 hwirq);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ struct sbi_irqchip_hwirq_data {
|
|||||||
/** raw hardware interrupt handler */
|
/** raw hardware interrupt handler */
|
||||||
int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
|
int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
|
||||||
|
|
||||||
|
#define IRQ_ENABLED BIT(0)
|
||||||
|
/** interrupt state
|
||||||
|
* bit 0 - 1: enabled, 0: disabled */
|
||||||
|
u32 irq_state;
|
||||||
|
|
||||||
/** target hart index */
|
/** target hart index */
|
||||||
u32 hart_index;
|
u32 hart_index;
|
||||||
|
|
||||||
@@ -80,23 +85,54 @@ int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
|
|||||||
return data->raw_handler(chip, hwirq);
|
return data->raw_handler(chip, hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 sbi_irqchip_get_irq_state(struct sbi_irqchip_device *chip,
|
||||||
|
u32 hwirq)
|
||||||
|
{
|
||||||
|
if (!chip || !chip->hwirqs || hwirq >= chip->num_hwirq)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return chip->hwirqs[hwirq].irq_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sbi_irqchip_is_hwirq_enabled(struct sbi_irqchip_device *chip,
|
||||||
|
u32 hwirq)
|
||||||
|
{
|
||||||
|
return !!(sbi_irqchip_get_irq_state(chip, hwirq) & IRQ_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
|
int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
|
||||||
{
|
{
|
||||||
|
struct sbi_irqchip_hwirq_data *data;
|
||||||
|
|
||||||
if (!chip || chip->num_hwirq <= hwirq)
|
if (!chip || chip->num_hwirq <= hwirq)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
data = &chip->hwirqs[hwirq];
|
||||||
|
if (sbi_irqchip_is_hwirq_enabled(chip, hwirq))
|
||||||
|
return SBI_EALREADY;
|
||||||
|
|
||||||
if (chip->hwirq_unmask)
|
if (chip->hwirq_unmask)
|
||||||
chip->hwirq_unmask(chip, hwirq);
|
chip->hwirq_unmask(chip, hwirq);
|
||||||
|
|
||||||
|
data->irq_state |= IRQ_ENABLED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
|
int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
|
||||||
{
|
{
|
||||||
|
struct sbi_irqchip_hwirq_data *data;
|
||||||
|
|
||||||
if (!chip || chip->num_hwirq <= hwirq)
|
if (!chip || chip->num_hwirq <= hwirq)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
if (!sbi_irqchip_is_hwirq_enabled(chip, hwirq))
|
||||||
|
return SBI_EALREADY;
|
||||||
|
|
||||||
if (chip->hwirq_mask)
|
if (chip->hwirq_mask)
|
||||||
chip->hwirq_mask(chip, hwirq);
|
chip->hwirq_mask(chip, hwirq);
|
||||||
|
|
||||||
|
data = &chip->hwirqs[hwirq];
|
||||||
|
data->irq_state &= ~IRQ_ENABLED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-28
@@ -225,29 +225,20 @@ static struct sbi_ipi_device imsic_ipi_device = {
|
|||||||
.ipi_send = imsic_ipi_send
|
.ipi_send = imsic_ipi_send
|
||||||
};
|
};
|
||||||
|
|
||||||
static void imsic_local_eix_update(unsigned long base_id,
|
static void imsic_local_eix_update(unsigned long id,
|
||||||
unsigned long num_id, bool pend, bool val)
|
bool pend, bool val)
|
||||||
{
|
{
|
||||||
unsigned long i, isel, ireg;
|
unsigned long isel, ireg = 0;
|
||||||
unsigned long id = base_id, last_id = base_id + num_id;
|
|
||||||
|
|
||||||
while (id < last_id) {
|
isel = id / __riscv_xlen;
|
||||||
isel = id / __riscv_xlen;
|
isel *= __riscv_xlen / IMSIC_EIPx_BITS;
|
||||||
isel *= __riscv_xlen / IMSIC_EIPx_BITS;
|
isel += (pend) ? IMSIC_EIP0 : IMSIC_EIE0;
|
||||||
isel += (pend) ? IMSIC_EIP0 : IMSIC_EIE0;
|
ireg |= BIT(id);
|
||||||
|
|
||||||
ireg = 0;
|
if (val)
|
||||||
for (i = id & (__riscv_xlen - 1);
|
imsic_csr_set(isel, ireg);
|
||||||
(id < last_id) && (i < __riscv_xlen); i++) {
|
else
|
||||||
ireg |= BIT(i);
|
imsic_csr_clear(isel, ireg);
|
||||||
id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val)
|
|
||||||
imsic_csr_set(isel, ireg);
|
|
||||||
else
|
|
||||||
imsic_csr_clear(isel, ireg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void imsic_local_irqchip_init(void)
|
void imsic_local_irqchip_init(void)
|
||||||
@@ -275,13 +266,14 @@ void imsic_local_irqchip_init(void)
|
|||||||
imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY);
|
imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY);
|
||||||
|
|
||||||
/* Enable IPI */
|
/* Enable IPI */
|
||||||
imsic_local_eix_update(IMSIC_IPI_ID, 1, false, true);
|
imsic_local_eix_update(IMSIC_IPI_ID, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imsic_warm_irqchip_init(struct sbi_irqchip_device *dev)
|
static int imsic_warm_irqchip_init(struct sbi_irqchip_device *dev)
|
||||||
{
|
{
|
||||||
struct imsic_data *imsic;
|
struct imsic_data *imsic;
|
||||||
struct imsic_data *hart_imsic;
|
struct imsic_data *hart_imsic;
|
||||||
|
int i;
|
||||||
|
|
||||||
imsic = container_of(dev, struct imsic_data, irqchip);
|
imsic = container_of(dev, struct imsic_data, irqchip);
|
||||||
hart_imsic = imsic_get_data(current_hartindex());
|
hart_imsic = imsic_get_data(current_hartindex());
|
||||||
@@ -291,11 +283,16 @@ static int imsic_warm_irqchip_init(struct sbi_irqchip_device *dev)
|
|||||||
!hart_imsic->targets_mmode)
|
!hart_imsic->targets_mmode)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
/* Disable all interrupts */
|
/* enable interrutps based on the irq state */
|
||||||
imsic_local_eix_update(1, imsic->num_ids, false, false);
|
for (i = 1; i < imsic->num_ids; i++) {
|
||||||
|
if (sbi_irqchip_is_hwirq_enabled(&imsic->irqchip, i) == true)
|
||||||
|
imsic_local_eix_update(i, true, true);
|
||||||
|
else
|
||||||
|
imsic_local_eix_update(i, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear IPI pending */
|
/* Clear IPI pending */
|
||||||
imsic_local_eix_update(IMSIC_IPI_ID, 1, true, false);
|
imsic_local_eix_update(IMSIC_IPI_ID, true, false);
|
||||||
|
|
||||||
/* Local IMSIC initialization */
|
/* Local IMSIC initialization */
|
||||||
imsic_local_irqchip_init();
|
imsic_local_irqchip_init();
|
||||||
@@ -395,8 +392,8 @@ static void imsic_hwirq_cleanup(struct sbi_irqchip_device *chip, u32 hwirq)
|
|||||||
if (!imsic || !imsic->targets_mmode)
|
if (!imsic || !imsic->targets_mmode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
imsic_local_eix_update(hwirq, 1, false, false);
|
imsic_local_eix_update(hwirq, false, false);
|
||||||
imsic_local_eix_update(hwirq, 1, true, false);
|
imsic_local_eix_update(hwirq, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imsic_hwirq_eoi(struct sbi_irqchip_device *chip, u32 hwirq)
|
static void imsic_hwirq_eoi(struct sbi_irqchip_device *chip, u32 hwirq)
|
||||||
@@ -529,7 +526,7 @@ static void imsic_hwirq_mask(struct sbi_irqchip_device *chip, u32 hwirq)
|
|||||||
if (!imsic || !imsic->targets_mmode)
|
if (!imsic || !imsic->targets_mmode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
imsic_local_eix_update(hwirq, 1, false, false);
|
imsic_local_eix_update(hwirq, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imsic_hwirq_unmask(struct sbi_irqchip_device *chip, u32 hwirq)
|
static void imsic_hwirq_unmask(struct sbi_irqchip_device *chip, u32 hwirq)
|
||||||
@@ -546,7 +543,7 @@ static void imsic_hwirq_unmask(struct sbi_irqchip_device *chip, u32 hwirq)
|
|||||||
if (!hwirq || hwirq == IMSIC_IPI_ID)
|
if (!hwirq || hwirq == IMSIC_IPI_ID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
imsic_local_eix_update(hwirq, 1, false, true);
|
imsic_local_eix_update(hwirq, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sbi_irqchip_device imsic_device = {
|
static struct sbi_irqchip_device imsic_device = {
|
||||||
|
|||||||
Reference in New Issue
Block a user