Files
opensbi/include/sbi/sbi_irqchip.h
T
Pawandeep OzaandAnup Patel 759910326c lib: utils/irqchip/aplic: add MSI mode support with IMSIC parent linking
Add parent_unique_id fields to struct aplic_data for
IMSIC parent linking in MSI mode. Store parent IMSIC unique_id
during FDT parsing of the APLIC node.

Add aplic_is_msi_mode() complementing aplic_is_direct_mode() to
consolidate delivery mode detection. Add APLIC_TARGET_EIID() macro
for packing the EIID field into the TARGET register.

Add parent_unique_id and parent_irq_map fields to struct aplic_data.
parent_unique_id identifies the upstream IMSIC irqchip device resolved
via sbi_irqchip_find_device() during hwirq_setup. parent_irq_map is
a per-source array allocated at cold init time to track the EIID
assigned by the IMSIC for each APLIC source.

Restore aplic_writel_msicfg() and re-introduce MSI address register
programming in aplic_init(), gated on aplic_is_msi_mode(). Set the
DOMAINCFG_DM bit to switch the hardware to MSI delivery mode when
no IDC structures are present.

Add aplic_program_msi_target() to pack hart_index, guest_index, and
EIID into the APLIC_TARGET register. Add aplic_write_msi() as the
sbi_irqchip write_msi callback that extracts EIID and hart_index from
the MSI message and calls aplic_program_msi_target(). Add
aplic_msi_callback() as the MSI receive callback that dispatches to
sbi_irqchip_process_hwirq() on the APLIC chip.

Extend aplic_hwirq_setup() with an MSI path that resolves the parent
IMSIC chip by parent_unique_id, registers an MSI route via
sbi_irqchip_register_msi(), and stores the allocated EIID in
parent_irq_map for the source being configured.

Extend aplic_hwirq_set_affinity() with an MSI path that delegates
affinity reprogramming to the parent IMSIC chip via
sbi_irqchip_set_affinity() using the stored parent_irq_map entry.

Guard warm_init, process_hwirqs, and hwirq_eoi with early returns in
MSI mode as interrupt delivery and acknowledgement are handled by the
IMSIC in that configuration.

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-3-pawandeep.oza@oss.qualcomm.com
Signed-off-by: Anup Patel <anup@brainfault.org>
2026-07-22 13:08:13 +05:30

172 lines
5.5 KiB
C

/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_list.h>
#include <sbi/sbi_types.h>
struct sbi_scratch;
/** irqchip message signalled interrupt (MSI) */
struct sbi_irqchip_msi_msg {
u32 address_lo;
u32 address_hi;
u32 data;
};
/** irqchip hardware device */
struct sbi_irqchip_device {
/** Node in the list of irqchip devices (private) */
struct sbi_dlist node;
/** Internal data of all hardware interrupts of this irqchip (private) */
struct sbi_irqchip_hwirq_data *hwirqs;
/** List of interrupt handlers (private) */
struct sbi_dlist handler_list;
/** Unique ID of this irqchip */
u32 id;
/** Capabilities of this irqchip */
#define SBI_IRQCHIP_CAPS_WIRED BIT(0)
#define SBI_IRQCHIP_CAPS_MSI BIT(1)
unsigned long caps;
/** Number of hardware IRQs of this irqchip */
u32 num_hwirq;
/** Set of harts targetted by this irqchip */
struct sbi_hartmask target_harts;
/** Initialize per-hart state for the current hart */
int (*warm_init)(struct sbi_irqchip_device *chip);
/** Process hardware interrupts from this irqchip */
int (*process_hwirqs)(struct sbi_irqchip_device *chip);
/** Setup a hardware interrupt of this irqchip */
int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq,
u32 hwirq_flags);
#define SBI_HWIRQ_FLAGS_NONE 0x00000000UL
#define SBI_HWIRQ_FLAGS_EDGE_RISING 0x00000001UL
#define SBI_HWIRQ_FLAGS_EDGE_FALLING 0x00000002UL
#define SBI_HWIRQ_FLAGS_EDGE_BOTH (SBI_HWIRQ_FLAGS_EDGE_RISING | \
SBI_HWIRQ_FLAGS_EDGE_FALLING)
#define SBI_HWIRQ_FLAGS_LEVEL_HIGH 0x00000004UL
#define SBI_HWIRQ_FLAGS_LEVEL_LOW 0x00000008UL
#define SBI_HWIRQ_FLAGS_LEVEL_SENSE_MASK 0x0000000fUL
/** Cleanup a hardware interrupt of this irqchip */
void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
/** End of hardware interrupt of this irqchip */
void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
/** Set hardware interrupt affinity */
int (*hwirq_set_affinity)(struct sbi_irqchip_device *chip, u32 hwirq,
u32 hart_index);
/** Mask a hardware interrupt of this irqchip */
void (*hwirq_mask)(struct sbi_irqchip_device *chip, u32 hwirq);
/** Unmask a hardware interrupt of this irqchip */
void (*hwirq_unmask)(struct sbi_irqchip_device *chip, u32 hwirq);
};
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(void);
/**
* Process a hwirq of an irqchip device
*
* This function is called by irqchip drivers to handle hardware
* interrupts of the irqchip.
*/
int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
/** Unmask a hardware interrupt */
int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
/** Mask a hardware interrupt */
int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
/** Helper to set private data in sbi_irqchip_hwirq_data */
int sbi_irqchip_set_hwirq_priv(struct sbi_irqchip_device *chip, u32 hwirq, void *priv);
/** Helper to retrieve data from sbi_irqchip_hwirq_data */
void *sbi_irqchip_get_hwirq_priv(struct sbi_irqchip_device *chip, u32 hwirq);
/** Default raw hardware interrupt handler */
int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq);
/** Set raw hardware interrupt handler */
int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
int (*raw_hndl)(struct sbi_irqchip_device *, u32));
/** Get hardware interrupt affinity */
int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
u32 *out_hart_index);
/** Set hardware interrupt affinity */
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 */
int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
int (*callback)(u32 hwirq, void *priv), void *priv);
/** Register a hardware interrupts as reserved */
int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
u32 first_hwirq, u32 num_hwirq);
/** Unregister a hardware interrupt handler */
int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
u32 first_hwirq, u32 num_hwirq);
/** Find an irqchip device based on matching capabilities */
struct sbi_irqchip_device *sbi_irqchip_find_device_by_caps(unsigned long caps,
struct sbi_irqchip_device *first);
/** Find an irqchip device based on unique ID */
struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
/** Register an irqchip device to receive callbacks */
int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif