The cns3xxx uses irq61 for pcie0_intr which in the case of a PCIe-to-PCI bridge ends up combining INTA/B/C/D on a single ARM CPU interrupt. This is not optimal when you have multiple cores. To overcome this limitation an enhancement had been made on newer Laguna PCB's that support miniPCI cards to route the INTA/B/C/D signals to unique external ARM CPU interrupts which can help balance CPU core utilization and in some cases increase overall system performance or responsiveness.
For more details see: http://trac.gateworks.com/wiki/multicoreprocessing#PCIInterruptsteering Signed-off-by: Tim Harvey <thar...@gateworks.com> --- .../patches-3.8/066-pci_isolated_interrupts.patch | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 target/linux/cns3xxx/patches-3.8/066-pci_isolated_interrupts.patch diff --git a/target/linux/cns3xxx/patches-3.8/066-pci_isolated_interrupts.patch b/target/linux/cns3xxx/patches-3.8/066-pci_isolated_interrupts.patch new file mode 100644 index 0000000..5bac43d --- /dev/null +++ b/target/linux/cns3xxx/patches-3.8/066-pci_isolated_interrupts.patch @@ -0,0 +1,209 @@ +--- a/arch/arm/mach-cns3xxx/cns3420vb.c ++++ b/arch/arm/mach-cns3xxx/cns3420vb.c +@@ -276,7 +276,7 @@ static int __init cns3420vb_pcie_init(vo + if (!machine_is_cns3420vb()) + return 0; + +- return cns3xxx_pcie_init(); ++ return cns3xxx_pcie_init(NULL, NULL); + } + subsys_initcall(cns3420vb_pcie_init); + +--- a/arch/arm/mach-cns3xxx/core.h ++++ b/arch/arm/mach-cns3xxx/core.h +@@ -17,7 +17,7 @@ extern void cns3xxx_pcie_iotable_init(vo + + void __init cns3xxx_common_init(void); + void __init cns3xxx_init_irq(void); +-int __init cns3xxx_pcie_init(void); ++int __init cns3xxx_pcie_init(int *pcie0_irqs, int *pcie1_irqs); + void cns3xxx_power_off(void); + void cns3xxx_restart(char, const char *); + +--- a/arch/arm/mach-cns3xxx/laguna.c ++++ b/arch/arm/mach-cns3xxx/laguna.c +@@ -21,6 +21,7 @@ + #include <linux/kernel.h> + #include <linux/compiler.h> + #include <linux/io.h> ++#include <linux/irq.h> + #include <linux/gpio.h> + #include <linux/dma-mapping.h> + #include <linux/serial_core.h> +@@ -39,6 +40,7 @@ + #include <linux/pps-gpio.h> + #include <linux/usb/ehci_pdriver.h> + #include <linux/usb/ohci_pdriver.h> ++#include <asm/hardware/gic.h> + #include <asm/setup.h> + #include <asm/mach-types.h> + #include <asm/mach/arch.h> +@@ -808,12 +810,53 @@ static int laguna_register_gpio(struct g + return ret; + } + ++static int cns3xxx_pciextirq = 1; ++ ++static int __init cns3xxx_pciextirq_disable(char *s) ++{ ++ cns3xxx_pciextirq = 0; ++ return 1; ++} ++__setup("noextirq", cns3xxx_pciextirq_disable); ++ + static int __init laguna_pcie_init(void) + { + if (!machine_is_gw2388()) + return 0; + +- return cns3xxx_pcie_init(); ++ if (cns3xxx_pciextirq) { ++ u32 __iomem *mem; ++ u32 reg; ++ int pcie0_irqs[] = { ++ IRQ_CNS3XXX_EXTERNAL_PIN0, ++ IRQ_CNS3XXX_EXTERNAL_PIN1, ++ IRQ_CNS3XXX_EXTERNAL_PIN2, ++ 154, ++ }; ++ ++ /* ++ * Detect board revision: ++ * GW2388-4-G+ GPIOB[26:29] INTA/B/C/D thus will be high ++ * GW2388-4-F- GPIOB[16:19] INTA/B/C/D thus will be high ++ */ ++ mem = (void __iomem *)(CNS3XXX_GPIOB_BASE_VIRT + 0x0004); ++ reg = __raw_readl(mem) >> 16; ++ switch (reg & 0x3c00) { ++ case 0x0408: /* GW2388-4-H */ ++ pcie0_irqs[0] = IRQ_CNS3XXX_PCIE0_DEVICE; ++ pcie0_irqs[1] = IRQ_CNS3XXX_PCIE0_DEVICE; ++ pcie0_irqs[2] = IRQ_CNS3XXX_PCIE0_DEVICE; ++ case 0x0400: /* GW2388-4-G (mod) */ ++ printk("%s: using external-irq\n", __func__); ++ return cns3xxx_pcie_init(pcie0_irqs, NULL); ++ break; ++ case 0x3c00: /* GW2388-4-G */ ++ default: ++ break; ++ } ++ } ++ ++ return cns3xxx_pcie_init(NULL, NULL); + } + subsys_initcall(laguna_pcie_init); + +@@ -828,8 +871,30 @@ static int __init laguna_model_setup(voi + printk("Running on Gateworks Laguna %s\n", laguna_info.model); + cns3xxx_gpio_init( 0, 32, CNS3XXX_GPIOA_BASE_VIRT, IRQ_CNS3XXX_GPIOA, + NR_IRQS_CNS3XXX); +- cns3xxx_gpio_init(32, 32, CNS3XXX_GPIOB_BASE_VIRT, IRQ_CNS3XXX_GPIOB, +- NR_IRQS_CNS3XXX + 32); ++ ++ if (cns3xxx_pciextirq) { ++ /* ++ * if pcie external interrupts are supported and desired ++ * configure IRQ types and configure pin function. ++ */ ++ mem = (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0018); ++ reg = __raw_readl(mem); ++ /* GPIO26 is gpio, EXT_INT[0:2] not gpio func */ ++ reg &= ~0x3c000000; ++ reg |= 0x38000000; ++ __raw_writel(reg, mem); ++ ++ cns3xxx_gpio_init(32, 32, CNS3XXX_GPIOB_BASE_VIRT, ++ IRQ_CNS3XXX_GPIOB, NR_IRQS_CNS3XXX + 32); ++ ++ irq_set_irq_type(154, IRQ_TYPE_LEVEL_LOW); ++ irq_set_irq_type(93, IRQ_TYPE_LEVEL_HIGH); ++ irq_set_irq_type(94, IRQ_TYPE_LEVEL_HIGH); ++ irq_set_irq_type(95, IRQ_TYPE_LEVEL_HIGH); ++ } else { ++ cns3xxx_gpio_init(32, 32, CNS3XXX_GPIOB_BASE_VIRT, ++ IRQ_CNS3XXX_GPIOB, NR_IRQS_CNS3XXX + 32); ++ } + + if (strncmp(laguna_info.model, "GW", 2) == 0) { + if (laguna_info.config_bitmap & ETH0_LOAD) +--- a/arch/arm/mach-cns3xxx/pcie.c ++++ b/arch/arm/mach-cns3xxx/pcie.c +@@ -18,6 +18,7 @@ + #include <linux/io.h> + #include <linux/ioport.h> + #include <linux/interrupt.h> ++#include <linux/irq.h> + #include <linux/ptrace.h> + #include <asm/mach/map.h> + #include <mach/cns3xxx.h> +@@ -32,7 +33,7 @@ enum cns3xxx_access_type { + + struct cns3xxx_pcie { + struct map_desc cfg_bases[CNS3XXX_NUM_ACCESS_TYPES]; +- unsigned int irqs[2]; ++ unsigned int irqs[6]; + struct resource res_io; + struct resource res_mem; + struct hw_pci hw_pci; +@@ -255,7 +256,7 @@ static struct pci_ops cns3xxx_pcie_ops = + static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) + { + struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev); +- int irq = cnspci->irqs[slot]; ++ int irq = cnspci->irqs[slot+pin-1]; + + pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n", + pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn), +@@ -298,7 +299,12 @@ static struct cns3xxx_pcie cns3xxx_pcie[ + .end = CNS3XXX_PCIE0_MEM_BASE + SZ_16M - 1, + .flags = IORESOURCE_MEM, + }, +- .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, ++ .irqs = { IRQ_CNS3XXX_PCIE0_RC, ++ IRQ_CNS3XXX_PCIE0_DEVICE, ++ IRQ_CNS3XXX_PCIE0_DEVICE, ++ IRQ_CNS3XXX_PCIE0_DEVICE, ++ IRQ_CNS3XXX_PCIE0_DEVICE, ++ }, + .hw_pci = { + .domain = 0, + .nr_controllers = 1, +@@ -340,7 +346,13 @@ static struct cns3xxx_pcie cns3xxx_pcie[ + .end = CNS3XXX_PCIE1_MEM_BASE + SZ_16M - 1, + .flags = IORESOURCE_MEM, + }, +- .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, ++ .irqs = { ++ IRQ_CNS3XXX_PCIE1_RC, ++ IRQ_CNS3XXX_PCIE1_DEVICE, ++ IRQ_CNS3XXX_PCIE1_DEVICE, ++ IRQ_CNS3XXX_PCIE1_DEVICE, ++ IRQ_CNS3XXX_PCIE1_DEVICE, ++ }, + .hw_pci = { + .domain = 1, + .nr_controllers = 1, +@@ -460,13 +472,22 @@ void __init cns3xxx_pcie_iotable_init() + } + } + +-int __init cns3xxx_pcie_init(void) ++int __init cns3xxx_pcie_init(int *pcie0_irqs, int *pcie1_irqs) + { + int i; + + pcibios_min_io = 0; + pcibios_min_mem = 0; + ++ if (pcie0_irqs) { ++ for (i = 0; i < 4; i++) ++ cns3xxx_pcie[0].irqs[i+1] = pcie0_irqs[i]; ++ } ++ if (pcie1_irqs) { ++ for (i = 0; i < 4; i++) ++ cns3xxx_pcie[1].irqs[i+1] = pcie1_irqs[i]; ++ } ++ + hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0, + "imprecise external abort"); + -- 1.8.3.2 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel