diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2016-07-06 07:25:55 -0700 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2016-07-06 07:25:55 -0700 |
commit | ea1a25c3348abc33d7d94db28501766adf3d1c7d (patch) | |
tree | ca3c5c8b72532117034dd2d57a2a85eead13db7b /drivers/irqchip | |
parent | 5e7ff2ca7f2da55fe777167849d0c93403bd0dc8 (diff) | |
parent | 262e2bfd7d1e1f1ee48b870e5dfabb87c06b975e (diff) | |
download | talos-op-linux-ea1a25c3348abc33d7d94db28501766adf3d1c7d.tar.gz talos-op-linux-ea1a25c3348abc33d7d94db28501766adf3d1c7d.zip |
Merge branch 'jejb-fixes' into fixes
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/Kconfig | 7 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-clps711x.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-eznps.c | 165 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-common.c | 13 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-common.h | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 49 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 177 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic.c | 91 | ||||
-rw-r--r-- | drivers/irqchip/irq-hip04.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 44 | ||||
-rw-r--r-- | drivers/irqchip/irq-pic32-evic.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/spear-shirq.c | 2 |
13 files changed, 509 insertions, 49 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 81f88ada3a61..fa33c50b0e5a 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -253,3 +253,10 @@ config LS_SCFG_MSI config PARTITION_PERCPU bool + +config EZNPS_GIC + bool "NPS400 Global Interrupt Manager (GIM)" + depends on ARC || (COMPILE_TEST && !64BIT) + select IRQ_DOMAIN + help + Support the EZchip NPS400 global interrupt controller diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index f828244b44c2..38853a187607 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o +obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c index eb5eb0cd414d..2223b3f15d68 100644 --- a/drivers/irqchip/irq-clps711x.c +++ b/drivers/irqchip/irq-clps711x.c @@ -182,7 +182,7 @@ static int __init _clps711x_intc_init(struct device_node *np, writel_relaxed(0, clps711x_intc->intmr[2]); err = irq_alloc_descs(-1, 0, ARRAY_SIZE(clps711x_irqs), numa_node_id()); - if (IS_ERR_VALUE(err)) + if (err < 0) goto out_iounmap; clps711x_intc->ops.map = clps711x_intc_irq_map; diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c new file mode 100644 index 000000000000..efbf0e4304b7 --- /dev/null +++ b/drivers/irqchip/irq-eznps.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/irqchip.h> +#include <soc/nps/common.h> + +#define NPS_NR_CPU_IRQS 8 /* number of interrupt lines of NPS400 CPU */ +#define NPS_TIMER0_IRQ 3 + +/* + * NPS400 core includes an Interrupt Controller (IC) support. + * All cores can deactivate level irqs at first level control + * at cores mesh layer called MTM. + * For devices out side chip e.g. uart, network there is another + * level called Global Interrupt Manager (GIM). + * This second level can control level and edge interrupt. + * + * NOTE: AUX_IENABLE and CTOP_AUX_IACK are auxiliary registers + * with private HW copy per CPU. + */ + +static void nps400_irq_mask(struct irq_data *irqd) +{ + unsigned int ienb; + unsigned int irq = irqd_to_hwirq(irqd); + + ienb = read_aux_reg(AUX_IENABLE); + ienb &= ~(1 << irq); + write_aux_reg(AUX_IENABLE, ienb); +} + +static void nps400_irq_unmask(struct irq_data *irqd) +{ + unsigned int ienb; + unsigned int irq = irqd_to_hwirq(irqd); + + ienb = read_aux_reg(AUX_IENABLE); + ienb |= (1 << irq); + write_aux_reg(AUX_IENABLE, ienb); +} + +static void nps400_irq_eoi_global(struct irq_data *irqd) +{ + unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); + + write_aux_reg(CTOP_AUX_IACK, 1 << irq); + + /* Don't ack GIC before all device access attempts are done */ + mb(); + + nps_ack_gic(); +} + +static void nps400_irq_eoi(struct irq_data *irqd) +{ + unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); + + write_aux_reg(CTOP_AUX_IACK, 1 << irq); +} + +static struct irq_chip nps400_irq_chip_fasteoi = { + .name = "NPS400 IC Global", + .irq_mask = nps400_irq_mask, + .irq_unmask = nps400_irq_unmask, + .irq_eoi = nps400_irq_eoi_global, +}; + +static struct irq_chip nps400_irq_chip_percpu = { + .name = "NPS400 IC", + .irq_mask = nps400_irq_mask, + .irq_unmask = nps400_irq_unmask, + .irq_eoi = nps400_irq_eoi, +}; + +static int nps400_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + switch (hw) { + case NPS_TIMER0_IRQ: +#ifdef CONFIG_SMP + case NPS_IPI_IRQ: +#endif + irq_set_percpu_devid(virq); + irq_set_chip_and_handler(virq, &nps400_irq_chip_percpu, + handle_percpu_devid_irq); + break; + default: + irq_set_chip_and_handler(virq, &nps400_irq_chip_fasteoi, + handle_fasteoi_irq); + break; + } + + return 0; +} + +static const struct irq_domain_ops nps400_irq_ops = { + .xlate = irq_domain_xlate_onecell, + .map = nps400_irq_map, +}; + +static int __init nps400_of_init(struct device_node *node, + struct device_node *parent) +{ + static struct irq_domain *nps400_root_domain; + + if (parent) { + pr_err("DeviceTree incore ic not a root irq controller\n"); + return -EINVAL; + } + + nps400_root_domain = irq_domain_add_linear(node, NPS_NR_CPU_IRQS, + &nps400_irq_ops, NULL); + + if (!nps400_root_domain) { + pr_err("nps400 root irq domain not avail\n"); + return -ENOMEM; + } + + /* + * Needed for primary domain lookup to succeed + * This is a primary irqchip, and can never have a parent + */ + irq_set_default_host(nps400_root_domain); + +#ifdef CONFIG_SMP + irq_create_mapping(nps400_root_domain, NPS_IPI_IRQ); +#endif + + return 0; +} +IRQCHIP_DECLARE(ezchip_nps400_ic, "ezchip,nps400-ic", nps400_of_init); diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 97c0028e8388..89e7423f0ebb 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -21,6 +21,19 @@ #include "irq-gic-common.h" +static const struct gic_kvm_info *gic_kvm_info; + +const struct gic_kvm_info *gic_get_kvm_info(void) +{ + return gic_kvm_info; +} + +void gic_set_kvm_info(const struct gic_kvm_info *info) +{ + BUG_ON(gic_kvm_info != NULL); + gic_kvm_info = info; +} + void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data) { diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index fff697db8e22..205e5fddf6da 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/irqdomain.h> +#include <linux/irqchip/arm-gic-common.h> struct gic_quirk { const char *desc; @@ -35,4 +36,6 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, void *data); +void gic_set_kvm_info(const struct gic_kvm_info *info); + #endif /* _IRQ_GIC_COMMON_H */ diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 6bd881be24ea..5eb1f9e17a98 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -41,6 +41,7 @@ #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) +#define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) @@ -82,6 +83,7 @@ struct its_node { u64 flags; u32 ite_size; u32 device_ids; + int numa_node; }; #define ITS_ITT_ALIGN SZ_256 @@ -613,11 +615,23 @@ static void its_unmask_irq(struct irq_data *d) static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { - unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); + unsigned int cpu; + const struct cpumask *cpu_mask = cpu_online_mask; struct its_device *its_dev = irq_data_get_irq_chip_data(d); struct its_collection *target_col; u32 id = its_get_event_id(d); + /* lpi cannot be routed to a redistributor that is on a foreign node */ + if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { + if (its_dev->its->numa_node >= 0) { + cpu_mask = cpumask_of_node(its_dev->its->numa_node); + if (!cpumask_intersects(mask_val, cpu_mask)) + return -EINVAL; + } + } + + cpu = cpumask_any_and(mask_val, cpu_mask); + if (cpu >= nr_cpu_ids) return -EINVAL; @@ -1101,6 +1115,16 @@ static void its_cpu_init_collection(void) list_for_each_entry(its, &its_nodes, entry) { u64 target; + /* avoid cross node collections and its mapping */ + if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { + struct device_node *cpu_node; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (its->numa_node != NUMA_NO_NODE && + its->numa_node != of_node_to_nid(cpu_node)) + continue; + } + /* * We now have to bind each collection to its target * redistributor. @@ -1351,9 +1375,14 @@ static void its_irq_domain_activate(struct irq_domain *domain, { struct its_device *its_dev = irq_data_get_irq_chip_data(d); u32 event = its_get_event_id(d); + const struct cpumask *cpu_mask = cpu_online_mask; + + /* get the cpu_mask of local node */ + if (its_dev->its->numa_node >= 0) + cpu_mask = cpumask_of_node(its_dev->its->numa_node); /* Bind the LPI to the first possible CPU */ - its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask); + its_dev->event_map.col_map[event] = cpumask_first(cpu_mask); /* Map the GIC IRQ and event to the device */ its_send_mapvi(its_dev, d->hwirq, event); @@ -1443,6 +1472,13 @@ static void __maybe_unused its_enable_quirk_cavium_22375(void *data) its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375; } +static void __maybe_unused its_enable_quirk_cavium_23144(void *data) +{ + struct its_node *its = data; + + its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_23144; +} + static const struct gic_quirk its_quirks[] = { #ifdef CONFIG_CAVIUM_ERRATUM_22375 { @@ -1452,6 +1488,14 @@ static const struct gic_quirk its_quirks[] = { .init = its_enable_quirk_cavium_22375, }, #endif +#ifdef CONFIG_CAVIUM_ERRATUM_23144 + { + .desc = "ITS: Cavium erratum 23144", + .iidr = 0xa100034c, /* ThunderX pass 1.x */ + .mask = 0xffff0fff, + .init = its_enable_quirk_cavium_23144, + }, +#endif { } }; @@ -1514,6 +1558,7 @@ static int __init its_probe(struct device_node *node, its->base = its_base; its->phys_base = res.start; its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; + its->numa_node = of_node_to_nid(node); its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); if (!its->cmd_base) { diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 1a1ea4f733c1..2c5ba0e704bf 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -15,6 +15,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define pr_fmt(fmt) "GICv3: " fmt + #include <linux/acpi.h> #include <linux/cpu.h> #include <linux/cpu_pm.h> @@ -28,6 +30,7 @@ #include <linux/slab.h> #include <linux/irqchip.h> +#include <linux/irqchip/arm-gic-common.h> #include <linux/irqchip/arm-gic-v3.h> #include <linux/irqchip/irq-partition-percpu.h> @@ -59,6 +62,8 @@ struct gic_chip_data { static struct gic_chip_data gic_data __read_mostly; static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; +static struct gic_kvm_info gic_v3_kvm_info; + #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K) @@ -150,7 +155,7 @@ static void gic_enable_redist(bool enable) while (count--) { val = readl_relaxed(rbase + GICR_WAKER); - if (enable ^ (val & GICR_WAKER_ChildrenAsleep)) + if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep)) break; cpu_relax(); udelay(1); @@ -1002,7 +1007,7 @@ static int get_cpu_number(struct device_node *dn) } /* Create all possible partitions at boot time */ -static void gic_populate_ppi_partitions(struct device_node *gic_node) +static void __init gic_populate_ppi_partitions(struct device_node *gic_node) { struct device_node *parts_node, *child_part; int part_idx = 0, i; @@ -1089,6 +1094,30 @@ static void gic_populate_ppi_partitions(struct device_node *gic_node) } } +static void __init gic_of_setup_kvm_info(struct device_node *node) +{ + int ret; + struct resource r; + u32 gicv_idx; + + gic_v3_kvm_info.type = GIC_V3; + + gic_v3_kvm_info.maint_irq = irq_of_parse_and_map(node, 0); + if (!gic_v3_kvm_info.maint_irq) + return; + + if (of_property_read_u32(node, "#redistributor-regions", + &gicv_idx)) + gicv_idx = 1; + + gicv_idx += 3; /* Also skip GICD, GICC, GICH */ + ret = of_address_to_resource(node, gicv_idx, &r); + if (!ret) + gic_v3_kvm_info.vcpu = r; + + gic_set_kvm_info(&gic_v3_kvm_info); +} + static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *dist_base; @@ -1144,6 +1173,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare goto out_unmap_rdist; gic_populate_ppi_partitions(node); + gic_of_setup_kvm_info(node); return 0; out_unmap_rdist: @@ -1159,19 +1189,25 @@ out_unmap_dist: IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #ifdef CONFIG_ACPI -static void __iomem *dist_base; -static struct redist_region *redist_regs __initdata; -static u32 nr_redist_regions __initdata; -static bool single_redist; +static struct +{ + void __iomem *dist_base; + struct redist_region *redist_regs; + u32 nr_redist_regions; + bool single_redist; + u32 maint_irq; + int maint_irq_mode; + phys_addr_t vcpu_base; +} acpi_data __initdata; static void __init gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base) { static int count = 0; - redist_regs[count].phys_base = phys_base; - redist_regs[count].redist_base = redist_base; - redist_regs[count].single_redist = single_redist; + acpi_data.redist_regs[count].phys_base = phys_base; + acpi_data.redist_regs[count].redist_base = redist_base; + acpi_data.redist_regs[count].single_redist = acpi_data.single_redist; count++; } @@ -1199,7 +1235,7 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, { struct acpi_madt_generic_interrupt *gicc = (struct acpi_madt_generic_interrupt *)header; - u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; + u32 reg = readl_relaxed(acpi_data.dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; void __iomem *redist_base; @@ -1216,7 +1252,7 @@ static int __init gic_acpi_collect_gicr_base(void) acpi_tbl_entry_handler redist_parser; enum acpi_madt_type type; - if (single_redist) { + if (acpi_data.single_redist) { type = ACPI_MADT_TYPE_GENERIC_INTERRUPT; redist_parser = gic_acpi_parse_madt_gicc; } else { @@ -1267,14 +1303,14 @@ static int __init gic_acpi_count_gicr_regions(void) count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, gic_acpi_match_gicr, 0); if (count > 0) { - single_redist = false; + acpi_data.single_redist = false; return count; } count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, gic_acpi_match_gicc, 0); if (count > 0) - single_redist = true; + acpi_data.single_redist = true; return count; } @@ -1294,36 +1330,117 @@ static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header, if (count <= 0) return false; - nr_redist_regions = count; + acpi_data.nr_redist_regions = count; return true; } +static int __init gic_acpi_parse_virt_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc = + (struct acpi_madt_generic_interrupt *)header; + int maint_irq_mode; + static int first_madt = true; + + /* Skip unusable CPUs */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return 0; + + maint_irq_mode = (gicc->flags & ACPI_MADT_VGIC_IRQ_MODE) ? + ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + + if (first_madt) { + first_madt = false; + + acpi_data.maint_irq = gicc->vgic_interrupt; + acpi_data.maint_irq_mode = maint_irq_mode; + acpi_data.vcpu_base = gicc->gicv_base_address; + + return 0; + } + + /* + * The maintenance interrupt and GICV should be the same for every CPU + */ + if ((acpi_data.maint_irq != gicc->vgic_interrupt) || + (acpi_data.maint_irq_mode != maint_irq_mode) || + (acpi_data.vcpu_base != gicc->gicv_base_address)) + return -EINVAL; + + return 0; +} + +static bool __init gic_acpi_collect_virt_info(void) +{ + int count; + + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_parse_virt_madt_gicc, 0); + + return (count > 0); +} + #define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K) +#define ACPI_GICV2_VCTRL_MEM_SIZE (SZ_4K) +#define ACPI_GICV2_VCPU_MEM_SIZE (SZ_8K) + +static void __init gic_acpi_setup_kvm_info(void) +{ + int irq; + + if (!gic_acpi_collect_virt_info()) { + pr_warn("Unable to get hardware information used for virtualization\n"); + return; + } + + gic_v3_kvm_info.type = GIC_V3; + + irq = acpi_register_gsi(NULL, acpi_data.maint_irq, + acpi_data.maint_irq_mode, + ACPI_ACTIVE_HIGH); + if (irq <= 0) + return; + + gic_v3_kvm_info.maint_irq = irq; + + if (acpi_data.vcpu_base) { + struct resource *vcpu = &gic_v3_kvm_info.vcpu; + + vcpu->flags = IORESOURCE_MEM; + vcpu->start = acpi_data.vcpu_base; + vcpu->end = vcpu->start + ACPI_GICV2_VCPU_MEM_SIZE - 1; + } + + gic_set_kvm_info(&gic_v3_kvm_info); +} static int __init gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_generic_distributor *dist; struct fwnode_handle *domain_handle; + size_t size; int i, err; /* Get distributor base address */ dist = (struct acpi_madt_generic_distributor *)header; - dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE); - if (!dist_base) { + acpi_data.dist_base = ioremap(dist->base_address, + ACPI_GICV3_DIST_MEM_SIZE); + if (!acpi_data.dist_base) { pr_err("Unable to map GICD registers\n"); return -ENOMEM; } - err = gic_validate_dist_version(dist_base); + err = gic_validate_dist_version(acpi_data.dist_base); if (err) { - pr_err("No distributor detected at @%p, giving up", dist_base); + pr_err("No distributor detected at @%p, giving up", + acpi_data.dist_base); goto out_dist_unmap; } - redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions, - GFP_KERNEL); - if (!redist_regs) { + size = sizeof(*acpi_data.redist_regs) * acpi_data.nr_redist_regions; + acpi_data.redist_regs = kzalloc(size, GFP_KERNEL); + if (!acpi_data.redist_regs) { err = -ENOMEM; goto out_dist_unmap; } @@ -1332,29 +1449,31 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) if (err) goto out_redist_unmap; - domain_handle = irq_domain_alloc_fwnode(dist_base); + domain_handle = irq_domain_alloc_fwnode(acpi_data.dist_base); if (!domain_handle) { err = -ENOMEM; goto out_redist_unmap; } - err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0, - domain_handle); + err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs, + acpi_data.nr_redist_regions, 0, domain_handle); if (err) goto out_fwhandle_free; acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); + gic_acpi_setup_kvm_info(); + return 0; out_fwhandle_free: irq_domain_free_fwnode(domain_handle); out_redist_unmap: - for (i = 0; i < nr_redist_regions; i++) - if (redist_regs[i].redist_base) - iounmap(redist_regs[i].redist_base); - kfree(redist_regs); + for (i = 0; i < acpi_data.nr_redist_regions; i++) + if (acpi_data.redist_regs[i].redist_base) + iounmap(acpi_data.redist_regs[i].redist_base); + kfree(acpi_data.redist_regs); out_dist_unmap: - iounmap(dist_base); + iounmap(acpi_data.dist_base); return err; } IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 1de20e14a721..fbc4ae2afd29 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -105,6 +105,8 @@ static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly; +static struct gic_kvm_info gic_v2_kvm_info; + #ifdef CONFIG_GIC_NON_BANKED static void __iomem *gic_get_percpu_base(union gic_base *base) { @@ -1121,7 +1123,7 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start, irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); - if (IS_ERR_VALUE(irq_base)) { + if (irq_base < 0) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); irq_base = irq_start; @@ -1248,7 +1250,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base) return true; } -static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node) +static int __init gic_of_setup(struct gic_chip_data *gic, struct device_node *node) { if (!gic || !node) return -EINVAL; @@ -1272,6 +1274,29 @@ error: return -ENOMEM; } +static void __init gic_of_setup_kvm_info(struct device_node *node) +{ + int ret; + struct resource *vctrl_res = &gic_v2_kvm_info.vctrl; + struct resource *vcpu_res = &gic_v2_kvm_info.vcpu; + + gic_v2_kvm_info.type = GIC_V2; + + gic_v2_kvm_info.maint_irq = irq_of_parse_and_map(node, 0); + if (!gic_v2_kvm_info.maint_irq) + return; + + ret = of_address_to_resource(node, 2, vctrl_res); + if (ret) + return; + + ret = of_address_to_resource(node, 3, vcpu_res); + if (ret) + return; + + gic_set_kvm_info(&gic_v2_kvm_info); +} + int __init gic_of_init(struct device_node *node, struct device_node *parent) { @@ -1303,8 +1328,10 @@ gic_of_init(struct device_node *node, struct device_node *parent) return ret; } - if (!gic_cnt) + if (!gic_cnt) { gic_init_physaddr(node); + gic_of_setup_kvm_info(node); + } if (parent) { irq = irq_of_parse_and_map(node, 0); @@ -1330,7 +1357,14 @@ IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init); #endif #ifdef CONFIG_ACPI -static phys_addr_t cpu_phy_base __initdata; +static struct +{ + phys_addr_t cpu_phys_base; + u32 maint_irq; + int maint_irq_mode; + phys_addr_t vctrl_base; + phys_addr_t vcpu_base; +} acpi_data __initdata; static int __init gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, @@ -1350,10 +1384,16 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, * All CPU interface addresses have to be the same. */ gic_cpu_base = processor->base_address; - if (cpu_base_assigned && gic_cpu_base != cpu_phy_base) + if (cpu_base_assigned && gic_cpu_base != acpi_data.cpu_phys_base) return -EINVAL; - cpu_phy_base = gic_cpu_base; + acpi_data.cpu_phys_base = gic_cpu_base; + acpi_data.maint_irq = processor->vgic_interrupt; + acpi_data.maint_irq_mode = (processor->flags & ACPI_MADT_VGIC_IRQ_MODE) ? + ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + acpi_data.vctrl_base = processor->gich_base_address; + acpi_data.vcpu_base = processor->gicv_base_address; + cpu_base_assigned = 1; return 0; } @@ -1384,6 +1424,41 @@ static bool __init gic_validate_dist(struct acpi_subtable_header *header, #define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K) #define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) +#define ACPI_GICV2_VCTRL_MEM_SIZE (SZ_4K) +#define ACPI_GICV2_VCPU_MEM_SIZE (SZ_8K) + +static void __init gic_acpi_setup_kvm_info(void) +{ + int irq; + struct resource *vctrl_res = &gic_v2_kvm_info.vctrl; + struct resource *vcpu_res = &gic_v2_kvm_info.vcpu; + + gic_v2_kvm_info.type = GIC_V2; + + if (!acpi_data.vctrl_base) + return; + + vctrl_res->flags = IORESOURCE_MEM; + vctrl_res->start = acpi_data.vctrl_base; + vctrl_res->end = vctrl_res->start + ACPI_GICV2_VCTRL_MEM_SIZE - 1; + + if (!acpi_data.vcpu_base) + return; + + vcpu_res->flags = IORESOURCE_MEM; + vcpu_res->start = acpi_data.vcpu_base; + vcpu_res->end = vcpu_res->start + ACPI_GICV2_VCPU_MEM_SIZE - 1; + + irq = acpi_register_gsi(NULL, acpi_data.maint_irq, + acpi_data.maint_irq_mode, + ACPI_ACTIVE_HIGH); + if (irq <= 0) + return; + + gic_v2_kvm_info.maint_irq = irq; + + gic_set_kvm_info(&gic_v2_kvm_info); +} static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, const unsigned long end) @@ -1401,7 +1476,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, return -EINVAL; } - gic->raw_cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); + gic->raw_cpu_base = ioremap(acpi_data.cpu_phys_base, ACPI_GIC_CPU_IF_MEM_SIZE); if (!gic->raw_cpu_base) { pr_err("Unable to map GICC registers\n"); return -ENOMEM; @@ -1447,6 +1522,8 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) gicv2m_init(NULL, gic_data[0].domain); + gic_acpi_setup_kvm_info(); + return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 9688d2e2a636..9e25d8ce08e5 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -402,7 +402,7 @@ hip04_of_init(struct device_node *node, struct device_node *parent) nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */ irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id()); - if (IS_ERR_VALUE(irq_base)) { + if (irq_base < 0) { pr_err("failed to allocate IRQ numbers\n"); return -EINVAL; } diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 4dffccf532a2..8a4adbeb2b8c 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -197,7 +197,7 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu)); if (mips_cm_is64) { gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); @@ -246,6 +246,14 @@ void gic_stop_count(void) #endif +unsigned gic_read_local_vp_id(void) +{ + unsigned long ident; + + ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT)); + return ident & GIC_VP_IDENT_VCNUM_MSK; +} + static bool gic_local_irq_is_routable(int intr) { u32 vpe_ctl; @@ -553,7 +561,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -567,7 +576,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -607,7 +617,8 @@ static void __init gic_basic_init(void) for (i = 0; i < gic_vpes; i++) { unsigned int j; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; @@ -652,7 +663,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, for (i = 0; i < gic_vpes; i++) { u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); switch (intr) { case GIC_LOCAL_INT_WD: @@ -734,6 +746,12 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, /* verify that it doesn't conflict with an IPI irq */ if (test_bit(spec->hwirq, ipi_resrv)) return -EBUSY; + + hwirq = GIC_SHARED_TO_HWIRQ(spec->hwirq); + + return irq_domain_set_hwirq_and_chip(d, virq, hwirq, + &gic_level_irq_controller, + NULL); } else { base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); if (base_hwirq == gic_shared_intrs) { @@ -855,10 +873,14 @@ static int gic_dev_domain_alloc(struct irq_domain *d, unsigned int virq, &gic_level_irq_controller, NULL); if (ret) - return ret; + goto error; } return 0; + +error: + irq_domain_free_irqs_parent(d, virq, nr_irqs); + return ret; } void gic_dev_domain_free(struct irq_domain *d, unsigned int virq, @@ -956,7 +978,7 @@ static void __init __gic_init(unsigned long gic_base_addr, unsigned int cpu_vec, unsigned int irqbase, struct device_node *node) { - unsigned int gicconfig; + unsigned int gicconfig, cpu; unsigned int v[2]; __gic_base_addr = gic_base_addr; @@ -973,6 +995,14 @@ static void __init __gic_init(unsigned long gic_base_addr, gic_vpes = gic_vpes + 1; if (cpu_has_veic) { + /* Set EIC mode for all VPEs */ + for_each_present_cpu(cpu) { + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(cpu)); + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_CTL), + GIC_VPE_CTL_EIC_MODE_MSK); + } + /* Always use vector 1 in EIC mode */ gic_cpu_pin = 0; timer_cpu_pin = gic_cpu_pin; diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c index e7155db01d55..73addb4b625b 100644 --- a/drivers/irqchip/irq-pic32-evic.c +++ b/drivers/irqchip/irq-pic32-evic.c @@ -91,7 +91,7 @@ static int pic32_set_type_edge(struct irq_data *data, /* set polarity for external interrupts only */ for (i = 0; i < ARRAY_SIZE(priv->ext_irqs); i++) { if (priv->ext_irqs[i] == data->hwirq) { - ret = pic32_set_ext_polarity(i + 1, flow_type); + ret = pic32_set_ext_polarity(i, flow_type); if (ret) return ret; } diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 1ccd2abed65f..1518ba31a80c 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -232,7 +232,7 @@ static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr, nr_irqs += shirq_blocks[i]->nr_irqs; virq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); - if (IS_ERR_VALUE(virq_base)) { + if (virq_base < 0) { pr_err("%s: irq desc alloc failed\n", __func__); goto err_unmap; } |