Loading Documentation/devicetree/bindings/arm/gic.txt 0 → 100644 +55 −0 Original line number Diff line number Diff line * ARM Generic Interrupt Controller ARM SMP cores are often associated with a GIC, providing per processor interrupts (PPI), shared processor interrupts (SPI) and software generated interrupts (SGI). Primary GIC is attached directly to the CPU and typically has PPIs and SGIs. Secondary GICs are cascaded into the upward interrupt controller and do not have PPIs or SGIs. Main node required properties: - compatible : should be one of: "arm,cortex-a9-gic" "arm,arm11mp-gic" - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an interrupt source. The type shall be a <u32> and the value shall be 3. The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI interrupts. The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the range [0-15]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags. 1 = low-to-high edge triggered 2 = high-to-low edge triggered 4 = active high level-sensitive 8 = active low level-sensitive bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of the 8 possible cpus attached to the GIC. A bit set to '1' indicated the interrupt is wired to that CPU. Only valid for PPI interrupts. - reg : Specifies base physical address(s) and size of the GIC registers. The first region is the GIC distributor register base and size. The 2nd region is the GIC cpu interface register base and size. Optional - interrupts : Interrupt source of the parent interrupt controller. Only present on secondary GICs. Example: intc: interrupt-controller@fff11000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; arch/arm/Kconfig +36 −10 Original line number Diff line number Diff line Loading @@ -196,7 +196,8 @@ config VECTORS_BASE The base address of exception vectors. config ARM_PATCH_PHYS_VIRT bool "Patch physical to virtual translations at runtime" bool "Patch physical to virtual translations at runtime" if EMBEDDED default y depends on !XIP_KERNEL && MMU depends on !ARCH_REALVIEW || !SPARSEMEM help Loading @@ -205,16 +206,25 @@ config ARM_PATCH_PHYS_VIRT kernel in system memory. This can only be used with non-XIP MMU kernels where the base of physical memory is at a 16MB boundary, or theoretically 64K for the MSM machine class. of physical memory is at a 16MB boundary. config ARM_PATCH_PHYS_VIRT_16BIT def_bool y depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM Only disable this option if you know that you do not require this feature (eg, building a kernel for a single machine) and you need to shrink the kernel to the minimal size. config NEED_MACH_MEMORY_H bool help Select this when mach/memory.h is required to provide special definitions for this platform. The need for mach/memory.h should be avoided when possible. config PHYS_OFFSET hex "Physical address of main memory" depends on !ARM_PATCH_PHYS_VIRT && !NEED_MACH_MEMORY_H help This option extends the physical to virtual translation patching to allow physical memory down to a theoretical minimum of 64K boundaries. Please provide the physical address corresponding to the location of main memory in your system. source "init/Kconfig" Loading Loading @@ -247,6 +257,7 @@ config ARCH_INTEGRATOR select GENERIC_CLOCKEVENTS select PLAT_VERSATILE select PLAT_VERSATILE_FPGA_IRQ select NEED_MACH_MEMORY_H help Support for ARM's Integrator platform. Loading @@ -262,6 +273,7 @@ config ARCH_REALVIEW select PLAT_VERSATILE_CLCD select ARM_TIMER_SP804 select GPIO_PL061 if GPIOLIB select NEED_MACH_MEMORY_H help This enables support for ARM Ltd RealView boards. Loading Loading @@ -302,7 +314,6 @@ config ARCH_AT91 select ARCH_REQUIRE_GPIOLIB select HAVE_CLK select CLKDEV_LOOKUP select ARM_PATCH_PHYS_VIRT if MMU help This enables support for systems based on the Atmel AT91RM9200, AT91SAM9 and AT91CAP9 processors. Loading @@ -323,6 +334,7 @@ config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x-based" select CPU_ARM720T select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Cirrus Logic 711x/721x based boards. Loading Loading @@ -363,6 +375,7 @@ config ARCH_EBSA110 select ISA select NO_IOPORT select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help This is an evaluation board for the StrongARM processor available from Digital. It has limited hardware on-board, including an Loading @@ -378,6 +391,7 @@ config ARCH_EP93XX select ARCH_REQUIRE_GPIOLIB select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_USES_GETTIMEOFFSET select NEED_MEMORY_H help This enables support for the Cirrus EP93xx series of CPUs. Loading @@ -386,6 +400,7 @@ config ARCH_FOOTBRIDGE select CPU_SA110 select FOOTBRIDGE select GENERIC_CLOCKEVENTS select NEED_MACH_MEMORY_H help Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. Loading Loading @@ -435,6 +450,7 @@ config ARCH_IOP13XX select PCI select ARCH_SUPPORTS_MSI select VMSPLIT_1G select NEED_MACH_MEMORY_H help Support for Intel's IOP13XX (XScale) family of processors. Loading Loading @@ -465,6 +481,7 @@ config ARCH_IXP23XX select CPU_XSC3 select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Intel's IXP23xx (XScale) family of processors. Loading @@ -474,6 +491,7 @@ config ARCH_IXP2000 select CPU_XSCALE select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Intel's IXP2400/2800 (XScale) family of processors. Loading Loading @@ -567,6 +585,7 @@ config ARCH_KS8695 select CPU_ARM922T select ARCH_REQUIRE_GPIOLIB select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based System-on-Chip devices. Loading Loading @@ -658,6 +677,7 @@ config ARCH_SHMOBILE select SPARSE_IRQ select MULTI_IRQ_HANDLER select PM_GENERIC_DOMAINS if PM select NEED_MACH_MEMORY_H help Support for Renesas's SH-Mobile and R-Mobile ARM platforms. Loading @@ -672,6 +692,7 @@ config ARCH_RPC select NO_IOPORT select ARCH_SPARSEMEM_ENABLE select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help On the Acorn Risc-PC, Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. Loading @@ -690,6 +711,7 @@ config ARCH_SA1100 select HAVE_SCHED_CLOCK select TICK_ONESHOT select ARCH_REQUIRE_GPIOLIB select NEED_MACH_MEMORY_H help Support for StrongARM 11x0 based boards. Loading Loading @@ -782,6 +804,7 @@ config ARCH_S5PV210 select HAVE_S3C2410_I2C if I2C select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_WATCHDOG if WATCHDOG select NEED_MACH_MEMORY_H help Samsung S5PV210/S5PC110 series based systems Loading @@ -798,6 +821,7 @@ config ARCH_EXYNOS4 select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG select NEED_MACH_MEMORY_H help Samsung EXYNOS4 series based systems Loading @@ -809,6 +833,7 @@ config ARCH_SHARK select ZONE_DMA select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for the StrongARM based Digital DNARD machine, also known as "Shark" (<http://www.shark-linux.de/shark.html>). Loading Loading @@ -836,6 +861,7 @@ config ARCH_U300 select CLKDEV_LOOKUP select HAVE_MACH_CLKDEV select GENERIC_GPIO select NEED_MACH_MEMORY_H help Support for ST-Ericsson U300 series mobile platforms. Loading arch/arm/Makefile +3 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,9 @@ textofs-$(CONFIG_PM_H1940) := 0x00108000 ifeq ($(CONFIG_ARCH_SA1100),y) textofs-$(CONFIG_SA1111) := 0x00208000 endif textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000 textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000 textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 # Machine directory name. This list is sorted alphanumerically # by CONFIG_* macro name. Loading arch/arm/common/Kconfig +1 −0 Original line number Diff line number Diff line config ARM_GIC select IRQ_DOMAIN bool config ARM_VIC Loading arch/arm/common/gic.c +128 −45 Original line number Diff line number Diff line Loading @@ -24,11 +24,20 @@ */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/err.h> #include <linux/export.h> #include <linux/list.h> #include <linux/smp.h> #include <linux/cpu_pm.h> #include <linux/cpumask.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <asm/irq.h> #include <asm/mach/irq.h> Loading Loading @@ -72,8 +81,7 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d) static inline unsigned int gic_irq(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); return d->irq - gic_data->irq_offset; return d->hwirq; } /* Loading @@ -81,7 +89,7 @@ static inline unsigned int gic_irq(struct irq_data *d) */ static void gic_mask_irq(struct irq_data *d) { u32 mask = 1 << (d->irq % 32); u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); Loading @@ -92,7 +100,7 @@ static void gic_mask_irq(struct irq_data *d) static void gic_unmask_irq(struct irq_data *d) { u32 mask = 1 << (d->irq % 32); u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); if (gic_arch_extn.irq_unmask) Loading Loading @@ -173,7 +181,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); unsigned int shift = (d->irq % 4) * 8; unsigned int shift = (gic_irq(d) % 4) * 8; unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); u32 val, mask, bit; Loading Loading @@ -224,7 +232,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (gic_irq == 1023) goto out; cascade_irq = gic_irq + chip_data->irq_offset; cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) do_bad_IRQ(cascade_irq, desc); else Loading Loading @@ -256,11 +264,12 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) irq_set_chained_handler(irq, gic_handle_cascade_irq); } static void __init gic_dist_init(struct gic_chip_data *gic, unsigned int irq_start) static void __init gic_dist_init(struct gic_chip_data *gic) { unsigned int gic_irqs, irq_limit, i; unsigned int i, irq; u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; struct irq_domain *domain = &gic->domain; void __iomem *base = gic->dist_base; u32 cpu = 0; Loading @@ -274,17 +283,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic, writel_relaxed(0, base + GIC_DIST_CTRL); /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; gic->gic_irqs = gic_irqs; /* * Set all global interrupts to be level triggered, active low. */ Loading @@ -310,20 +308,21 @@ static void __init gic_dist_init(struct gic_chip_data *gic, for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); /* * Limit number of interrupts registered to the platform maximum */ irq_limit = gic->irq_offset + gic_irqs; if (WARN_ON(irq_limit > NR_IRQS)) irq_limit = NR_IRQS; /* * Setup the Linux IRQ subsystem. */ for (i = irq_start; i < irq_limit; i++) { irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); irq_set_chip_data(i, gic); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); irq_domain_for_each_irq(domain, i, irq) { if (i < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &gic_chip, handle_percpu_devid_irq); set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); } else { irq_set_chip_and_handler(irq, &gic_chip, handle_fasteoi_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } irq_set_chip_data(irq, gic); } writel_relaxed(1, base + GIC_DIST_CTRL); Loading Loading @@ -535,23 +534,85 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif void __init gic_init(unsigned int gic_nr, unsigned int irq_start, #ifdef CONFIG_OF static int gic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { if (d->of_node != controller) return -EINVAL; if (intsize < 3) return -EINVAL; /* Get the interrupt number and add 16 to skip over SGIs */ *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ if (!intspec[0]) *out_hwirq += 16; *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } #endif const struct irq_domain_ops gic_irq_domain_ops = { #ifdef CONFIG_OF .dt_translate = gic_irq_domain_dt_translate, #endif }; void __init gic_init(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { struct gic_chip_data *gic; struct irq_domain *domain; int gic_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); gic = &gic_data[gic_nr]; domain = &gic->domain; gic->dist_base = dist_base; gic->cpu_base = cpu_base; gic->irq_offset = (irq_start - 1) & ~31; if (gic_nr == 0) /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ if (gic_nr == 0) { gic_cpu_base_addr = cpu_base; domain->hwirq_base = 16; if (irq_start > 0) irq_start = (irq_start & ~31) + 16; } else domain->hwirq_base = 32; /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; gic->gic_irqs = gic_irqs; domain->nr_irq = gic_irqs - domain->hwirq_base; domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, numa_node_id()); if (IS_ERR_VALUE(domain->irq_base)) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); domain->irq_base = irq_start; } domain->priv = gic; domain->ops = &gic_irq_domain_ops; irq_domain_add(domain); gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic, irq_start); gic_dist_init(gic); gic_cpu_init(gic); gic_pm_init(gic); } Loading @@ -563,16 +624,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr) gic_cpu_init(&gic_data[gic_nr]); } void __cpuinit gic_enable_ppi(unsigned int irq) { unsigned long flags; local_irq_save(flags); irq_set_status_flags(irq, IRQ_NOPROBE); gic_unmask_irq(irq_get_irq_data(irq)); local_irq_restore(flags); } #ifdef CONFIG_SMP void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { Loading @@ -593,3 +644,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); } #endif #ifdef CONFIG_OF static int gic_cnt __initdata = 0; int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *cpu_base; void __iomem *dist_base; int irq; struct irq_domain *domain = &gic_data[gic_cnt].domain; if (WARN_ON(!node)) return -ENODEV; dist_base = of_iomap(node, 0); WARN(!dist_base, "unable to map gic dist registers\n"); cpu_base = of_iomap(node, 1); WARN(!cpu_base, "unable to map gic cpu registers\n"); domain->of_node = of_node_get(node); gic_init(gic_cnt, -1, dist_base, cpu_base); if (parent) { irq = irq_of_parse_and_map(node, 0); gic_cascade_irq(gic_cnt, irq); } gic_cnt++; return 0; } #endif Loading
Documentation/devicetree/bindings/arm/gic.txt 0 → 100644 +55 −0 Original line number Diff line number Diff line * ARM Generic Interrupt Controller ARM SMP cores are often associated with a GIC, providing per processor interrupts (PPI), shared processor interrupts (SPI) and software generated interrupts (SGI). Primary GIC is attached directly to the CPU and typically has PPIs and SGIs. Secondary GICs are cascaded into the upward interrupt controller and do not have PPIs or SGIs. Main node required properties: - compatible : should be one of: "arm,cortex-a9-gic" "arm,arm11mp-gic" - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an interrupt source. The type shall be a <u32> and the value shall be 3. The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI interrupts. The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the range [0-15]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags. 1 = low-to-high edge triggered 2 = high-to-low edge triggered 4 = active high level-sensitive 8 = active low level-sensitive bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of the 8 possible cpus attached to the GIC. A bit set to '1' indicated the interrupt is wired to that CPU. Only valid for PPI interrupts. - reg : Specifies base physical address(s) and size of the GIC registers. The first region is the GIC distributor register base and size. The 2nd region is the GIC cpu interface register base and size. Optional - interrupts : Interrupt source of the parent interrupt controller. Only present on secondary GICs. Example: intc: interrupt-controller@fff11000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; };
arch/arm/Kconfig +36 −10 Original line number Diff line number Diff line Loading @@ -196,7 +196,8 @@ config VECTORS_BASE The base address of exception vectors. config ARM_PATCH_PHYS_VIRT bool "Patch physical to virtual translations at runtime" bool "Patch physical to virtual translations at runtime" if EMBEDDED default y depends on !XIP_KERNEL && MMU depends on !ARCH_REALVIEW || !SPARSEMEM help Loading @@ -205,16 +206,25 @@ config ARM_PATCH_PHYS_VIRT kernel in system memory. This can only be used with non-XIP MMU kernels where the base of physical memory is at a 16MB boundary, or theoretically 64K for the MSM machine class. of physical memory is at a 16MB boundary. config ARM_PATCH_PHYS_VIRT_16BIT def_bool y depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM Only disable this option if you know that you do not require this feature (eg, building a kernel for a single machine) and you need to shrink the kernel to the minimal size. config NEED_MACH_MEMORY_H bool help Select this when mach/memory.h is required to provide special definitions for this platform. The need for mach/memory.h should be avoided when possible. config PHYS_OFFSET hex "Physical address of main memory" depends on !ARM_PATCH_PHYS_VIRT && !NEED_MACH_MEMORY_H help This option extends the physical to virtual translation patching to allow physical memory down to a theoretical minimum of 64K boundaries. Please provide the physical address corresponding to the location of main memory in your system. source "init/Kconfig" Loading Loading @@ -247,6 +257,7 @@ config ARCH_INTEGRATOR select GENERIC_CLOCKEVENTS select PLAT_VERSATILE select PLAT_VERSATILE_FPGA_IRQ select NEED_MACH_MEMORY_H help Support for ARM's Integrator platform. Loading @@ -262,6 +273,7 @@ config ARCH_REALVIEW select PLAT_VERSATILE_CLCD select ARM_TIMER_SP804 select GPIO_PL061 if GPIOLIB select NEED_MACH_MEMORY_H help This enables support for ARM Ltd RealView boards. Loading Loading @@ -302,7 +314,6 @@ config ARCH_AT91 select ARCH_REQUIRE_GPIOLIB select HAVE_CLK select CLKDEV_LOOKUP select ARM_PATCH_PHYS_VIRT if MMU help This enables support for systems based on the Atmel AT91RM9200, AT91SAM9 and AT91CAP9 processors. Loading @@ -323,6 +334,7 @@ config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x-based" select CPU_ARM720T select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Cirrus Logic 711x/721x based boards. Loading Loading @@ -363,6 +375,7 @@ config ARCH_EBSA110 select ISA select NO_IOPORT select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help This is an evaluation board for the StrongARM processor available from Digital. It has limited hardware on-board, including an Loading @@ -378,6 +391,7 @@ config ARCH_EP93XX select ARCH_REQUIRE_GPIOLIB select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_USES_GETTIMEOFFSET select NEED_MEMORY_H help This enables support for the Cirrus EP93xx series of CPUs. Loading @@ -386,6 +400,7 @@ config ARCH_FOOTBRIDGE select CPU_SA110 select FOOTBRIDGE select GENERIC_CLOCKEVENTS select NEED_MACH_MEMORY_H help Support for systems based on the DC21285 companion chip ("FootBridge"), such as the Simtec CATS and the Rebel NetWinder. Loading Loading @@ -435,6 +450,7 @@ config ARCH_IOP13XX select PCI select ARCH_SUPPORTS_MSI select VMSPLIT_1G select NEED_MACH_MEMORY_H help Support for Intel's IOP13XX (XScale) family of processors. Loading Loading @@ -465,6 +481,7 @@ config ARCH_IXP23XX select CPU_XSC3 select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Intel's IXP23xx (XScale) family of processors. Loading @@ -474,6 +491,7 @@ config ARCH_IXP2000 select CPU_XSCALE select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Intel's IXP2400/2800 (XScale) family of processors. Loading Loading @@ -567,6 +585,7 @@ config ARCH_KS8695 select CPU_ARM922T select ARCH_REQUIRE_GPIOLIB select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based System-on-Chip devices. Loading Loading @@ -658,6 +677,7 @@ config ARCH_SHMOBILE select SPARSE_IRQ select MULTI_IRQ_HANDLER select PM_GENERIC_DOMAINS if PM select NEED_MACH_MEMORY_H help Support for Renesas's SH-Mobile and R-Mobile ARM platforms. Loading @@ -672,6 +692,7 @@ config ARCH_RPC select NO_IOPORT select ARCH_SPARSEMEM_ENABLE select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help On the Acorn Risc-PC, Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. Loading @@ -690,6 +711,7 @@ config ARCH_SA1100 select HAVE_SCHED_CLOCK select TICK_ONESHOT select ARCH_REQUIRE_GPIOLIB select NEED_MACH_MEMORY_H help Support for StrongARM 11x0 based boards. Loading Loading @@ -782,6 +804,7 @@ config ARCH_S5PV210 select HAVE_S3C2410_I2C if I2C select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_WATCHDOG if WATCHDOG select NEED_MACH_MEMORY_H help Samsung S5PV210/S5PC110 series based systems Loading @@ -798,6 +821,7 @@ config ARCH_EXYNOS4 select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG select NEED_MACH_MEMORY_H help Samsung EXYNOS4 series based systems Loading @@ -809,6 +833,7 @@ config ARCH_SHARK select ZONE_DMA select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help Support for the StrongARM based Digital DNARD machine, also known as "Shark" (<http://www.shark-linux.de/shark.html>). Loading Loading @@ -836,6 +861,7 @@ config ARCH_U300 select CLKDEV_LOOKUP select HAVE_MACH_CLKDEV select GENERIC_GPIO select NEED_MACH_MEMORY_H help Support for ST-Ericsson U300 series mobile platforms. Loading
arch/arm/Makefile +3 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,9 @@ textofs-$(CONFIG_PM_H1940) := 0x00108000 ifeq ($(CONFIG_ARCH_SA1100),y) textofs-$(CONFIG_SA1111) := 0x00208000 endif textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000 textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000 textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 # Machine directory name. This list is sorted alphanumerically # by CONFIG_* macro name. Loading
arch/arm/common/Kconfig +1 −0 Original line number Diff line number Diff line config ARM_GIC select IRQ_DOMAIN bool config ARM_VIC Loading
arch/arm/common/gic.c +128 −45 Original line number Diff line number Diff line Loading @@ -24,11 +24,20 @@ */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/err.h> #include <linux/export.h> #include <linux/list.h> #include <linux/smp.h> #include <linux/cpu_pm.h> #include <linux/cpumask.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> #include <asm/irq.h> #include <asm/mach/irq.h> Loading Loading @@ -72,8 +81,7 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d) static inline unsigned int gic_irq(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); return d->irq - gic_data->irq_offset; return d->hwirq; } /* Loading @@ -81,7 +89,7 @@ static inline unsigned int gic_irq(struct irq_data *d) */ static void gic_mask_irq(struct irq_data *d) { u32 mask = 1 << (d->irq % 32); u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); Loading @@ -92,7 +100,7 @@ static void gic_mask_irq(struct irq_data *d) static void gic_unmask_irq(struct irq_data *d) { u32 mask = 1 << (d->irq % 32); u32 mask = 1 << (gic_irq(d) % 32); spin_lock(&irq_controller_lock); if (gic_arch_extn.irq_unmask) Loading Loading @@ -173,7 +181,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); unsigned int shift = (d->irq % 4) * 8; unsigned int shift = (gic_irq(d) % 4) * 8; unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); u32 val, mask, bit; Loading Loading @@ -224,7 +232,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (gic_irq == 1023) goto out; cascade_irq = gic_irq + chip_data->irq_offset; cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) do_bad_IRQ(cascade_irq, desc); else Loading Loading @@ -256,11 +264,12 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) irq_set_chained_handler(irq, gic_handle_cascade_irq); } static void __init gic_dist_init(struct gic_chip_data *gic, unsigned int irq_start) static void __init gic_dist_init(struct gic_chip_data *gic) { unsigned int gic_irqs, irq_limit, i; unsigned int i, irq; u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; struct irq_domain *domain = &gic->domain; void __iomem *base = gic->dist_base; u32 cpu = 0; Loading @@ -274,17 +283,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic, writel_relaxed(0, base + GIC_DIST_CTRL); /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; gic->gic_irqs = gic_irqs; /* * Set all global interrupts to be level triggered, active low. */ Loading @@ -310,20 +308,21 @@ static void __init gic_dist_init(struct gic_chip_data *gic, for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); /* * Limit number of interrupts registered to the platform maximum */ irq_limit = gic->irq_offset + gic_irqs; if (WARN_ON(irq_limit > NR_IRQS)) irq_limit = NR_IRQS; /* * Setup the Linux IRQ subsystem. */ for (i = irq_start; i < irq_limit; i++) { irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); irq_set_chip_data(i, gic); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); irq_domain_for_each_irq(domain, i, irq) { if (i < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &gic_chip, handle_percpu_devid_irq); set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); } else { irq_set_chip_and_handler(irq, &gic_chip, handle_fasteoi_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } irq_set_chip_data(irq, gic); } writel_relaxed(1, base + GIC_DIST_CTRL); Loading Loading @@ -535,23 +534,85 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif void __init gic_init(unsigned int gic_nr, unsigned int irq_start, #ifdef CONFIG_OF static int gic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) { if (d->of_node != controller) return -EINVAL; if (intsize < 3) return -EINVAL; /* Get the interrupt number and add 16 to skip over SGIs */ *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ if (!intspec[0]) *out_hwirq += 16; *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } #endif const struct irq_domain_ops gic_irq_domain_ops = { #ifdef CONFIG_OF .dt_translate = gic_irq_domain_dt_translate, #endif }; void __init gic_init(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { struct gic_chip_data *gic; struct irq_domain *domain; int gic_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); gic = &gic_data[gic_nr]; domain = &gic->domain; gic->dist_base = dist_base; gic->cpu_base = cpu_base; gic->irq_offset = (irq_start - 1) & ~31; if (gic_nr == 0) /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ if (gic_nr == 0) { gic_cpu_base_addr = cpu_base; domain->hwirq_base = 16; if (irq_start > 0) irq_start = (irq_start & ~31) + 16; } else domain->hwirq_base = 32; /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; if (gic_irqs > 1020) gic_irqs = 1020; gic->gic_irqs = gic_irqs; domain->nr_irq = gic_irqs - domain->hwirq_base; domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, numa_node_id()); if (IS_ERR_VALUE(domain->irq_base)) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); domain->irq_base = irq_start; } domain->priv = gic; domain->ops = &gic_irq_domain_ops; irq_domain_add(domain); gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic, irq_start); gic_dist_init(gic); gic_cpu_init(gic); gic_pm_init(gic); } Loading @@ -563,16 +624,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr) gic_cpu_init(&gic_data[gic_nr]); } void __cpuinit gic_enable_ppi(unsigned int irq) { unsigned long flags; local_irq_save(flags); irq_set_status_flags(irq, IRQ_NOPROBE); gic_unmask_irq(irq_get_irq_data(irq)); local_irq_restore(flags); } #ifdef CONFIG_SMP void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { Loading @@ -593,3 +644,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); } #endif #ifdef CONFIG_OF static int gic_cnt __initdata = 0; int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *cpu_base; void __iomem *dist_base; int irq; struct irq_domain *domain = &gic_data[gic_cnt].domain; if (WARN_ON(!node)) return -ENODEV; dist_base = of_iomap(node, 0); WARN(!dist_base, "unable to map gic dist registers\n"); cpu_base = of_iomap(node, 1); WARN(!cpu_base, "unable to map gic cpu registers\n"); domain->of_node = of_node_get(node); gic_init(gic_cnt, -1, dist_base, cpu_base); if (parent) { irq = irq_of_parse_and_map(node, 0); gic_cascade_irq(gic_cnt, irq); } gic_cnt++; return 0; } #endif