mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
irqchip/gic-v5: Add GICv5 ITS support
The GICv5 architecture implements Interrupt Translation Service (ITS) components in order to translate events coming from peripherals into interrupt events delivered to the connected IRSes. Events (ie MSI memory writes to ITS translate frame), are translated by the ITS using tables kept in memory. ITS translation tables for peripherals is kept in memory storage (device table [DT] and Interrupt Translation Table [ITT]) that is allocated by the driver on boot. Both tables can be 1- or 2-level; the structure is chosen by the driver after probing the ITS HW parameters and checking the allowed table splits and supported {device/event}_IDbits. DT table entries are allocated on demand (ie when a device is probed); the DT table is sized using the number of supported deviceID bits in that that's a system design decision (ie the number of deviceID bits implemented should reflect the number of devices expected in a system) therefore it makes sense to allocate a DT table that can cater for the maximum number of devices. DT and ITT tables are allocated using the kmalloc interface; the allocation size may be smaller than a page or larger, and must provide contiguous memory pages. LPIs INTIDs backing the device events are allocated one-by-one and only upon Linux IRQ allocation; this to avoid preallocating a large number of LPIs to cover the HW device MSI vector size whereas few MSI entries are actually enabled by a device. ITS cacheability/shareability attributes are programmed according to the provided firmware ITS description. The GICv5 partially reuses the GICv3 ITS MSI parent infrastructure and adds functions required to retrieve the ITS translate frame addresses out of msi-map and msi-parent properties to implement the GICv5 ITS MSI parent callbacks. Co-developed-by: Sascha Bischoff <sascha.bischoff@arm.com> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com> Co-developed-by: Timothy Hayes <timothy.hayes@arm.com> Signed-off-by: Timothy Hayes <timothy.hayes@arm.com> Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20250703-gicv5-host-v7-28-12e71f1b3528@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
8b65db1e93
commit
57d72196df
9 changed files with 1561 additions and 1 deletions
|
@ -1970,6 +1970,7 @@ M: Marc Zyngier <maz@kernel.org>
|
|||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/arm,gic-v5*.yaml
|
||||
F: drivers/irqchip/irq-gic-its-msi-parent.[ch]
|
||||
F: drivers/irqchip/irq-gic-v5*.[ch]
|
||||
F: include/linux/irqchip/arm-gic-v5.h
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ config ARM_GIC_V5
|
|||
bool
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
select GENERIC_MSI_IRQ
|
||||
select IRQ_MSI_LIB
|
||||
select ARM_GIC_ITS_PARENT
|
||||
|
||||
config ARM_NVIC
|
||||
bool
|
||||
|
|
|
@ -37,7 +37,7 @@ obj-$(CONFIG_ARM_GIC_ITS_PARENT) += irq-gic-its-msi-parent.o
|
|||
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v4.o
|
||||
obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o
|
||||
obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o
|
||||
obj-$(CONFIG_ARM_GIC_V5) += irq-gic-v5.o irq-gic-v5-irs.o
|
||||
obj-$(CONFIG_ARM_GIC_V5) += irq-gic-v5.o irq-gic-v5-irs.o irq-gic-v5-its.o
|
||||
obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
|
||||
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
|
||||
obj-$(CONFIG_ARM_VIC) += irq-vic.o
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// Copyright (C) 2022 Intel
|
||||
|
||||
#include <linux/acpi_iort.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "irq-gic-its-msi-parent.h"
|
||||
|
@ -18,6 +19,23 @@
|
|||
MSI_FLAG_PCI_MSIX | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static int its_translate_frame_address(struct device_node *msi_node, phys_addr_t *pa)
|
||||
{
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
ret = of_property_match_string(msi_node, "reg-names", "ns-translate");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = of_address_to_resource(msi_node, ret, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*pa = res.start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
|
||||
{
|
||||
|
@ -82,8 +100,46 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
|
|||
msi_info = msi_get_domain_info(domain->parent);
|
||||
return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
|
||||
}
|
||||
|
||||
static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
|
||||
int nvec, msi_alloc_info_t *info)
|
||||
{
|
||||
struct device_node *msi_node = NULL;
|
||||
struct msi_domain_info *msi_info;
|
||||
struct pci_dev *pdev;
|
||||
phys_addr_t pa;
|
||||
u32 rid;
|
||||
int ret;
|
||||
|
||||
if (!dev_is_pci(dev))
|
||||
return -EINVAL;
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
rid = pci_msi_map_rid_ctlr_node(pdev, &msi_node);
|
||||
if (!msi_node)
|
||||
return -ENODEV;
|
||||
|
||||
ret = its_translate_frame_address(msi_node, &pa);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
|
||||
of_node_put(msi_node);
|
||||
|
||||
/* ITS specific DeviceID */
|
||||
info->scratchpad[0].ul = rid;
|
||||
/* ITS translate frame physical address */
|
||||
info->scratchpad[1].ul = pa;
|
||||
|
||||
/* Always allocate power of two vectors */
|
||||
nvec = roundup_pow_of_two(nvec);
|
||||
|
||||
msi_info = msi_get_domain_info(domain->parent);
|
||||
return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
|
||||
}
|
||||
#else /* CONFIG_PCI_MSI */
|
||||
#define its_pci_msi_prepare NULL
|
||||
#define its_v5_pci_msi_prepare NULL
|
||||
#endif /* !CONFIG_PCI_MSI */
|
||||
|
||||
static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
|
||||
|
@ -118,6 +174,53 @@ static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int of_v5_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev,
|
||||
u32 *dev_id, phys_addr_t *pa)
|
||||
{
|
||||
int ret, index = 0;
|
||||
/*
|
||||
* Retrieve the DeviceID and the ITS translate frame node pointer
|
||||
* out of the msi-parent property.
|
||||
*/
|
||||
do {
|
||||
struct of_phandle_args args;
|
||||
|
||||
ret = of_parse_phandle_with_args(dev->of_node,
|
||||
"msi-parent", "#msi-cells",
|
||||
index, &args);
|
||||
if (ret)
|
||||
break;
|
||||
/*
|
||||
* The IRQ domain fwnode is the msi controller parent
|
||||
* in GICv5 (where the msi controller nodes are the
|
||||
* ITS translate frames).
|
||||
*/
|
||||
if (args.np->parent == irq_domain_get_of_node(domain)) {
|
||||
if (WARN_ON(args.args_count != 1))
|
||||
return -EINVAL;
|
||||
*dev_id = args.args[0];
|
||||
|
||||
ret = its_translate_frame_address(args.np, pa);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
} while (!ret);
|
||||
|
||||
if (ret) {
|
||||
struct device_node *np = NULL;
|
||||
|
||||
ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id);
|
||||
if (np) {
|
||||
ret = its_translate_frame_address(np, pa);
|
||||
of_node_put(np);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
|
||||
{
|
||||
return -1;
|
||||
|
@ -148,6 +251,33 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
|
|||
dev, nvec, info);
|
||||
}
|
||||
|
||||
static int its_v5_pmsi_prepare(struct irq_domain *domain, struct device *dev,
|
||||
int nvec, msi_alloc_info_t *info)
|
||||
{
|
||||
struct msi_domain_info *msi_info;
|
||||
phys_addr_t pa;
|
||||
u32 dev_id;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_v5_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* ITS specific DeviceID */
|
||||
info->scratchpad[0].ul = dev_id;
|
||||
/* ITS translate frame physical address */
|
||||
info->scratchpad[1].ul = pa;
|
||||
|
||||
/* Allocate always as a power of 2 */
|
||||
nvec = roundup_pow_of_two(nvec);
|
||||
|
||||
msi_info = msi_get_domain_info(domain->parent);
|
||||
return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
|
||||
}
|
||||
|
||||
static void its_msi_teardown(struct irq_domain *domain, msi_alloc_info_t *info)
|
||||
{
|
||||
struct msi_domain_info *msi_info;
|
||||
|
@ -199,6 +329,32 @@ static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool its_v5_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
|
||||
struct irq_domain *real_parent, struct msi_domain_info *info)
|
||||
{
|
||||
if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
|
||||
return false;
|
||||
|
||||
switch (info->bus_token) {
|
||||
case DOMAIN_BUS_PCI_DEVICE_MSI:
|
||||
case DOMAIN_BUS_PCI_DEVICE_MSIX:
|
||||
info->ops->msi_prepare = its_v5_pci_msi_prepare;
|
||||
info->ops->msi_teardown = its_msi_teardown;
|
||||
break;
|
||||
case DOMAIN_BUS_DEVICE_MSI:
|
||||
case DOMAIN_BUS_WIRED_TO_MSI:
|
||||
info->ops->msi_prepare = its_v5_pmsi_prepare;
|
||||
info->ops->msi_teardown = its_msi_teardown;
|
||||
break;
|
||||
default:
|
||||
/* Confused. How did the lib return true? */
|
||||
WARN_ON_ONCE(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
|
||||
.supported_flags = ITS_MSI_FLAGS_SUPPORTED,
|
||||
.required_flags = ITS_MSI_FLAGS_REQUIRED,
|
||||
|
@ -208,3 +364,13 @@ const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
|
|||
.prefix = "ITS-",
|
||||
.init_dev_msi_info = its_init_dev_msi_info,
|
||||
};
|
||||
|
||||
const struct msi_parent_ops gic_v5_its_msi_parent_ops = {
|
||||
.supported_flags = ITS_MSI_FLAGS_SUPPORTED,
|
||||
.required_flags = ITS_MSI_FLAGS_REQUIRED,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_EOI,
|
||||
.bus_select_token = DOMAIN_BUS_NEXUS,
|
||||
.bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
|
||||
.prefix = "ITS-v5-",
|
||||
.init_dev_msi_info = its_v5_init_dev_msi_info,
|
||||
};
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
#define _IRQ_GIC_ITS_MSI_PARENT_H
|
||||
|
||||
extern const struct msi_parent_ops gic_v3_its_msi_parent_ops;
|
||||
extern const struct msi_parent_ops gic_v5_its_msi_parent_ops;
|
||||
|
||||
#endif /* _IRQ_GIC_ITS_MSI_PARENT_H */
|
||||
|
|
|
@ -484,6 +484,22 @@ static int gicv5_irs_wait_for_idle(struct gicv5_irs_chip_data *irs_data)
|
|||
GICV5_IRS_CR0_IDLE, NULL);
|
||||
}
|
||||
|
||||
void gicv5_irs_syncr(void)
|
||||
{
|
||||
struct gicv5_irs_chip_data *irs_data;
|
||||
u32 syncr;
|
||||
|
||||
irs_data = list_first_entry_or_null(&irs_nodes, struct gicv5_irs_chip_data, entry);
|
||||
if (WARN_ON_ONCE(!irs_data))
|
||||
return;
|
||||
|
||||
syncr = FIELD_PREP(GICV5_IRS_SYNCR_SYNC, 1);
|
||||
irs_writel_relaxed(irs_data, syncr, GICV5_IRS_SYNCR);
|
||||
|
||||
gicv5_wait_for_op(irs_data->irs_base, GICV5_IRS_SYNC_STATUSR,
|
||||
GICV5_IRS_SYNC_STATUSR_IDLE);
|
||||
}
|
||||
|
||||
int gicv5_irs_register_cpu(int cpuid)
|
||||
{
|
||||
struct gicv5_irs_chip_data *irs_data;
|
||||
|
@ -780,6 +796,14 @@ int __init gicv5_irs_enable(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init gicv5_irs_its_probe(void)
|
||||
{
|
||||
struct gicv5_irs_chip_data *irs_data;
|
||||
|
||||
list_for_each_entry(irs_data, &irs_nodes, entry)
|
||||
gicv5_its_of_probe(to_of_node(irs_data->fwnode));
|
||||
}
|
||||
|
||||
int __init gicv5_irs_of_probe(struct device_node *parent)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
|
1206
drivers/irqchip/irq-gic-v5-its.c
Normal file
1206
drivers/irqchip/irq-gic-v5-its.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1071,6 +1071,8 @@ static int __init gicv5_of_init(struct device_node *node, struct device_node *pa
|
|||
|
||||
gicv5_smp_init();
|
||||
|
||||
gicv5_irs_its_probe();
|
||||
|
||||
return 0;
|
||||
|
||||
out_int:
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#define GICV5_IRS_IDR7 0x001c
|
||||
#define GICV5_IRS_CR0 0x0080
|
||||
#define GICV5_IRS_CR1 0x0084
|
||||
#define GICV5_IRS_SYNCR 0x00c0
|
||||
#define GICV5_IRS_SYNC_STATUSR 0x00c4
|
||||
#define GICV5_IRS_SPI_SELR 0x0108
|
||||
#define GICV5_IRS_SPI_CFGR 0x0114
|
||||
#define GICV5_IRS_SPI_STATUSR 0x0118
|
||||
|
@ -103,6 +105,10 @@
|
|||
#define GICV5_IRS_CR1_OC GENMASK(3, 2)
|
||||
#define GICV5_IRS_CR1_SH GENMASK(1, 0)
|
||||
|
||||
#define GICV5_IRS_SYNCR_SYNC BIT(31)
|
||||
|
||||
#define GICV5_IRS_SYNC_STATUSR_IDLE BIT(0)
|
||||
|
||||
#define GICV5_IRS_SPI_STATUSR_V BIT(1)
|
||||
#define GICV5_IRS_SPI_STATUSR_IDLE BIT(0)
|
||||
|
||||
|
@ -144,6 +150,104 @@
|
|||
|
||||
#define GICV5_ISTL1E_L2_ADDR_MASK GENMASK_ULL(55, 12)
|
||||
|
||||
/*
|
||||
* ITS registers and tables structures
|
||||
*/
|
||||
#define GICV5_ITS_IDR1 0x0004
|
||||
#define GICV5_ITS_IDR2 0x0008
|
||||
#define GICV5_ITS_CR0 0x0080
|
||||
#define GICV5_ITS_CR1 0x0084
|
||||
#define GICV5_ITS_DT_BASER 0x00c0
|
||||
#define GICV5_ITS_DT_CFGR 0x00d0
|
||||
#define GICV5_ITS_DIDR 0x0100
|
||||
#define GICV5_ITS_EIDR 0x0108
|
||||
#define GICV5_ITS_INV_EVENTR 0x010c
|
||||
#define GICV5_ITS_INV_DEVICER 0x0110
|
||||
#define GICV5_ITS_STATUSR 0x0120
|
||||
#define GICV5_ITS_SYNCR 0x0140
|
||||
#define GICV5_ITS_SYNC_STATUSR 0x0148
|
||||
|
||||
#define GICV5_ITS_IDR1_L2SZ GENMASK(10, 8)
|
||||
#define GICV5_ITS_IDR1_ITT_LEVELS BIT(7)
|
||||
#define GICV5_ITS_IDR1_DT_LEVELS BIT(6)
|
||||
#define GICV5_ITS_IDR1_DEVICEID_BITS GENMASK(5, 0)
|
||||
|
||||
#define GICV5_ITS_IDR1_L2SZ_SUPPORT_4KB(r) FIELD_GET(BIT(8), (r))
|
||||
#define GICV5_ITS_IDR1_L2SZ_SUPPORT_16KB(r) FIELD_GET(BIT(9), (r))
|
||||
#define GICV5_ITS_IDR1_L2SZ_SUPPORT_64KB(r) FIELD_GET(BIT(10), (r))
|
||||
|
||||
#define GICV5_ITS_IDR2_XDMN_EVENTs GENMASK(6, 5)
|
||||
#define GICV5_ITS_IDR2_EVENTID_BITS GENMASK(4, 0)
|
||||
|
||||
#define GICV5_ITS_CR0_IDLE BIT(1)
|
||||
#define GICV5_ITS_CR0_ITSEN BIT(0)
|
||||
|
||||
#define GICV5_ITS_CR1_ITT_RA BIT(7)
|
||||
#define GICV5_ITS_CR1_DT_RA BIT(6)
|
||||
#define GICV5_ITS_CR1_IC GENMASK(5, 4)
|
||||
#define GICV5_ITS_CR1_OC GENMASK(3, 2)
|
||||
#define GICV5_ITS_CR1_SH GENMASK(1, 0)
|
||||
|
||||
#define GICV5_ITS_DT_CFGR_STRUCTURE BIT(16)
|
||||
#define GICV5_ITS_DT_CFGR_L2SZ GENMASK(7, 6)
|
||||
#define GICV5_ITS_DT_CFGR_DEVICEID_BITS GENMASK(5, 0)
|
||||
|
||||
#define GICV5_ITS_DT_BASER_ADDR_MASK GENMASK_ULL(55, 3)
|
||||
|
||||
#define GICV5_ITS_INV_DEVICER_I BIT(31)
|
||||
#define GICV5_ITS_INV_DEVICER_EVENTID_BITS GENMASK(5, 1)
|
||||
#define GICV5_ITS_INV_DEVICER_L1 BIT(0)
|
||||
|
||||
#define GICV5_ITS_DIDR_DEVICEID GENMASK_ULL(31, 0)
|
||||
|
||||
#define GICV5_ITS_EIDR_EVENTID GENMASK(15, 0)
|
||||
|
||||
#define GICV5_ITS_INV_EVENTR_I BIT(31)
|
||||
#define GICV5_ITS_INV_EVENTR_ITT_L2SZ GENMASK(2, 1)
|
||||
#define GICV5_ITS_INV_EVENTR_L1 BIT(0)
|
||||
|
||||
#define GICV5_ITS_STATUSR_IDLE BIT(0)
|
||||
|
||||
#define GICV5_ITS_SYNCR_SYNC BIT_ULL(63)
|
||||
#define GICV5_ITS_SYNCR_SYNCALL BIT_ULL(32)
|
||||
#define GICV5_ITS_SYNCR_DEVICEID GENMASK_ULL(31, 0)
|
||||
|
||||
#define GICV5_ITS_SYNC_STATUSR_IDLE BIT(0)
|
||||
|
||||
#define GICV5_DTL1E_VALID BIT_ULL(0)
|
||||
/* Note that there is no shift for the address by design */
|
||||
#define GICV5_DTL1E_L2_ADDR_MASK GENMASK_ULL(55, 3)
|
||||
#define GICV5_DTL1E_SPAN GENMASK_ULL(63, 60)
|
||||
|
||||
#define GICV5_DTL2E_VALID BIT_ULL(0)
|
||||
#define GICV5_DTL2E_ITT_L2SZ GENMASK_ULL(2, 1)
|
||||
/* Note that there is no shift for the address by design */
|
||||
#define GICV5_DTL2E_ITT_ADDR_MASK GENMASK_ULL(55, 3)
|
||||
#define GICV5_DTL2E_ITT_DSWE BIT_ULL(57)
|
||||
#define GICV5_DTL2E_ITT_STRUCTURE BIT_ULL(58)
|
||||
#define GICV5_DTL2E_EVENT_ID_BITS GENMASK_ULL(63, 59)
|
||||
|
||||
#define GICV5_ITTL1E_VALID BIT_ULL(0)
|
||||
/* Note that there is no shift for the address by design */
|
||||
#define GICV5_ITTL1E_L2_ADDR_MASK GENMASK_ULL(55, 3)
|
||||
#define GICV5_ITTL1E_SPAN GENMASK_ULL(63, 60)
|
||||
|
||||
#define GICV5_ITTL2E_LPI_ID GENMASK_ULL(23, 0)
|
||||
#define GICV5_ITTL2E_DAC GENMASK_ULL(29, 28)
|
||||
#define GICV5_ITTL2E_VIRTUAL BIT_ULL(30)
|
||||
#define GICV5_ITTL2E_VALID BIT_ULL(31)
|
||||
#define GICV5_ITTL2E_VM_ID GENMASK_ULL(47, 32)
|
||||
|
||||
#define GICV5_ITS_DT_ITT_CFGR_L2SZ_4k 0b00
|
||||
#define GICV5_ITS_DT_ITT_CFGR_L2SZ_16k 0b01
|
||||
#define GICV5_ITS_DT_ITT_CFGR_L2SZ_64k 0b10
|
||||
|
||||
#define GICV5_ITS_DT_ITT_CFGR_STRUCTURE_LINEAR 0
|
||||
#define GICV5_ITS_DT_ITT_CFGR_STRUCTURE_TWO_LEVEL 1
|
||||
|
||||
#define GICV5_ITS_HWIRQ_DEVICE_ID GENMASK_ULL(31, 0)
|
||||
#define GICV5_ITS_HWIRQ_EVENT_ID GENMASK_ULL(63, 32)
|
||||
|
||||
/*
|
||||
* Global Data structures and functions
|
||||
*/
|
||||
|
@ -197,24 +301,77 @@ static inline int gicv5_wait_for_op_s_atomic(void __iomem *addr, u32 offset,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int gicv5_wait_for_op_s(void __iomem *addr, u32 offset,
|
||||
const char *reg_s, u32 mask)
|
||||
{
|
||||
void __iomem *reg = addr + offset;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(reg, val, val & mask, 1, 10 * USEC_PER_MSEC);
|
||||
if (unlikely(ret == -ETIMEDOUT)) {
|
||||
pr_err_ratelimited("%s timeout...\n", reg_s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define gicv5_wait_for_op_atomic(base, reg, mask, val) \
|
||||
gicv5_wait_for_op_s_atomic(base, reg, #reg, mask, val)
|
||||
|
||||
#define gicv5_wait_for_op(base, reg, mask) \
|
||||
gicv5_wait_for_op_s(base, reg, #reg, mask)
|
||||
|
||||
void __init gicv5_init_lpi_domain(void);
|
||||
void __init gicv5_free_lpi_domain(void);
|
||||
|
||||
int gicv5_irs_of_probe(struct device_node *parent);
|
||||
void gicv5_irs_remove(void);
|
||||
int gicv5_irs_enable(void);
|
||||
void gicv5_irs_its_probe(void);
|
||||
int gicv5_irs_register_cpu(int cpuid);
|
||||
int gicv5_irs_cpu_to_iaffid(int cpu_id, u16 *iaffid);
|
||||
struct gicv5_irs_chip_data *gicv5_irs_lookup_by_spi_id(u32 spi_id);
|
||||
int gicv5_spi_irq_set_type(struct irq_data *d, unsigned int type);
|
||||
int gicv5_irs_iste_alloc(u32 lpi);
|
||||
void gicv5_irs_syncr(void);
|
||||
|
||||
struct gicv5_its_devtab_cfg {
|
||||
union {
|
||||
struct {
|
||||
__le64 *devtab;
|
||||
} linear;
|
||||
struct {
|
||||
__le64 *l1devtab;
|
||||
__le64 **l2ptrs;
|
||||
} l2;
|
||||
};
|
||||
u32 cfgr;
|
||||
};
|
||||
|
||||
struct gicv5_its_itt_cfg {
|
||||
union {
|
||||
struct {
|
||||
__le64 *itt;
|
||||
unsigned int num_ents;
|
||||
} linear;
|
||||
struct {
|
||||
__le64 *l1itt;
|
||||
__le64 **l2ptrs;
|
||||
unsigned int num_l1_ents;
|
||||
u8 l2sz;
|
||||
} l2;
|
||||
};
|
||||
u8 event_id_bits;
|
||||
bool l2itt;
|
||||
};
|
||||
|
||||
void gicv5_init_lpis(u32 max);
|
||||
void gicv5_deinit_lpis(void);
|
||||
|
||||
int gicv5_alloc_lpi(void);
|
||||
void gicv5_free_lpi(u32 lpi);
|
||||
|
||||
void __init gicv5_its_of_probe(struct device_node *parent);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue