Commit a2234642 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-4.20' of...

Merge tag 'irqchip-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

Pull irqchip updates from Marc Zyngier:

 - kexec/kdump support for EFI-based GICv3 platforms
 - Marvell SEI support
 - QC PDC fixes
 - GIC cleanups and optimizations
 - DT updates

[ tglx: Dropped the madera driver as it breaks the build ]
parents 94967b55 2130b789
......@@ -5,6 +5,8 @@ The Marvell ICU (Interrupt Consolidation Unit) controller is
responsible for collecting all wired-interrupt sources in the CP and
communicating them to the GIC in the AP, the unit translates interrupt
requests on input wires to MSG memory mapped transactions to the GIC.
These messages will access a different GIC memory area depending on
their type (NSR, SR, SEI, REI, etc).
Required properties:
......@@ -12,20 +14,23 @@ Required properties:
- reg: Should contain ICU registers location and length.
- #interrupt-cells: Specifies the number of cells needed to encode an
interrupt source. The value shall be 3.
Subnodes: Each group of interrupt is declared as a subnode of the ICU,
with their own compatible.
Required properties for the icu_nsr/icu_sei subnodes:
The 1st cell is the group type of the ICU interrupt. Possible group
types are:
- compatible: Should be one of:
* "marvell,cp110-icu-nsr"
* "marvell,cp110-icu-sr"
* "marvell,cp110-icu-sei"
* "marvell,cp110-icu-rei"
ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure
ICU_GRP_SR (0x1) : Shared peripheral interrupt, secure
ICU_GRP_SEI (0x4) : System error interrupt
ICU_GRP_REI (0x5) : RAM error interrupt
- #interrupt-cells: Specifies the number of cells needed to encode an
interrupt source. The value shall be 2.
The 2nd cell is the index of the interrupt in the ICU unit.
The 1st cell is the index of the interrupt in the ICU unit.
The 3rd cell is the type of the interrupt. See arm,gic.txt for
The 2nd cell is the type of the interrupt. See arm,gic.txt for
details.
- interrupt-controller: Identifies the node as an interrupt
......@@ -35,17 +40,73 @@ Required properties:
that allows to trigger interrupts using MSG memory mapped
transactions.
Note: each 'interrupts' property referring to any 'icu_xxx' node shall
have a different number within [0:206].
Example:
icu: interrupt-controller@1e0000 {
compatible = "marvell,cp110-icu";
reg = <0x1e0000 0x10>;
reg = <0x1e0000 0x440>;
CP110_LABEL(icu_nsr): interrupt-controller@10 {
compatible = "marvell,cp110-icu-nsr";
reg = <0x10 0x20>;
#interrupt-cells = <2>;
interrupt-controller;
msi-parent = <&gicp>;
};
CP110_LABEL(icu_sei): interrupt-controller@50 {
compatible = "marvell,cp110-icu-sei";
reg = <0x50 0x10>;
#interrupt-cells = <2>;
interrupt-controller;
msi-parent = <&sei>;
};
};
node1 {
interrupt-parent = <&icu_nsr>;
interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
};
node2 {
interrupt-parent = <&icu_sei>;
interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
};
/* Would not work with the above nodes */
node3 {
interrupt-parent = <&icu_nsr>;
interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
};
The legacy bindings were different in this way:
- #interrupt-cells: The value was 3.
The 1st cell was the group type of the ICU interrupt. Possible
group types were:
ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure
ICU_GRP_SR (0x1) : Shared peripheral interrupt, secure
ICU_GRP_SEI (0x4) : System error interrupt
ICU_GRP_REI (0x5) : RAM error interrupt
The 2nd cell was the index of the interrupt in the ICU unit.
The 3rd cell was the type of the interrupt. See arm,gic.txt for
details.
Example:
icu: interrupt-controller@1e0000 {
compatible = "marvell,cp110-icu";
reg = <0x1e0000 0x440>;
#interrupt-cells = <3>;
interrupt-controller;
msi-parent = <&gicp>;
};
usb3h0: usb3@500000 {
node1 {
interrupt-parent = <&icu>;
interrupts = <ICU_GRP_NSR 106 IRQ_TYPE_LEVEL_HIGH>;
};
Marvell SEI (System Error Interrupt) Controller
-----------------------------------------------
Marvell SEI (System Error Interrupt) controller is an interrupt
aggregator. It receives interrupts from several sources and aggregates
them to a single interrupt line (an SPI) on the parent interrupt
controller.
This interrupt controller can handle up to 64 SEIs, a set comes from the
AP and is wired while a second set comes from the CPs by the mean of
MSIs.
Required properties:
- compatible: should be one of:
* "marvell,ap806-sei"
- reg: SEI registers location and length.
- interrupts: identifies the parent IRQ that will be triggered.
- #interrupt-cells: number of cells to define an SEI wired interrupt
coming from the AP, should be 1. The cell is the IRQ
number.
- interrupt-controller: identifies the node as an interrupt controller
for AP interrupts.
- msi-controller: identifies the node as an MSI controller for the CPs
interrupts.
Example:
sei: interrupt-controller@3f0200 {
compatible = "marvell,ap806-sei";
reg = <0x3f0200 0x40>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <1>;
interrupt-controller;
msi-controller;
};
......@@ -2,10 +2,12 @@ DT bindings for the R-Mobile/R-Car/RZ/G interrupt controller
Required properties:
- compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback.
- compatible: must be "renesas,irqc-<soctype>" or "renesas,intc-ex-<soctype>",
and "renesas,irqc" as fallback.
Examples with soctypes are:
- "renesas,irqc-r8a73a4" (R-Mobile APE6)
- "renesas,irqc-r8a7743" (RZ/G1M)
- "renesas,irqc-r8a7744" (RZ/G1N)
- "renesas,irqc-r8a7745" (RZ/G1E)
- "renesas,irqc-r8a77470" (RZ/G1C)
- "renesas,irqc-r8a7790" (R-Car H2)
......@@ -19,6 +21,7 @@ Required properties:
- "renesas,intc-ex-r8a77965" (R-Car M3-N)
- "renesas,intc-ex-r8a77970" (R-Car V3M)
- "renesas,intc-ex-r8a77980" (R-Car V3H)
- "renesas,intc-ex-r8a77990" (R-Car E3)
- "renesas,intc-ex-r8a77995" (R-Car D3)
- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
interrupts.txt in this directory
......
......@@ -128,6 +128,7 @@ config ARCH_MVEBU
select MVEBU_ICU
select MVEBU_ODMI
select MVEBU_PIC
select MVEBU_SEI
select OF_GPIO
select PINCTRL
select PINCTRL_ARMADA_37XX
......
......@@ -321,11 +321,12 @@ void *platform_msi_get_host_data(struct irq_domain *domain)
* Returns an irqdomain for @nvec interrupts
*/
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data)
__platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
bool is_tree,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data)
{
struct platform_msi_priv_data *data;
struct irq_domain *domain;
......@@ -336,7 +337,8 @@ platform_msi_create_device_domain(struct device *dev,
return NULL;
data->host_data = host_data;
domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
domain = irq_domain_create_hierarchy(dev->msi_domain, 0,
is_tree ? 0 : nvec,
dev->fwnode, ops, data);
if (!domain)
goto free_priv;
......
......@@ -52,7 +52,8 @@ struct efi __read_mostly efi = {
.properties_table = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = EFI_INVALID_TABLE_ADDR,
.tpm_log = EFI_INVALID_TABLE_ADDR
.tpm_log = EFI_INVALID_TABLE_ADDR,
.mem_reserve = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
......@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
{NULL_GUID, NULL, NULL},
};
......@@ -591,6 +593,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
early_memunmap(tbl, sizeof(*tbl));
}
if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
unsigned long prsv = efi.mem_reserve;
while (prsv) {
struct linux_efi_memreserve *rsv;
/* reserve the entry itself */
memblock_reserve(prsv, sizeof(*rsv));
rsv = early_memremap(prsv, sizeof(*rsv));
if (rsv == NULL) {
pr_err("Could not map UEFI memreserve entry!\n");
return -ENOMEM;
}
if (rsv->size)
memblock_reserve(rsv->base, rsv->size);
prsv = rsv->next;
early_memunmap(rsv, sizeof(*rsv));
}
}
return 0;
}
......@@ -937,6 +962,38 @@ bool efi_is_table_address(unsigned long phys_addr)
return false;
}
static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
int efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
{
struct linux_efi_memreserve *rsv, *parent;
if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
return -ENODEV;
rsv = kmalloc(sizeof(*rsv), GFP_KERNEL);
if (!rsv)
return -ENOMEM;
parent = memremap(efi.mem_reserve, sizeof(*rsv), MEMREMAP_WB);
if (!parent) {
kfree(rsv);
return -ENOMEM;
}
rsv->base = addr;
rsv->size = size;
spin_lock(&efi_mem_reserve_persistent_lock);
rsv->next = parent->next;
parent->next = __pa(rsv);
spin_unlock(&efi_mem_reserve_persistent_lock);
memunmap(parent);
return 0;
}
#ifdef CONFIG_KEXEC
static int update_efi_random_seed(struct notifier_block *nb,
unsigned long code, void *unused)
......
......@@ -69,6 +69,31 @@ static struct screen_info *setup_graphics(efi_system_table_t *sys_table_arg)
return si;
}
void install_memreserve_table(efi_system_table_t *sys_table_arg)
{
struct linux_efi_memreserve *rsv;
efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
efi_status_t status;
status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv),
(void **)&rsv);
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table_arg, "Failed to allocate memreserve entry!\n");
return;
}
rsv->next = 0;
rsv->base = 0;
rsv->size = 0;
status = efi_call_early(install_configuration_table,
&memreserve_table_guid,
rsv);
if (status != EFI_SUCCESS)
pr_efi_err(sys_table_arg, "Failed to install memreserve config table!\n");
}
/*
* This function handles the architcture specific differences between arm and
* arm64 regarding where the kernel image must be loaded and any memory that
......@@ -235,6 +260,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
}
}
install_memreserve_table(sys_table);
new_fdt_addr = fdt_addr;
status = allocate_new_fdt_and_exit_boot(sys_table, handle,
&new_fdt_addr, efi_get_max_fdt_addr(dram_base),
......
......@@ -310,6 +310,9 @@ config MVEBU_ODMI
config MVEBU_PIC
bool
config MVEBU_SEI
bool
config LS_SCFG_MSI
def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
depends on PCI && PCI_MSI
......
......@@ -76,6 +76,7 @@ obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o
obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
......
This diff is collapsed.
......@@ -348,48 +348,45 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
{
u32 irqnr;
do {
irqnr = gic_read_iar();
irqnr = gic_read_iar();
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;
if (static_branch_likely(&supports_deactivate_key))
if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
else
isb();
err = handle_domain_irq(gic_data.domain, irqnr, regs);
if (err) {
WARN_ONCE(true, "Unexpected interrupt received!\n");
if (static_branch_likely(&supports_deactivate_key)) {
if (irqnr < 8192)
gic_write_dir(irqnr);
} else {
gic_write_eoir(irqnr);
else
isb();
err = handle_domain_irq(gic_data.domain, irqnr, regs);
if (err) {
WARN_ONCE(true, "Unexpected interrupt received!\n");
if (static_branch_likely(&supports_deactivate_key)) {
if (irqnr < 8192)
gic_write_dir(irqnr);
} else {
gic_write_eoir(irqnr);
}
}
continue;
}
if (irqnr < 16) {
gic_write_eoir(irqnr);
if (static_branch_likely(&supports_deactivate_key))
gic_write_dir(irqnr);
return;
}
if (irqnr < 16) {
gic_write_eoir(irqnr);
if (static_branch_likely(&supports_deactivate_key))
gic_write_dir(irqnr);
#ifdef CONFIG_SMP
/*
* Unlike GICv2, we don't need an smp_rmb() here.
* The control dependency from gic_read_iar to
* the ISB in gic_write_eoir is enough to ensure
* that any shared data read by handle_IPI will
* be read after the ACK.
*/
handle_IPI(irqnr, regs);
/*
* Unlike GICv2, we don't need an smp_rmb() here.
* The control dependency from gic_read_iar to
* the ISB in gic_write_eoir is enough to ensure
* that any shared data read by handle_IPI will
* be read after the ACK.
*/
handle_IPI(irqnr, regs);
#else
WARN_ONCE(true, "Unexpected SGI received!\n");
WARN_ONCE(true, "Unexpected SGI received!\n");
#endif
continue;
}
} while (irqnr != ICC_IAR1_EL1_SPURIOUS);
}
}
static void __init gic_dist_init(void)
......@@ -653,7 +650,9 @@ early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
static int gic_dist_supports_lpis(void)
{
return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi;
return (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) &&
!!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) &&
!gicv3_nolpi);
}
static void gic_cpu_init(void)
......@@ -673,10 +672,6 @@ static void gic_cpu_init(void)
gic_cpu_config(rbase, gic_redist_wait_for_rwp);
/* Give LPIs a spin */
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
its_cpu_init();
/* initialise system registers */
gic_cpu_sys_reg_init();
}
......@@ -689,6 +684,10 @@ static void gic_cpu_init(void)
static int gic_starting_cpu(unsigned int cpu)
{
gic_cpu_init();
if (gic_dist_supports_lpis())
its_cpu_init();
return 0;
}
......@@ -1127,14 +1126,16 @@ static int __init gic_init_bases(void __iomem *dist_base,
gic_update_vlpi_properties();
if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
its_init(handle, &gic_data.rdists, gic_data.domain);
gic_smp_init();
gic_dist_init();
gic_cpu_init();
gic_cpu_pm_init();
if (gic_dist_supports_lpis()) {
its_init(handle, &gic_data.rdists, gic_data.domain);
its_cpu_init();
}
return 0;
out_free:
......
This diff is collapsed.
This diff is collapsed.
......@@ -124,6 +124,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
break;
case IRQ_TYPE_EDGE_BOTH:
pdc_type = PDC_EDGE_DUAL;
type = IRQ_TYPE_EDGE_RISING;
break;
case IRQ_TYPE_LEVEL_HIGH:
pdc_type = PDC_LEVEL_HIGH;
......
......@@ -672,6 +672,7 @@ void efi_native_runtime_setup(void);
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
typedef struct {
efi_guid_t guid;
......@@ -957,6 +958,7 @@ extern struct efi {
unsigned long mem_attr_table; /* memory attributes table */
unsigned long rng_seed; /* UEFI firmware random seed */
unsigned long tpm_log; /* TPM2 Event Log table */
unsigned long mem_reserve; /* Linux EFI memreserve table */
efi_get_time_t *get_time;
efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time;
......@@ -1041,6 +1043,7 @@ extern int __init efi_uart_console_only (void);
extern u64 efi_mem_desc_end(efi_memory_desc_t *md);
extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md);
extern void efi_mem_reserve(phys_addr_t addr, u64 size);
extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size);
extern void efi_initialize_iomem_resources(struct resource *code_resource,
struct resource *data_resource, struct resource *bss_resource);
extern void efi_reserve_boot_services(void);
......@@ -1662,4 +1665,10 @@ extern int efi_tpm_eventlog_init(void);
/* Workqueue to queue EFI Runtime Services */
extern struct workqueue_struct *efi_rts_wq;
struct linux_efi_memreserve {
phys_addr_t next;
phys_addr_t base;
phys_addr_t size;
};
#endif /* _LINUX_EFI_H */
......@@ -13,6 +13,12 @@
#include <linux/types.h>
#include <linux/ioport.h>
#define GICD_INT_DEF_PRI 0xa0
#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
(GICD_INT_DEF_PRI << 16) |\
(GICD_INT_DEF_PRI << 8) |\
GICD_INT_DEF_PRI)
enum gic_type {
GIC_V2,
GIC_V3,
......
......@@ -585,8 +585,10 @@ struct rdists {
void __iomem *rd_base;
struct page *pend_page;
phys_addr_t phys_base;
bool lpi_enabled;
} __percpu *rdist;
struct page *prop_page;
phys_addr_t prop_table_pa;
void *prop_table_va;
u64 flags;
u32 gicd_typer;
bool has_vlpis;
......
......@@ -65,11 +65,6 @@
#define GICD_INT_EN_CLR_X32 0xffffffff
#define GICD_INT_EN_SET_SGI 0x0000ffff
#define GICD_INT_EN_CLR_PPI 0xffff0000
#define GICD_INT_DEF_PRI 0xa0
#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
(GICD_INT_DEF_PRI << 16) |\
(GICD_INT_DEF_PRI << 8) |\
GICD_INT_DEF_PRI)
#define GICD_IIDR_IMPLEMENTER_SHIFT 0
#define GICD_IIDR_IMPLEMENTER_MASK (0xfff << GICD_IIDR_IMPLEMENTER_SHIFT)
......
......@@ -75,6 +75,7 @@ struct irq_fwspec {
enum irq_domain_bus_token {
DOMAIN_BUS_ANY = 0,
DOMAIN_BUS_WIRED,
DOMAIN_BUS_GENERIC_MSI,
DOMAIN_BUS_PCI_MSI,
DOMAIN_BUS_PLATFORM_MSI,
DOMAIN_BUS_NEXUS,
......
......@@ -317,11 +317,18 @@ int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
int virq, int nvec, msi_alloc_info_t *args);
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
__platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
bool is_tree,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
#define platform_msi_create_device_domain(dev, nvec, write, ops, data) \
__platform_msi_create_device_domain(dev, nvec, false, write, ops, data)
#define platform_msi_create_device_tree_domain(dev, nvec, write, ops, data) \
__platform_msi_create_device_domain(dev, nvec, true, write, ops, data)
int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs);
void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment