Pull irq updates from Thomas Gleixner: "The irq department provides: - a major update to the auto affinity management code, which is used by multi-queue devices - move of the microblaze irq chip driver into the common driver code so it can be shared between microblaze, powerpc and MIPS - a series of updates to the ARM GICV3 interrupt controller - the usual pile of fixes and small improvements all over the place" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits) powerpc/virtex: Use generic xilinx irqchip driver irqchip/xilinx: Try to fall back if xlnx,kind-of-intr not provided irqchip/xilinx: Add support for parent intc irqchip/xilinx: Rename get_irq to xintc_get_irq irqchip/xilinx: Restructure and use jump label api irqchip/xilinx: Clean up print messages microblaze/irqchip: Move intc driver to irqchip ARM: virt: Select ARM_GIC_V3_ITS ARM: gic-v3-its: Add 32bit support to GICv3 ITS irqchip/gic-v3-its: Specialise readq and writeq accesses irqchip/gic-v3-its: Specialise flush_dcache operation irqchip/gic-v3-its: Narrow down Entry Size when used as a divider irqchip/gic-v3-its: Change unsigned types for AArch32 compatibility irqchip/gic-v3: Use nops macro for Cavium ThunderX erratum 23154 irqchip/gic-v3: Convert arm64 GIC accessors to {read,write}_sysreg_s genirq/msi: Drop artificial PCI dependency irqchip/bcm7038-l1: Implement irq_cpu_offline() callback genirq/affinity: Use default affinity mask for reserved vectors genirq/affinity: Take reserved vectors into account when spreading irqs PCI: Remove the irq_affinity mask from struct pci_dev ...
Unified · Split
| @@ -703,6 +703,7 @@ config ARCH_VIRT · 702 unmodified lines | ||
| 703 | 703 | select ARM_GIC |
| 704 | 704 | select ARM_GIC_V2M if PCI |
| 705 | 705 | select ARM_GIC_V3 |
| 706 | + select ARM_GIC_V3_ITS if PCI | |
| 706 | 707 | select ARM_PSCI |
| 707 | 708 | select HAVE_ARM_ARCH_TIMER |
| 708 | 709 | |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | |
| 23 | 23 | #include <linux/io.h> |
| 24 | 24 | #include <asm/barrier.h> |
| 25 | +#include <asm/cacheflush.h> | |
| 25 | 26 | #include <asm/cp15.h> |
| 26 | 27 | |
| 27 | 28 | #define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) |
| @@ -230,19 +231,14 @@ static inline void gic_write_bpr1(u32 val) · 202 unmodified lines | ||
| 230 | 231 | * AArch32, since the syndrome register doesn't provide any information for |
| 231 | 232 | * them. |
| 232 | 233 | * Consequently, the following IO helpers use 32bit accesses. |
| 233 | − * | |
| 234 | − * There are only two registers that need 64bit accesses in this driver: | |
| 235 | − * - GICD_IROUTERn, contain the affinity values associated to each interrupt. | |
| 236 | − * The upper-word (aff3) will always be 0, so there is no need for a lock. | |
| 237 | − * - GICR_TYPER is an ID register and doesn't need atomicity. | |
| 238 | 234 | */ |
| 239 | −static inline void gic_write_irouter(u64 val, volatile void __iomem *addr) | |
| 235 | +static inline void __gic_writeq_nonatomic(u64 val, volatile void __iomem *addr) | |
| 240 | 236 | { |
| 241 | 237 | writel_relaxed((u32)val, addr); |
| 242 | 238 | writel_relaxed((u32)(val >> 32), addr + 4); |
| 243 | 239 | } |
| 244 | 240 | |
| 245 | −static inline u64 gic_read_typer(const volatile void __iomem *addr) | |
| 241 | +static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr) | |
| 246 | 242 | { |
| 247 | 243 | u64 val; |
| 248 | 244 | |
| @@ -251,5 +247,49 @@ static inline u64 gic_read_typer(const volatile void __iomem *addr) · 2 unmodified lines | ||
| 251 | 247 | return val; |
| 252 | 248 | } |
| 253 | 249 | |
| 250 | +#define gic_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) | |
| 251 | + | |
| 252 | +/* | |
| 253 | + * GICD_IROUTERn, contain the affinity values associated to each interrupt. | |
| 254 | + * The upper-word (aff3) will always be 0, so there is no need for a lock. | |
| 255 | + */ | |
| 256 | +#define gic_write_irouter(v, c) __gic_writeq_nonatomic(v, c) | |
| 257 | + | |
| 258 | +/* | |
| 259 | + * GICR_TYPER is an ID register and doesn't need atomicity. | |
| 260 | + */ | |
| 261 | +#define gic_read_typer(c) __gic_readq_nonatomic(c) | |
| 262 | + | |
| 263 | +/* | |
| 264 | + * GITS_BASER - hi and lo bits may be accessed independently. | |
| 265 | + */ | |
| 266 | +#define gits_read_baser(c) __gic_readq_nonatomic(c) | |
| 267 | +#define gits_write_baser(v, c) __gic_writeq_nonatomic(v, c) | |
| 268 | + | |
| 269 | +/* | |
| 270 | + * GICR_PENDBASER and GICR_PROPBASE are changed with LPIs disabled, so they | |
| 271 | + * won't be being used during any updates and can be changed non-atomically | |
| 272 | + */ | |
| 273 | +#define gicr_read_propbaser(c) __gic_readq_nonatomic(c) | |
| 274 | +#define gicr_write_propbaser(v, c) __gic_writeq_nonatomic(v, c) | |
| 275 | +#define gicr_read_pendbaser(c) __gic_readq_nonatomic(c) | |
| 276 | +#define gicr_write_pendbaser(v, c) __gic_writeq_nonatomic(v, c) | |
| 277 | + | |
| 278 | +/* | |
| 279 | + * GITS_TYPER is an ID register and doesn't need atomicity. | |
| 280 | + */ | |
| 281 | +#define gits_read_typer(c) __gic_readq_nonatomic(c) | |
| 282 | + | |
| 283 | +/* | |
| 284 | + * GITS_CBASER - hi and lo bits may be accessed independently. | |
| 285 | + */ | |
| 286 | +#define gits_read_cbaser(c) __gic_readq_nonatomic(c) | |
| 287 | +#define gits_write_cbaser(v, c) __gic_writeq_nonatomic(v, c) | |
| 288 | + | |
| 289 | +/* | |
| 290 | + * GITS_CWRITER - hi and lo bits may be accessed independently. | |
| 291 | + */ | |
| 292 | +#define gits_write_cwriter(v, c) __gic_writeq_nonatomic(v, c) | |
| 293 | + | |
| 254 | 294 | #endif /* !__ASSEMBLY__ */ |
| 255 | 295 | #endif /* !__ASM_ARCH_GICV3_H */ |
| @@ -79,19 +79,10 @@ · 78 unmodified lines | ||
| 79 | 79 | |
| 80 | 80 | #include <linux/stringify.h> |
| 81 | 81 | #include <asm/barrier.h> |
| 82 | +#include <asm/cacheflush.h> | |
| 82 | 83 | |
| 83 | −#define read_gicreg(r) \ | |
| 84 | − ({ \ | |
| 85 | − u64 reg; \ | |
| 86 | − asm volatile("mrs_s %0, " __stringify(r) : "=r" (reg)); \ | |
| 87 | − reg; \ | |
| 88 | − }) | |
| 89 | − | |
| 90 | −#define write_gicreg(v,r) \ | |
| 91 | − do { \ | |
| 92 | − u64 __val = (v); \ | |
| 93 | − asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\ | |
| 94 | − } while (0) | |
| 84 | +#define read_gicreg read_sysreg_s | |
| 85 | +#define write_gicreg write_sysreg_s | |
| 95 | 86 | |
| 96 | 87 | /* |
| 97 | 88 | * Low-level accessors |
| @@ -102,13 +93,13 @@ · 4 unmodified lines | ||
| 102 | 93 | |
| 103 | 94 | static inline void gic_write_eoir(u32 irq) |
| 104 | 95 | { |
| 105 | − asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); | |
| 96 | + write_sysreg_s(irq, ICC_EOIR1_EL1); | |
| 106 | 97 | isb(); |
| 107 | 98 | } |
| 108 | 99 | |
| 109 | 100 | static inline void gic_write_dir(u32 irq) |
| 110 | 101 | { |
| 111 | − asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); | |
| 102 | + write_sysreg_s(irq, ICC_DIR_EL1); | |
| 112 | 103 | isb(); |
| 113 | 104 | } |
| 114 | 105 | |
| @@ -116,7 +107,7 @@ static inline u64 gic_read_iar_common(void) · 1 unmodified line | ||
| 116 | 107 | { |
| 117 | 108 | u64 irqstat; |
| 118 | 109 | |
| 119 | − asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); | |
| 110 | + irqstat = read_sysreg_s(ICC_IAR1_EL1); | |
| 120 | 111 | dsb(sy); |
| 121 | 112 | return irqstat; |
| 122 | 113 | } |
| @@ -132,12 +123,9 @@ static inline u64 gic_read_iar_cavium_thunderx(void) · 9 unmodified lines | ||
| 132 | 123 | { |
| 133 | 124 | u64 irqstat; |
| 134 | 125 | |
| 135 | − asm volatile( | |
| 136 | − "nop;nop;nop;nop\n\t" | |
| 137 | − "nop;nop;nop;nop\n\t" | |
| 138 | − "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" | |
| 139 | − "nop;nop;nop;nop" | |
| 140 | − : "=r" (irqstat)); | |
| 126 | + nops(8); | |
| 127 | + irqstat = read_sysreg_s(ICC_IAR1_EL1); | |
| 128 | + nops(4); | |
| 141 | 129 | mb(); |
| 142 | 130 | |
| 143 | 131 | return irqstat; |
| @@ -145,37 +133,34 @@ static inline u64 gic_read_iar_cavium_thunderx(void) · 1 unmodified line | ||
| 145 | 133 | |
| 146 | 134 | static inline void gic_write_pmr(u32 val) |
| 147 | 135 | { |
| 148 | − asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); | |
| 136 | + write_sysreg_s(val, ICC_PMR_EL1); | |
| 149 | 137 | } |
| 150 | 138 | |
| 151 | 139 | static inline void gic_write_ctlr(u32 val) |
| 152 | 140 | { |
| 153 | − asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); | |
| 141 | + write_sysreg_s(val, ICC_CTLR_EL1); | |
| 154 | 142 | isb(); |
| 155 | 143 | } |
| 156 | 144 | |
| 157 | 145 | static inline void gic_write_grpen1(u32 val) |
| 158 | 146 | { |
| 159 | − asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); | |
| 147 | + write_sysreg_s(val, ICC_GRPEN1_EL1); | |
| 160 | 148 | isb(); |
| 161 | 149 | } |
| 162 | 150 | |
| 163 | 151 | static inline void gic_write_sgi1r(u64 val) |
| 164 | 152 | { |
| 165 | − asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); | |
| 153 | + write_sysreg_s(val, ICC_SGI1R_EL1); | |
| 166 | 154 | } |
| 167 | 155 | |
| 168 | 156 | static inline u32 gic_read_sre(void) |
| 169 | 157 | { |
| 170 | − u64 val; | |
| 171 | − | |
| 172 | − asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); | |
| 173 | − return val; | |
| 158 | + return read_sysreg_s(ICC_SRE_EL1); | |
| 174 | 159 | } |
| 175 | 160 | |
| 176 | 161 | static inline void gic_write_sre(u32 val) |
| 177 | 162 | { |
| 178 | − asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); | |
| 163 | + write_sysreg_s(val, ICC_SRE_EL1); | |
| 179 | 164 | isb(); |
| 180 | 165 | } |
| 181 | 166 | |
| @@ -187,5 +172,21 @@ static inline void gic_write_bpr1(u32 val) · 5 unmodified lines | ||
| 187 | 172 | #define gic_read_typer(c) readq_relaxed(c) |
| 188 | 173 | #define gic_write_irouter(v, c) writeq_relaxed(v, c) |
| 189 | 174 | |
| 175 | +#define gic_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) | |
| 176 | + | |
| 177 | +#define gits_read_baser(c) readq_relaxed(c) | |
| 178 | +#define gits_write_baser(v, c) writeq_relaxed(v, c) | |
| 179 | + | |
| 180 | +#define gits_read_cbaser(c) readq_relaxed(c) | |
| 181 | +#define gits_write_cbaser(v, c) writeq_relaxed(v, c) | |
| 182 | + | |
| 183 | +#define gits_write_cwriter(v, c) writeq_relaxed(v, c) | |
| 184 | + | |
| 185 | +#define gicr_read_propbaser(c) readq_relaxed(c) | |
| 186 | +#define gicr_write_propbaser(v, c) writeq_relaxed(v, c) | |
| 187 | + | |
| 188 | +#define gicr_write_pendbaser(v, c) writeq_relaxed(v, c) | |
| 189 | +#define gicr_read_pendbaser(c) readq_relaxed(c) | |
| 190 | + | |
| 190 | 191 | #endif /* __ASSEMBLY__ */ |
| 191 | 192 | #endif /* __ASM_ARCH_GICV3_H */ |
| @@ -27,6 +27,7 @@ config MICROBLAZE · 26 unmodified lines | ||
| 27 | 27 | select HAVE_MEMBLOCK_NODE_MAP |
| 28 | 28 | select HAVE_OPROFILE |
| 29 | 29 | select IRQ_DOMAIN |
| 30 | + select XILINX_INTC | |
| 30 | 31 | select MODULES_USE_ELF_RELA |
| 31 | 32 | select OF |
| 32 | 33 | select OF_EARLY_FLATTREE |
| @@ -16,6 +16,6 @@ struct pt_regs; · 15 unmodified lines | ||
| 16 | 16 | extern void do_IRQ(struct pt_regs *regs); |
| 17 | 17 | |
| 18 | 18 | /* should be defined in each interrupt controller driver */ |
| 19 | −extern unsigned int get_irq(void); | |
| 19 | +extern unsigned int xintc_get_irq(void); | |
| 20 | 20 | |
| 21 | 21 | #endif /* _ASM_MICROBLAZE_IRQ_H */ |
| @@ -15,7 +15,7 @@ endif · 14 unmodified lines | ||
| 15 | 15 | extra-y := head.o vmlinux.lds |
| 16 | 16 | |
| 17 | 17 | obj-y += dma.o exceptions.o \ |
| 18 | − hw_exception_handler.o intc.o irq.o \ | |
| 18 | + hw_exception_handler.o irq.o \ | |
| 19 | 19 | platform.o process.o prom.o ptrace.o \ |
| 20 | 20 | reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o |
| 21 | 21 | |
| @@ -1,196 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu> | |
| 3 | − * Copyright (C) 2012-2013 Xilinx, Inc. | |
| 4 | − * Copyright (C) 2007-2009 PetaLogix | |
| 5 | − * Copyright (C) 2006 Atmark Techno, Inc. | |
| 6 | − * | |
| 7 | − * This file is subject to the terms and conditions of the GNU General Public | |
| 8 | − * License. See the file "COPYING" in the main directory of this archive | |
| 9 | − * for more details. | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/irqdomain.h> | |
| 13 | −#include <linux/irq.h> | |
| 14 | −#include <linux/irqchip.h> | |
| 15 | −#include <linux/of_address.h> | |
| 16 | −#include <linux/io.h> | |
| 17 | −#include <linux/bug.h> | |
| 18 | − | |
| 19 | −static void __iomem *intc_baseaddr; | |
| 20 | − | |
| 21 | −/* No one else should require these constants, so define them locally here. */ | |
| 22 | −#define ISR 0x00 /* Interrupt Status Register */ | |
| 23 | −#define IPR 0x04 /* Interrupt Pending Register */ | |
| 24 | −#define IER 0x08 /* Interrupt Enable Register */ | |
| 25 | −#define IAR 0x0c /* Interrupt Acknowledge Register */ | |
| 26 | −#define SIE 0x10 /* Set Interrupt Enable bits */ | |
| 27 | −#define CIE 0x14 /* Clear Interrupt Enable bits */ | |
| 28 | −#define IVR 0x18 /* Interrupt Vector Register */ | |
| 29 | −#define MER 0x1c /* Master Enable Register */ | |
| 30 | − | |
| 31 | −#define MER_ME (1<<0) | |
| 32 | −#define MER_HIE (1<<1) | |
| 33 | − | |
| 34 | −static unsigned int (*read_fn)(void __iomem *); | |
| 35 | −static void (*write_fn)(u32, void __iomem *); | |
| 36 | − | |
| 37 | −static void intc_write32(u32 val, void __iomem *addr) | |
| 38 | −{ | |
| 39 | − iowrite32(val, addr); | |
| 40 | −} | |
| 41 | − | |
| 42 | −static unsigned int intc_read32(void __iomem *addr) | |
| 43 | −{ | |
| 44 | − return ioread32(addr); | |
| 45 | −} | |
| 46 | − | |
| 47 | −static void intc_write32_be(u32 val, void __iomem *addr) | |
| 48 | −{ | |
| 49 | − iowrite32be(val, addr); | |
| 50 | −} | |
| 51 | − | |
| 52 | −static unsigned int intc_read32_be(void __iomem *addr) | |
| 53 | −{ | |
| 54 | − return ioread32be(addr); | |
| 55 | −} | |
| 56 | − | |
| 57 | −static void intc_enable_or_unmask(struct irq_data *d) | |
| 58 | −{ | |
| 59 | − unsigned long mask = 1 << d->hwirq; | |
| 60 | − | |
| 61 | − pr_debug("enable_or_unmask: %ld\n", d->hwirq); | |
| 62 | − | |
| 63 | − /* ack level irqs because they can't be acked during | |
| 64 | − * ack function since the handle_level_irq function | |
| 65 | − * acks the irq before calling the interrupt handler | |
| 66 | − */ | |
| 67 | − if (irqd_is_level_type(d)) | |
| 68 | − write_fn(mask, intc_baseaddr + IAR); | |
| 69 | − | |
| 70 | − write_fn(mask, intc_baseaddr + SIE); | |
| 71 | −} | |
| 72 | − | |
| 73 | −static void intc_disable_or_mask(struct irq_data *d) | |
| 74 | −{ | |
| 75 | − pr_debug("disable: %ld\n", d->hwirq); | |
| 76 | − write_fn(1 << d->hwirq, intc_baseaddr + CIE); | |
| 77 | −} | |
| 78 | − | |
| 79 | −static void intc_ack(struct irq_data *d) | |
| 80 | −{ | |
| 81 | − pr_debug("ack: %ld\n", d->hwirq); | |
| 82 | − write_fn(1 << d->hwirq, intc_baseaddr + IAR); | |
| 83 | −} | |
| 84 | − | |
| 85 | −static void intc_mask_ack(struct irq_data *d) | |
| 86 | −{ | |
| 87 | − unsigned long mask = 1 << d->hwirq; | |
| 88 | − | |
| 89 | − pr_debug("disable_and_ack: %ld\n", d->hwirq); | |
| 90 | − write_fn(mask, intc_baseaddr + CIE); | |
| 91 | − write_fn(mask, intc_baseaddr + IAR); | |
| 92 | −} | |
| 93 | − | |
| 94 | −static struct irq_chip intc_dev = { | |
| 95 | − .name = "Xilinx INTC", | |
| 96 | − .irq_unmask = intc_enable_or_unmask, | |
| 97 | − .irq_mask = intc_disable_or_mask, | |
| 98 | − .irq_ack = intc_ack, | |
| 99 | − .irq_mask_ack = intc_mask_ack, | |
| 100 | −}; | |
| 101 | − | |
| 102 | −static struct irq_domain *root_domain; | |
| 103 | − | |
| 104 | −unsigned int get_irq(void) | |
| 105 | −{ | |
| 106 | − unsigned int hwirq, irq = -1; | |
| 107 | − | |
| 108 | − hwirq = read_fn(intc_baseaddr + IVR); | |
| 109 | − if (hwirq != -1U) | |
| 110 | − irq = irq_find_mapping(root_domain, hwirq); | |
| 111 | − | |
| 112 | − pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); | |
| 113 | − | |
| 114 | − return irq; | |
| 115 | −} | |
| 116 | − | |
| 117 | −static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | |
| 118 | −{ | |
| 119 | − u32 intr_mask = (u32)d->host_data; | |
| 120 | − | |
| 121 | − if (intr_mask & (1 << hw)) { | |
| 122 | − irq_set_chip_and_handler_name(irq, &intc_dev, | |
| 123 | − handle_edge_irq, "edge"); | |
| 124 | − irq_clear_status_flags(irq, IRQ_LEVEL); | |
| 125 | − } else { | |
| 126 | − irq_set_chip_and_handler_name(irq, &intc_dev, | |
| 127 | − handle_level_irq, "level"); | |
| 128 | − irq_set_status_flags(irq, IRQ_LEVEL); | |
| 129 | − } | |
| 130 | − return 0; | |
| 131 | −} | |
| 132 | − | |
| 133 | −static const struct irq_domain_ops xintc_irq_domain_ops = { | |
| 134 | − .xlate = irq_domain_xlate_onetwocell, | |
| 135 | − .map = xintc_map, | |
| 136 | −}; | |
| 137 | − | |
| 138 | −static int __init xilinx_intc_of_init(struct device_node *intc, | |
| 139 | − struct device_node *parent) | |
| 140 | −{ | |
| 141 | − u32 nr_irq, intr_mask; | |
| 142 | − int ret; | |
| 143 | − | |
| 144 | − intc_baseaddr = of_iomap(intc, 0); | |
| 145 | − BUG_ON(!intc_baseaddr); | |
| 146 | − | |
| 147 | − ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); | |
| 148 | − if (ret < 0) { | |
| 149 | − pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__); | |
| 150 | − return ret; | |
| 151 | − } | |
| 152 | − | |
| 153 | − ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask); | |
| 154 | − if (ret < 0) { | |
| 155 | − pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__); | |
| 156 | − return ret; | |
| 157 | − } | |
| 158 | − | |
| 159 | − if (intr_mask >> nr_irq) | |
| 160 | − pr_warn("%s: mismatch in kind-of-intr param\n", __func__); | |
| 161 | − | |
| 162 | − pr_info("%s: num_irq=%d, edge=0x%x\n", | |
| 163 | − intc->full_name, nr_irq, intr_mask); | |
| 164 | − | |
| 165 | − write_fn = intc_write32; | |
| 166 | − read_fn = intc_read32; | |
| 167 | − | |
| 168 | − /* | |
| 169 | − * Disable all external interrupts until they are | |
| 170 | − * explicity requested. | |
| 171 | − */ | |
| 172 | − write_fn(0, intc_baseaddr + IER); | |
| 173 | − | |
| 174 | − /* Acknowledge any pending interrupts just in case. */ | |
| 175 | − write_fn(0xffffffff, intc_baseaddr + IAR); | |
| 176 | − | |
| 177 | − /* Turn on the Master Enable. */ | |
| 178 | − write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); | |
| 179 | − if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) { | |
| 180 | − write_fn = intc_write32_be; | |
| 181 | − read_fn = intc_read32_be; | |
| 182 | − write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); | |
| 183 | − } | |
| 184 | − | |
| 185 | − /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm | |
| 186 | − * lazy and Michal can clean it up to something nicer when he tests | |
| 187 | − * and commits this patch. ~~gcl */ | |
| 188 | − root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, | |
| 189 | − (void *)intr_mask); | |
| 190 | − | |
| 191 | − irq_set_default_host(root_domain); | |
| 192 | − | |
| 193 | − return 0; | |
| 194 | −} | |
| 195 | − | |
| 196 | −IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init); | |
| @@ -29,12 +29,12 @@ void __irq_entry do_IRQ(struct pt_regs *regs) · 28 unmodified lines | ||
| 29 | 29 | trace_hardirqs_off(); |
| 30 | 30 | |
| 31 | 31 | irq_enter(); |
| 32 | − irq = get_irq(); | |
| 32 | + irq = xintc_get_irq(); | |
| 33 | 33 | next_irq: |
| 34 | 34 | BUG_ON(!irq); |
| 35 | 35 | generic_handle_irq(irq); |
| 36 | 36 | |
| 37 | − irq = get_irq(); | |
| 37 | + irq = xintc_get_irq(); | |
| 38 | 38 | if (irq != -1U) { |
| 39 | 39 | pr_debug("next irq: %d\n", irq); |
| 40 | 40 | ++concurrent_irq; |
| @@ -14,7 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #ifdef __KERNEL__ |
| 15 | 15 | |
| 16 | 16 | extern void __init xilinx_intc_init_tree(void); |
| 17 | −extern unsigned int xilinx_intc_get_irq(void); | |
| 17 | +extern unsigned int xintc_get_irq(void); | |
| 18 | 18 | |
| 19 | 19 | #endif /* __KERNEL__ */ |
| 20 | 20 | #endif /* _ASM_POWERPC_XILINX_INTC_H */ |
| @@ -64,6 +64,7 @@ config XILINX_VIRTEX_GENERIC_BOARD · 63 unmodified lines | ||
| 64 | 64 | default n |
| 65 | 65 | select XILINX_VIRTEX_II_PRO |
| 66 | 66 | select XILINX_VIRTEX_4_FX |
| 67 | + select XILINX_INTC | |
| 67 | 68 | help |
| 68 | 69 | This option enables generic support for Xilinx Virtex based boards. |
| 69 | 70 | |
| @@ -48,7 +48,7 @@ define_machine(virtex) { · 47 unmodified lines | ||
| 48 | 48 | .probe = virtex_probe, |
| 49 | 49 | .setup_arch = xilinx_pci_init, |
| 50 | 50 | .init_IRQ = xilinx_intc_init_tree, |
| 51 | − .get_irq = xilinx_intc_get_irq, | |
| 51 | + .get_irq = xintc_get_irq, | |
| 52 | 52 | .restart = ppc4xx_reset_system, |
| 53 | 53 | .calibrate_decr = generic_calibrate_decr, |
| 54 | 54 | }; |
| @@ -241,6 +241,7 @@ config XILINX_VIRTEX440_GENERIC_BOARD · 240 unmodified lines | ||
| 241 | 241 | depends on 44x |
| 242 | 242 | default n |
| 243 | 243 | select XILINX_VIRTEX_5_FXT |
| 244 | + select XILINX_INTC | |
| 244 | 245 | help |
| 245 | 246 | This option enables generic support for Xilinx Virtex based boards |
| 246 | 247 | that use a 440 based processor in the Virtex 5 FXT FPGA architecture. |
| @@ -54,7 +54,7 @@ define_machine(virtex) { · 53 unmodified lines | ||
| 54 | 54 | .probe = virtex_probe, |
| 55 | 55 | .setup_arch = xilinx_pci_init, |
| 56 | 56 | .init_IRQ = xilinx_intc_init_tree, |
| 57 | − .get_irq = xilinx_intc_get_irq, | |
| 57 | + .get_irq = xintc_get_irq, | |
| 58 | 58 | .calibrate_decr = generic_calibrate_decr, |
| 59 | 59 | .restart = ppc4xx_reset_system, |
| 60 | 60 | }; |
| @@ -29,194 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | #include <asm/processor.h> |
| 30 | 30 | #include <asm/i8259.h> |
| 31 | 31 | #include <asm/irq.h> |
| 32 | − | |
| 33 | −/* | |
| 34 | − * INTC Registers | |
| 35 | − */ | |
| 36 | −#define XINTC_ISR 0 /* Interrupt Status */ | |
| 37 | −#define XINTC_IPR 4 /* Interrupt Pending */ | |
| 38 | −#define XINTC_IER 8 /* Interrupt Enable */ | |
| 39 | −#define XINTC_IAR 12 /* Interrupt Acknowledge */ | |
| 40 | −#define XINTC_SIE 16 /* Set Interrupt Enable bits */ | |
| 41 | −#define XINTC_CIE 20 /* Clear Interrupt Enable bits */ | |
| 42 | −#define XINTC_IVR 24 /* Interrupt Vector */ | |
| 43 | −#define XINTC_MER 28 /* Master Enable */ | |
| 44 | − | |
| 45 | −static struct irq_domain *master_irqhost; | |
| 46 | − | |
| 47 | −#define XILINX_INTC_MAXIRQS (32) | |
| 48 | − | |
| 49 | −/* The following table allows the interrupt type, edge or level, | |
| 50 | − * to be cached after being read from the device tree until the interrupt | |
| 51 | − * is mapped | |
| 52 | − */ | |
| 53 | −static int xilinx_intc_typetable[XILINX_INTC_MAXIRQS]; | |
| 54 | − | |
| 55 | −/* Map the interrupt type from the device tree to the interrupt types | |
| 56 | − * used by the interrupt subsystem | |
| 57 | − */ | |
| 58 | −static unsigned char xilinx_intc_map_senses[] = { | |
| 59 | − IRQ_TYPE_EDGE_RISING, | |
| 60 | − IRQ_TYPE_EDGE_FALLING, | |
| 61 | − IRQ_TYPE_LEVEL_HIGH, | |
| 62 | − IRQ_TYPE_LEVEL_LOW, | |
| 63 | −}; | |
| 64 | − | |
| 65 | −/* | |
| 66 | − * The interrupt controller is setup such that it doesn't work well with | |
| 67 | − * the level interrupt handler in the kernel because the handler acks the | |
| 68 | − * interrupt before calling the application interrupt handler. To deal with | |
| 69 | − * that, we use 2 different irq chips so that different functions can be | |
| 70 | − * used for level and edge type interrupts. | |
| 71 | − * | |
| 72 | − * IRQ Chip common (across level and edge) operations | |
| 73 | − */ | |
| 74 | −static void xilinx_intc_mask(struct irq_data *d) | |
| 75 | −{ | |
| 76 | − int irq = irqd_to_hwirq(d); | |
| 77 | − void * regs = irq_data_get_irq_chip_data(d); | |
| 78 | − pr_debug("mask: %d\n", irq); | |
| 79 | − out_be32(regs + XINTC_CIE, 1 << irq); | |
| 80 | −} | |
| 81 | − | |
| 82 | −static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type) | |
| 83 | −{ | |
| 84 | − return 0; | |
| 85 | −} | |
| 86 | − | |
| 87 | −/* | |
| 88 | − * IRQ Chip level operations | |
| 89 | − */ | |
| 90 | −static void xilinx_intc_level_unmask(struct irq_data *d) | |
| 91 | −{ | |
| 92 | − int irq = irqd_to_hwirq(d); | |
| 93 | − void * regs = irq_data_get_irq_chip_data(d); | |
| 94 | − pr_debug("unmask: %d\n", irq); | |
| 95 | − out_be32(regs + XINTC_SIE, 1 << irq); | |
| 96 | − | |
| 97 | − /* ack level irqs because they can't be acked during | |
| 98 | − * ack function since the handle_level_irq function | |
| 99 | − * acks the irq before calling the inerrupt handler | |
| 100 | − */ | |
| 101 | − out_be32(regs + XINTC_IAR, 1 << irq); | |
| 102 | −} | |
| 103 | − | |
| 104 | −static struct irq_chip xilinx_intc_level_irqchip = { | |
| 105 | − .name = "Xilinx Level INTC", | |
| 106 | − .irq_mask = xilinx_intc_mask, | |
| 107 | − .irq_mask_ack = xilinx_intc_mask, | |
| 108 | − .irq_unmask = xilinx_intc_level_unmask, | |
| 109 | − .irq_set_type = xilinx_intc_set_type, | |
| 110 | −}; | |
| 111 | − | |
| 112 | −/* | |
| 113 | − * IRQ Chip edge operations | |
| 114 | − */ | |
| 115 | −static void xilinx_intc_edge_unmask(struct irq_data *d) | |
| 116 | −{ | |
| 117 | − int irq = irqd_to_hwirq(d); | |
| 118 | − void *regs = irq_data_get_irq_chip_data(d); | |
| 119 | − pr_debug("unmask: %d\n", irq); | |
| 120 | − out_be32(regs + XINTC_SIE, 1 << irq); | |
| 121 | −} | |
| 122 | − | |
| 123 | −static void xilinx_intc_edge_ack(struct irq_data *d) | |
| 124 | −{ | |
| 125 | − int irq = irqd_to_hwirq(d); | |
| 126 | − void * regs = irq_data_get_irq_chip_data(d); | |
| 127 | − pr_debug("ack: %d\n", irq); | |
| 128 | − out_be32(regs + XINTC_IAR, 1 << irq); | |
| 129 | −} | |
| 130 | − | |
| 131 | −static struct irq_chip xilinx_intc_edge_irqchip = { | |
| 132 | − .name = "Xilinx Edge INTC", | |
| 133 | − .irq_mask = xilinx_intc_mask, | |
| 134 | − .irq_unmask = xilinx_intc_edge_unmask, | |
| 135 | − .irq_ack = xilinx_intc_edge_ack, | |
| 136 | − .irq_set_type = xilinx_intc_set_type, | |
| 137 | −}; | |
| 138 | − | |
| 139 | −/* | |
| 140 | − * IRQ Host operations | |
| 141 | − */ | |
| 142 | − | |
| 143 | −/** | |
| 144 | − * xilinx_intc_xlate - translate virq# from device tree interrupts property | |
| 145 | − */ | |
| 146 | −static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct, | |
| 147 | − const u32 *intspec, unsigned int intsize, | |
| 148 | − irq_hw_number_t *out_hwirq, | |
| 149 | − unsigned int *out_flags) | |
| 150 | −{ | |
| 151 | − if ((intsize < 2) || (intspec[0] >= XILINX_INTC_MAXIRQS)) | |
| 152 | − return -EINVAL; | |
| 153 | − | |
| 154 | − /* keep a copy of the interrupt type til the interrupt is mapped | |
| 155 | − */ | |
| 156 | − xilinx_intc_typetable[intspec[0]] = xilinx_intc_map_senses[intspec[1]]; | |
| 157 | − | |
| 158 | − /* Xilinx uses 2 interrupt entries, the 1st being the h/w | |
| 159 | − * interrupt number, the 2nd being the interrupt type, edge or level | |
| 160 | − */ | |
| 161 | − *out_hwirq = intspec[0]; | |
| 162 | − *out_flags = xilinx_intc_map_senses[intspec[1]]; | |
| 163 | − | |
| 164 | − return 0; | |
| 165 | −} | |
| 166 | −static int xilinx_intc_map(struct irq_domain *h, unsigned int virq, | |
| 167 | − irq_hw_number_t irq) | |
| 168 | −{ | |
| 169 | − irq_set_chip_data(virq, h->host_data); | |
| 170 | − | |
| 171 | − if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH || | |
| 172 | − xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) { | |
| 173 | − irq_set_chip_and_handler(virq, &xilinx_intc_level_irqchip, | |
| 174 | − handle_level_irq); | |
| 175 | − } else { | |
| 176 | − irq_set_chip_and_handler(virq, &xilinx_intc_edge_irqchip, | |
| 177 | − handle_edge_irq); | |
| 178 | − } | |
| 179 | − return 0; | |
| 180 | −} | |
| 181 | − | |
| 182 | −static const struct irq_domain_ops xilinx_intc_ops = { | |
| 183 | − .map = xilinx_intc_map, | |
| 184 | − .xlate = xilinx_intc_xlate, | |
| 185 | −}; | |
| 186 | − | |
| 187 | −struct irq_domain * __init | |
| 188 | −xilinx_intc_init(struct device_node *np) | |
| 189 | −{ | |
| 190 | − struct irq_domain * irq; | |
| 191 | − void * regs; | |
| 192 | − | |
| 193 | − /* Find and map the intc registers */ | |
| 194 | − regs = of_iomap(np, 0); | |
| 195 | − if (!regs) { | |
| 196 | − pr_err("xilinx_intc: could not map registers\n"); | |
| 197 | − return NULL; | |
| 198 | − } | |
| 199 | − | |
| 200 | − /* Setup interrupt controller */ | |
| 201 | − out_be32(regs + XINTC_IER, 0); /* disable all irqs */ | |
| 202 | − out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */ | |
| 203 | − out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ | |
| 204 | − | |
| 205 | − /* Allocate and initialize an irq_domain structure. */ | |
| 206 | − irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops, | |
| 207 | − regs); | |
| 208 | − if (!irq) | |
| 209 | − panic(__FILE__ ": Cannot allocate IRQ host\n"); | |
| 210 | − | |
| 211 | − return irq; | |
| 212 | −} | |
| 213 | − | |
| 214 | −int xilinx_intc_get_irq(void) | |
| 215 | −{ | |
| 216 | − void * regs = master_irqhost->host_data; | |
| 217 | − pr_debug("get_irq:\n"); | |
| 218 | − return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); | |
| 219 | −} | |
| 32 | +#include <linux/irqchip.h> | |
| 220 | 33 | |
| 221 | 34 | #if defined(CONFIG_PPC_I8259) |
| 222 | 35 | /* |
| @@ -265,31 +78,11 @@ static void __init xilinx_i8259_setup_cascade(void) · 42 unmodified lines | ||
| 265 | 78 | static inline void xilinx_i8259_setup_cascade(void) { return; } |
| 266 | 79 | #endif /* defined(CONFIG_PPC_I8259) */ |
| 267 | 80 | |
| 268 | −static const struct of_device_id xilinx_intc_match[] __initconst = { | |
| 269 | − { .compatible = "xlnx,opb-intc-1.00.c", }, | |
| 270 | − { .compatible = "xlnx,xps-intc-1.00.a", }, | |
| 271 | − {} | |
| 272 | −}; | |
| 273 | − | |
| 274 | 81 | /* |
| 275 | 82 | * Initialize master Xilinx interrupt controller |
| 276 | 83 | */ |
| 277 | 84 | void __init xilinx_intc_init_tree(void) |
| 278 | 85 | { |
| 279 | − struct device_node *np; | |
| 280 | − | |
| 281 | − /* find top level interrupt controller */ | |
| 282 | − for_each_matching_node(np, xilinx_intc_match) { | |
| 283 | − if (!of_get_property(np, "interrupts", NULL)) | |
| 284 | − break; | |
| 285 | − } | |
| 286 | − BUG_ON(!np); | |
| 287 | − | |
| 288 | − master_irqhost = xilinx_intc_init(np); | |
| 289 | − BUG_ON(!master_irqhost); | |
| 290 | − | |
| 291 | − irq_set_default_host(master_irqhost); | |
| 292 | − of_node_put(np); | |
| 293 | − | |
| 86 | + irqchip_init(); | |
| 294 | 87 | xilinx_i8259_setup_cascade(); |
| 295 | 88 | } |
| @@ -211,6 +211,10 @@ config XTENSA_MX · 210 unmodified lines | ||
| 211 | 211 | bool |
| 212 | 212 | select IRQ_DOMAIN |
| 213 | 213 | |
| 214 | +config XILINX_INTC | |
| 215 | + bool | |
| 216 | + select IRQ_DOMAIN | |
| 217 | + | |
| 214 | 218 | config IRQ_CROSSBAR |
| 215 | 219 | bool |
| 216 | 220 | help |
| @@ -52,6 +52,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o · 51 unmodified lines | ||
| 52 | 52 | obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o |
| 53 | 53 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
| 54 | 54 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
| 55 | +obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o | |
| 55 | 56 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
| 56 | 57 | obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o |
| 57 | 58 | obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o |
| @@ -215,6 +215,31 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, · 214 unmodified lines | ||
| 215 | 215 | return 0; |
| 216 | 216 | } |
| 217 | 217 | |
| 218 | +static void bcm7038_l1_cpu_offline(struct irq_data *d) | |
| 219 | +{ | |
| 220 | + struct cpumask *mask = irq_data_get_affinity_mask(d); | |
| 221 | + int cpu = smp_processor_id(); | |
| 222 | + cpumask_t new_affinity; | |
| 223 | + | |
| 224 | + /* This CPU was not on the affinity mask */ | |
| 225 | + if (!cpumask_test_cpu(cpu, mask)) | |
| 226 | + return; | |
| 227 | + | |
| 228 | + if (cpumask_weight(mask) > 1) { | |
| 229 | + /* | |
| 230 | + * Multiple CPU affinity, remove this CPU from the affinity | |
| 231 | + * mask | |
| 232 | + */ | |
| 233 | + cpumask_copy(&new_affinity, mask); | |
| 234 | + cpumask_clear_cpu(cpu, &new_affinity); | |
| 235 | + } else { | |
| 236 | + /* Only CPU, put on the lowest online CPU */ | |
| 237 | + cpumask_clear(&new_affinity); | |
| 238 | + cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity); | |
| 239 | + } | |
| 240 | + irq_set_affinity_locked(d, &new_affinity, false); | |
| 241 | +} | |
| 242 | + | |
| 218 | 243 | static int __init bcm7038_l1_init_one(struct device_node *dn, |
| 219 | 244 | unsigned int idx, |
| 220 | 245 | struct bcm7038_l1_chip *intc) |
| @@ -266,6 +291,7 @@ static struct irq_chip bcm7038_l1_irq_chip = { · 45 unmodified lines | ||
| 266 | 291 | .irq_mask = bcm7038_l1_mask, |
| 267 | 292 | .irq_unmask = bcm7038_l1_unmask, |
| 268 | 293 | .irq_set_affinity = bcm7038_l1_set_affinity, |
| 294 | + .irq_cpu_offline = bcm7038_l1_cpu_offline, | |
| 269 | 295 | }; |
| 270 | 296 | |
| 271 | 297 | static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, |
| @@ -37,7 +37,6 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <linux/irqchip.h> |
| 38 | 38 | #include <linux/irqchip/arm-gic-v3.h> |
| 39 | 39 | |
| 40 | −#include <asm/cacheflush.h> | |
| 41 | 40 | #include <asm/cputype.h> |
| 42 | 41 | #include <asm/exception.h> |
| 43 | 42 | |
| @@ -196,7 +195,7 @@ typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *, · 152 unmodified lines | ||
| 196 | 195 | |
| 197 | 196 | static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) |
| 198 | 197 | { |
| 199 | − cmd->raw_cmd[0] &= ~0xffUL; | |
| 198 | + cmd->raw_cmd[0] &= ~0xffULL; | |
| 200 | 199 | cmd->raw_cmd[0] |= cmd_nr; |
| 201 | 200 | } |
| 202 | 201 | |
| @@ -208,43 +207,43 @@ static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) · 5 unmodified lines | ||
| 208 | 207 | |
| 209 | 208 | static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) |
| 210 | 209 | { |
| 211 | − cmd->raw_cmd[1] &= ~0xffffffffUL; | |
| 210 | + cmd->raw_cmd[1] &= ~0xffffffffULL; | |
| 212 | 211 | cmd->raw_cmd[1] |= id; |
| 213 | 212 | } |
| 214 | 213 | |
| 215 | 214 | static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) |
| 216 | 215 | { |
| 217 | − cmd->raw_cmd[1] &= 0xffffffffUL; | |
| 216 | + cmd->raw_cmd[1] &= 0xffffffffULL; | |
| 218 | 217 | cmd->raw_cmd[1] |= ((u64)phys_id) << 32; |
| 219 | 218 | } |
| 220 | 219 | |
| 221 | 220 | static void its_encode_size(struct its_cmd_block *cmd, u8 size) |
| 222 | 221 | { |
| 223 | − cmd->raw_cmd[1] &= ~0x1fUL; | |
| 222 | + cmd->raw_cmd[1] &= ~0x1fULL; | |
| 224 | 223 | cmd->raw_cmd[1] |= size & 0x1f; |
| 225 | 224 | } |
| 226 | 225 | |
| 227 | 226 | static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) |
| 228 | 227 | { |
| 229 | − cmd->raw_cmd[2] &= ~0xffffffffffffUL; | |
| 230 | − cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00UL; | |
| 228 | + cmd->raw_cmd[2] &= ~0xffffffffffffULL; | |
| 229 | + cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL; | |
| 231 | 230 | } |
| 232 | 231 | |
| 233 | 232 | static void its_encode_valid(struct its_cmd_block *cmd, int valid) |
| 234 | 233 | { |
| 235 | − cmd->raw_cmd[2] &= ~(1UL << 63); | |
| 234 | + cmd->raw_cmd[2] &= ~(1ULL << 63); | |
| 236 | 235 | cmd->raw_cmd[2] |= ((u64)!!valid) << 63; |
| 237 | 236 | } |
| 238 | 237 | |
| 239 | 238 | static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) |
| 240 | 239 | { |
| 241 | − cmd->raw_cmd[2] &= ~(0xffffffffUL << 16); | |
| 242 | − cmd->raw_cmd[2] |= (target_addr & (0xffffffffUL << 16)); | |
| 240 | + cmd->raw_cmd[2] &= ~(0xffffffffULL << 16); | |
| 241 | + cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16)); | |
| 243 | 242 | } |
| 244 | 243 | |
| 245 | 244 | static void its_encode_collection(struct its_cmd_block *cmd, u16 col) |
| 246 | 245 | { |
| 247 | − cmd->raw_cmd[2] &= ~0xffffUL; | |
| 246 | + cmd->raw_cmd[2] &= ~0xffffULL; | |
| 248 | 247 | cmd->raw_cmd[2] |= col; |
| 249 | 248 | } |
| 250 | 249 | |
| @@ -433,7 +432,7 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) · 182 unmodified lines | ||
| 433 | 432 | * the ITS. |
| 434 | 433 | */ |
| 435 | 434 | if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING) |
| 436 | − __flush_dcache_area(cmd, sizeof(*cmd)); | |
| 435 | + gic_flush_dcache_to_poc(cmd, sizeof(*cmd)); | |
| 437 | 436 | else |
| 438 | 437 | dsb(ishst); |
| 439 | 438 | } |
| @@ -602,7 +601,7 @@ static void lpi_set_config(struct irq_data *d, bool enable) · 162 unmodified lines | ||
| 602 | 601 | * Humpf... |
| 603 | 602 | */ |
| 604 | 603 | if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING) |
| 605 | − __flush_dcache_area(cfg, sizeof(*cfg)); | |
| 604 | + gic_flush_dcache_to_poc(cfg, sizeof(*cfg)); | |
| 606 | 605 | else |
| 607 | 606 | dsb(ishst); |
| 608 | 607 | its_send_inv(its_dev, id); |
| @@ -657,8 +656,8 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) · 48 unmodified lines | ||
| 657 | 656 | its = its_dev->its; |
| 658 | 657 | addr = its->phys_base + GITS_TRANSLATER; |
| 659 | 658 | |
| 660 | − msg->address_lo = addr & ((1UL << 32) - 1); | |
| 661 | − msg->address_hi = addr >> 32; | |
| 659 | + msg->address_lo = lower_32_bits(addr); | |
| 660 | + msg->address_hi = upper_32_bits(addr); | |
| 662 | 661 | msg->data = its_get_event_id(d); |
| 663 | 662 | |
| 664 | 663 | iommu_dma_map_msi_msg(d->irq, msg); |
| @@ -817,7 +816,7 @@ static int __init its_alloc_lpi_tables(void) · 152 unmodified lines | ||
| 817 | 816 | LPI_PROPBASE_SZ); |
| 818 | 817 | |
| 819 | 818 | /* Make sure the GIC will observe the written configuration */ |
| 820 | − __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ); | |
| 819 | + gic_flush_dcache_to_poc(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ); | |
| 821 | 820 | |
| 822 | 821 | return 0; |
| 823 | 822 | } |
| @@ -836,7 +835,7 @@ static u64 its_read_baser(struct its_node *its, struct its_baser *baser) · 12 unmodified lines | ||
| 836 | 835 | { |
| 837 | 836 | u32 idx = baser - its->tables; |
| 838 | 837 | |
| 839 | − return readq_relaxed(its->base + GITS_BASER + (idx << 3)); | |
| 838 | + return gits_read_baser(its->base + GITS_BASER + (idx << 3)); | |
| 840 | 839 | } |
| 841 | 840 | |
| 842 | 841 | static void its_write_baser(struct its_node *its, struct its_baser *baser, |
| @@ -844,7 +843,7 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, · 1 unmodified line | ||
| 844 | 843 | { |
| 845 | 844 | u32 idx = baser - its->tables; |
| 846 | 845 | |
| 847 | − writeq_relaxed(val, its->base + GITS_BASER + (idx << 3)); | |
| 846 | + gits_write_baser(val, its->base + GITS_BASER + (idx << 3)); | |
| 848 | 847 | baser->val = its_read_baser(its, baser); |
| 849 | 848 | } |
| 850 | 849 | |
| @@ -910,7 +909,7 @@ retry_baser: · 59 unmodified lines | ||
| 910 | 909 | shr = tmp & GITS_BASER_SHAREABILITY_MASK; |
| 911 | 910 | if (!shr) { |
| 912 | 911 | cache = GITS_BASER_nC; |
| 913 | − __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); | |
| 912 | + gic_flush_dcache_to_poc(base, PAGE_ORDER_TO_SIZE(order)); | |
| 914 | 913 | } |
| 915 | 914 | goto retry_baser; |
| 916 | 915 | } |
| @@ -935,9 +934,9 @@ retry_baser: · 18 unmodified lines | ||
| 935 | 934 | } |
| 936 | 935 | |
| 937 | 936 | if (val != tmp) { |
| 938 | − pr_err("ITS@%pa: %s doesn't stick: %lx %lx\n", | |
| 937 | + pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", | |
| 939 | 938 | &its->phys_base, its_base_type_string[type], |
| 940 | − (unsigned long) val, (unsigned long) tmp); | |
| 939 | + val, tmp); | |
| 941 | 940 | free_pages((unsigned long)base, order); |
| 942 | 941 | return -ENXIO; |
| 943 | 942 | } |
| @@ -948,7 +947,7 @@ retry_baser: · 4 unmodified lines | ||
| 948 | 947 | tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; |
| 949 | 948 | |
| 950 | 949 | pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", |
| 951 | − &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / tmp), | |
| 950 | + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / (int)tmp), | |
| 952 | 951 | its_base_type_string[type], |
| 953 | 952 | (unsigned long)virt_to_phys(base), |
| 954 | 953 | indirect ? "indirect" : "flat", (int)esz, |
| @@ -983,7 +982,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser · 28 unmodified lines | ||
| 983 | 982 | * which is reported by ITS hardware times lvl1 table |
| 984 | 983 | * entry size. |
| 985 | 984 | */ |
| 986 | − ids -= ilog2(psz / esz); | |
| 985 | + ids -= ilog2(psz / (int)esz); | |
| 987 | 986 | esz = GITS_LVL1_ENTRY_SIZE; |
| 988 | 987 | } |
| 989 | 988 | } |
| @@ -998,7 +997,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser · 8 unmodified lines | ||
| 998 | 997 | new_order = max_t(u32, get_order(esz << ids), new_order); |
| 999 | 998 | if (new_order >= MAX_ORDER) { |
| 1000 | 999 | new_order = MAX_ORDER - 1; |
| 1001 | − ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / esz); | |
| 1000 | + ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); | |
| 1002 | 1001 | pr_warn("ITS@%pa: Device Table too large, reduce ids %u->%u\n", |
| 1003 | 1002 | &its->phys_base, its->device_ids, ids); |
| 1004 | 1003 | } |
| @@ -1102,7 +1101,7 @@ static void its_cpu_init_lpis(void) · 97 unmodified lines | ||
| 1102 | 1101 | } |
| 1103 | 1102 | |
| 1104 | 1103 | /* Make sure the GIC will observe the zero-ed page */ |
| 1105 | − __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ); | |
| 1104 | + gic_flush_dcache_to_poc(page_address(pend_page), LPI_PENDBASE_SZ); | |
| 1106 | 1105 | |
| 1107 | 1106 | paddr = page_to_phys(pend_page); |
| 1108 | 1107 | pr_info("CPU%d: using LPI pending table @%pa\n", |
| @@ -1126,8 +1125,8 @@ static void its_cpu_init_lpis(void) · 17 unmodified lines | ||
| 1126 | 1125 | GICR_PROPBASER_WaWb | |
| 1127 | 1126 | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); |
| 1128 | 1127 | |
| 1129 | − writeq_relaxed(val, rbase + GICR_PROPBASER); | |
| 1130 | − tmp = readq_relaxed(rbase + GICR_PROPBASER); | |
| 1128 | + gicr_write_propbaser(val, rbase + GICR_PROPBASER); | |
| 1129 | + tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); | |
| 1131 | 1130 | |
| 1132 | 1131 | if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { |
| 1133 | 1132 | if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { |
| @@ -1139,7 +1138,7 @@ static void its_cpu_init_lpis(void) · 5 unmodified lines | ||
| 1139 | 1138 | val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | |
| 1140 | 1139 | GICR_PROPBASER_CACHEABILITY_MASK); |
| 1141 | 1140 | val |= GICR_PROPBASER_nC; |
| 1142 | − writeq_relaxed(val, rbase + GICR_PROPBASER); | |
| 1141 | + gicr_write_propbaser(val, rbase + GICR_PROPBASER); | |
| 1143 | 1142 | } |
| 1144 | 1143 | pr_info_once("GIC: using cache flushing for LPI property table\n"); |
| 1145 | 1144 | gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; |
| @@ -1150,8 +1149,8 @@ static void its_cpu_init_lpis(void) · 4 unmodified lines | ||
| 1150 | 1149 | GICR_PENDBASER_InnerShareable | |
| 1151 | 1150 | GICR_PENDBASER_WaWb); |
| 1152 | 1151 | |
| 1153 | − writeq_relaxed(val, rbase + GICR_PENDBASER); | |
| 1154 | − tmp = readq_relaxed(rbase + GICR_PENDBASER); | |
| 1152 | + gicr_write_pendbaser(val, rbase + GICR_PENDBASER); | |
| 1153 | + tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); | |
| 1155 | 1154 | |
| 1156 | 1155 | if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { |
| 1157 | 1156 | /* |
| @@ -1161,7 +1160,7 @@ static void its_cpu_init_lpis(void) · 3 unmodified lines | ||
| 1161 | 1160 | val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | |
| 1162 | 1161 | GICR_PENDBASER_CACHEABILITY_MASK); |
| 1163 | 1162 | val |= GICR_PENDBASER_nC; |
| 1164 | − writeq_relaxed(val, rbase + GICR_PENDBASER); | |
| 1163 | + gicr_write_pendbaser(val, rbase + GICR_PENDBASER); | |
| 1165 | 1164 | } |
| 1166 | 1165 | |
| 1167 | 1166 | /* Enable LPIs */ |
| @@ -1287,13 +1286,13 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id) · 119 unmodified lines | ||
| 1287 | 1286 | |
| 1288 | 1287 | /* Flush Lvl2 table to PoC if hw doesn't support coherency */ |
| 1289 | 1288 | if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) |
| 1290 | − __flush_dcache_area(page_address(page), baser->psz); | |
| 1289 | + gic_flush_dcache_to_poc(page_address(page), baser->psz); | |
| 1291 | 1290 | |
| 1292 | 1291 | table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); |
| 1293 | 1292 | |
| 1294 | 1293 | /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ |
| 1295 | 1294 | if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) |
| 1296 | − __flush_dcache_area(table + idx, GITS_LVL1_ENTRY_SIZE); | |
| 1295 | + gic_flush_dcache_to_poc(table + idx, GITS_LVL1_ENTRY_SIZE); | |
| 1297 | 1296 | |
| 1298 | 1297 | /* Ensure updated table contents are visible to ITS hardware */ |
| 1299 | 1298 | dsb(sy); |
| @@ -1340,7 +1339,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, · 40 unmodified lines | ||
| 1340 | 1339 | return NULL; |
| 1341 | 1340 | } |
| 1342 | 1341 | |
| 1343 | − __flush_dcache_area(itt, sz); | |
| 1342 | + gic_flush_dcache_to_poc(itt, sz); | |
| 1344 | 1343 | |
| 1345 | 1344 | dev->its = its; |
| 1346 | 1345 | dev->itt = itt; |
| @@ -1717,8 +1716,8 @@ static int __init its_probe_one(struct resource *res, · 370 unmodified lines | ||
| 1717 | 1716 | (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | |
| 1718 | 1717 | GITS_CBASER_VALID); |
| 1719 | 1718 | |
| 1720 | − writeq_relaxed(baser, its->base + GITS_CBASER); | |
| 1721 | − tmp = readq_relaxed(its->base + GITS_CBASER); | |
| 1719 | + gits_write_cbaser(baser, its->base + GITS_CBASER); | |
| 1720 | + tmp = gits_read_cbaser(its->base + GITS_CBASER); | |
| 1722 | 1721 | |
| 1723 | 1722 | if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { |
| 1724 | 1723 | if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { |
| @@ -1730,13 +1729,13 @@ static int __init its_probe_one(struct resource *res, · 5 unmodified lines | ||
| 1730 | 1729 | baser &= ~(GITS_CBASER_SHAREABILITY_MASK | |
| 1731 | 1730 | GITS_CBASER_CACHEABILITY_MASK); |
| 1732 | 1731 | baser |= GITS_CBASER_nC; |
| 1733 | − writeq_relaxed(baser, its->base + GITS_CBASER); | |
| 1732 | + gits_write_cbaser(baser, its->base + GITS_CBASER); | |
| 1734 | 1733 | } |
| 1735 | 1734 | pr_info("ITS: using cache flushing for cmd queue\n"); |
| 1736 | 1735 | its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; |
| 1737 | 1736 | } |
| 1738 | 1737 | |
| 1739 | − writeq_relaxed(0, its->base + GITS_CWRITER); | |
| 1738 | + gits_write_cwriter(0, its->base + GITS_CWRITER); | |
| 1740 | 1739 | writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); |
| 1741 | 1740 | |
| 1742 | 1741 | err = its_init_domain(handle, its); |
| @@ -0,0 +1,241 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu> | |
| 3 | + * Copyright (C) 2012-2013 Xilinx, Inc. | |
| 4 | + * Copyright (C) 2007-2009 PetaLogix | |
| 5 | + * Copyright (C) 2006 Atmark Techno, Inc. | |
| 6 | + * | |
| 7 | + * This file is subject to the terms and conditions of the GNU General Public | |
| 8 | + * License. See the file "COPYING" in the main directory of this archive | |
| 9 | + * for more details. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/irqdomain.h> | |
| 13 | +#include <linux/irq.h> | |
| 14 | +#include <linux/irqchip.h> | |
| 15 | +#include <linux/irqchip/chained_irq.h> | |
| 16 | +#include <linux/of_address.h> | |
| 17 | +#include <linux/io.h> | |
| 18 | +#include <linux/jump_label.h> | |
| 19 | +#include <linux/bug.h> | |
| 20 | +#include <linux/of_irq.h> | |
| 21 | + | |
| 22 | +/* No one else should require these constants, so define them locally here. */ | |
| 23 | +#define ISR 0x00 /* Interrupt Status Register */ | |
| 24 | +#define IPR 0x04 /* Interrupt Pending Register */ | |
| 25 | +#define IER 0x08 /* Interrupt Enable Register */ | |
| 26 | +#define IAR 0x0c /* Interrupt Acknowledge Register */ | |
| 27 | +#define SIE 0x10 /* Set Interrupt Enable bits */ | |
| 28 | +#define CIE 0x14 /* Clear Interrupt Enable bits */ | |
| 29 | +#define IVR 0x18 /* Interrupt Vector Register */ | |
| 30 | +#define MER 0x1c /* Master Enable Register */ | |
| 31 | + | |
| 32 | +#define MER_ME (1<<0) | |
| 33 | +#define MER_HIE (1<<1) | |
| 34 | + | |
| 35 | +static DEFINE_STATIC_KEY_FALSE(xintc_is_be); | |
| 36 | + | |
| 37 | +struct xintc_irq_chip { | |
| 38 | + void __iomem *base; | |
| 39 | + struct irq_domain *root_domain; | |
| 40 | + u32 intr_mask; | |
| 41 | +}; | |
| 42 | + | |
| 43 | +static struct xintc_irq_chip *xintc_irqc; | |
| 44 | + | |
| 45 | +static void xintc_write(int reg, u32 data) | |
| 46 | +{ | |
| 47 | + if (static_branch_unlikely(&xintc_is_be)) | |
| 48 | + iowrite32be(data, xintc_irqc->base + reg); | |
| 49 | + else | |
| 50 | + iowrite32(data, xintc_irqc->base + reg); | |
| 51 | +} | |
| 52 | + | |
| 53 | +static unsigned int xintc_read(int reg) | |
| 54 | +{ | |
| 55 | + if (static_branch_unlikely(&xintc_is_be)) | |
| 56 | + return ioread32be(xintc_irqc->base + reg); | |
| 57 | + else | |
| 58 | + return ioread32(xintc_irqc->base + reg); | |
| 59 | +} | |
| 60 | + | |
| 61 | +static void intc_enable_or_unmask(struct irq_data *d) | |
| 62 | +{ | |
| 63 | + unsigned long mask = 1 << d->hwirq; | |
| 64 | + | |
| 65 | + pr_debug("irq-xilinx: enable_or_unmask: %ld\n", d->hwirq); | |
| 66 | + | |
| 67 | + /* ack level irqs because they can't be acked during | |
| 68 | + * ack function since the handle_level_irq function | |
| 69 | + * acks the irq before calling the interrupt handler | |
| 70 | + */ | |
| 71 | + if (irqd_is_level_type(d)) | |
| 72 | + xintc_write(IAR, mask); | |
| 73 | + | |
| 74 | + xintc_write(SIE, mask); | |
| 75 | +} | |
| 76 | + | |
| 77 | +static void intc_disable_or_mask(struct irq_data *d) | |
| 78 | +{ | |
| 79 | + pr_debug("irq-xilinx: disable: %ld\n", d->hwirq); | |
| 80 | + xintc_write(CIE, 1 << d->hwirq); | |
| 81 | +} | |
| 82 | + | |
| 83 | +static void intc_ack(struct irq_data *d) | |
| 84 | +{ | |
| 85 | + pr_debug("irq-xilinx: ack: %ld\n", d->hwirq); | |
| 86 | + xintc_write(IAR, 1 << d->hwirq); | |
| 87 | +} | |
| 88 | + | |
| 89 | +static void intc_mask_ack(struct irq_data *d) | |
| 90 | +{ | |
| 91 | + unsigned long mask = 1 << d->hwirq; | |
| 92 | + | |
| 93 | + pr_debug("irq-xilinx: disable_and_ack: %ld\n", d->hwirq); | |
| 94 | + xintc_write(CIE, mask); | |
| 95 | + xintc_write(IAR, mask); | |
| 96 | +} | |
| 97 | + | |
| 98 | +static struct irq_chip intc_dev = { | |
| 99 | + .name = "Xilinx INTC", | |
| 100 | + .irq_unmask = intc_enable_or_unmask, | |
| 101 | + .irq_mask = intc_disable_or_mask, | |
| 102 | + .irq_ack = intc_ack, | |
| 103 | + .irq_mask_ack = intc_mask_ack, | |
| 104 | +}; | |
| 105 | + | |
| 106 | +unsigned int xintc_get_irq(void) | |
| 107 | +{ | |
| 108 | + unsigned int hwirq, irq = -1; | |
| 109 | + | |
| 110 | + hwirq = xintc_read(IVR); | |
| 111 | + if (hwirq != -1U) | |
| 112 | + irq = irq_find_mapping(xintc_irqc->root_domain, hwirq); | |
| 113 | + | |
| 114 | + pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq); | |
| 115 | + | |
| 116 | + return irq; | |
| 117 | +} | |
| 118 | + | |
| 119 | +static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | |
| 120 | +{ | |
| 121 | + if (xintc_irqc->intr_mask & (1 << hw)) { | |
| 122 | + irq_set_chip_and_handler_name(irq, &intc_dev, | |
| 123 | + handle_edge_irq, "edge"); | |
| 124 | + irq_clear_status_flags(irq, IRQ_LEVEL); | |
| 125 | + } else { | |
| 126 | + irq_set_chip_and_handler_name(irq, &intc_dev, | |
| 127 | + handle_level_irq, "level"); | |
| 128 | + irq_set_status_flags(irq, IRQ_LEVEL); | |
| 129 | + } | |
| 130 | + return 0; | |
| 131 | +} | |
| 132 | + | |
| 133 | +static const struct irq_domain_ops xintc_irq_domain_ops = { | |
| 134 | + .xlate = irq_domain_xlate_onetwocell, | |
| 135 | + .map = xintc_map, | |
| 136 | +}; | |
| 137 | + | |
| 138 | +static void xil_intc_irq_handler(struct irq_desc *desc) | |
| 139 | +{ | |
| 140 | + struct irq_chip *chip = irq_desc_get_chip(desc); | |
| 141 | + u32 pending; | |
| 142 | + | |
| 143 | + chained_irq_enter(chip, desc); | |
| 144 | + do { | |
| 145 | + pending = xintc_get_irq(); | |
| 146 | + if (pending == -1U) | |
| 147 | + break; | |
| 148 | + generic_handle_irq(pending); | |
| 149 | + } while (true); | |
| 150 | + chained_irq_exit(chip, desc); | |
| 151 | +} | |
| 152 | + | |
| 153 | +static int __init xilinx_intc_of_init(struct device_node *intc, | |
| 154 | + struct device_node *parent) | |
| 155 | +{ | |
| 156 | + u32 nr_irq; | |
| 157 | + int ret, irq; | |
| 158 | + struct xintc_irq_chip *irqc; | |
| 159 | + | |
| 160 | + if (xintc_irqc) { | |
| 161 | + pr_err("irq-xilinx: Multiple instances aren't supported\n"); | |
| 162 | + return -EINVAL; | |
| 163 | + } | |
| 164 | + | |
| 165 | + irqc = kzalloc(sizeof(*irqc), GFP_KERNEL); | |
| 166 | + if (!irqc) | |
| 167 | + return -ENOMEM; | |
| 168 | + | |
| 169 | + xintc_irqc = irqc; | |
| 170 | + | |
| 171 | + irqc->base = of_iomap(intc, 0); | |
| 172 | + BUG_ON(!irqc->base); | |
| 173 | + | |
| 174 | + ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); | |
| 175 | + if (ret < 0) { | |
| 176 | + pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n"); | |
| 177 | + goto err_alloc; | |
| 178 | + } | |
| 179 | + | |
| 180 | + ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask); | |
| 181 | + if (ret < 0) { | |
| 182 | + pr_warn("irq-xilinx: unable to read xlnx,kind-of-intr\n"); | |
| 183 | + irqc->intr_mask = 0; | |
| 184 | + } | |
| 185 | + | |
| 186 | + if (irqc->intr_mask >> nr_irq) | |
| 187 | + pr_warn("irq-xilinx: mismatch in kind-of-intr param\n"); | |
| 188 | + | |
| 189 | + pr_info("irq-xilinx: %s: num_irq=%d, edge=0x%x\n", | |
| 190 | + intc->full_name, nr_irq, irqc->intr_mask); | |
| 191 | + | |
| 192 | + | |
| 193 | + /* | |
| 194 | + * Disable all external interrupts until they are | |
| 195 | + * explicity requested. | |
| 196 | + */ | |
| 197 | + xintc_write(IER, 0); | |
| 198 | + | |
| 199 | + /* Acknowledge any pending interrupts just in case. */ | |
| 200 | + xintc_write(IAR, 0xffffffff); | |
| 201 | + | |
| 202 | + /* Turn on the Master Enable. */ | |
| 203 | + xintc_write(MER, MER_HIE | MER_ME); | |
| 204 | + if (!(xintc_read(MER) & (MER_HIE | MER_ME))) { | |
| 205 | + static_branch_enable(&xintc_is_be); | |
| 206 | + xintc_write(MER, MER_HIE | MER_ME); | |
| 207 | + } | |
| 208 | + | |
| 209 | + irqc->root_domain = irq_domain_add_linear(intc, nr_irq, | |
| 210 | + &xintc_irq_domain_ops, irqc); | |
| 211 | + if (!irqc->root_domain) { | |
| 212 | + pr_err("irq-xilinx: Unable to create IRQ domain\n"); | |
| 213 | + goto err_alloc; | |
| 214 | + } | |
| 215 | + | |
| 216 | + if (parent) { | |
| 217 | + irq = irq_of_parse_and_map(intc, 0); | |
| 218 | + if (irq) { | |
| 219 | + irq_set_chained_handler_and_data(irq, | |
| 220 | + xil_intc_irq_handler, | |
| 221 | + irqc); | |
| 222 | + } else { | |
| 223 | + pr_err("irq-xilinx: interrupts property not in DT\n"); | |
| 224 | + ret = -EINVAL; | |
| 225 | + goto err_alloc; | |
| 226 | + } | |
| 227 | + } else { | |
| 228 | + irq_set_default_host(irqc->root_domain); | |
| 229 | + } | |
| 230 | + | |
| 231 | + return 0; | |
| 232 | + | |
| 233 | +err_alloc: | |
| 234 | + xintc_irqc = NULL; | |
| 235 | + kfree(irqc); | |
| 236 | + return ret; | |
| 237 | + | |
| 238 | +} | |
| 239 | + | |
| 240 | +IRQCHIP_DECLARE(xilinx_intc_xps, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init); | |
| 241 | +IRQCHIP_DECLARE(xilinx_intc_opb, "xlnx,opb-intc-1.00.c", xilinx_intc_of_init); | |
| @@ -551,14 +551,14 @@ error_attrs: · 550 unmodified lines | ||
| 551 | 551 | } |
| 552 | 552 | |
| 553 | 553 | static struct msi_desc * |
| 554 | −msi_setup_entry(struct pci_dev *dev, int nvec, bool affinity) | |
| 554 | +msi_setup_entry(struct pci_dev *dev, int nvec, const struct irq_affinity *affd) | |
| 555 | 555 | { |
| 556 | 556 | struct cpumask *masks = NULL; |
| 557 | 557 | struct msi_desc *entry; |
| 558 | 558 | u16 control; |
| 559 | 559 | |
| 560 | − if (affinity) { | |
| 561 | − masks = irq_create_affinity_masks(dev->irq_affinity, nvec); | |
| 560 | + if (affd) { | |
| 561 | + masks = irq_create_affinity_masks(nvec, affd); | |
| 562 | 562 | if (!masks) |
| 563 | 563 | pr_err("Unable to allocate affinity masks, ignoring\n"); |
| 564 | 564 | } |
| @@ -618,7 +618,8 @@ static int msi_verify_entries(struct pci_dev *dev) · 53 unmodified lines | ||
| 618 | 618 | * an error, and a positive return value indicates the number of interrupts |
| 619 | 619 | * which could have been allocated. |
| 620 | 620 | */ |
| 621 | −static int msi_capability_init(struct pci_dev *dev, int nvec, bool affinity) | |
| 621 | +static int msi_capability_init(struct pci_dev *dev, int nvec, | |
| 622 | + const struct irq_affinity *affd) | |
| 622 | 623 | { |
| 623 | 624 | struct msi_desc *entry; |
| 624 | 625 | int ret; |
| @@ -626,7 +627,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec, bool affinity) · 1 unmodified line | ||
| 626 | 627 | |
| 627 | 628 | pci_msi_set_enable(dev, 0); /* Disable MSI during set up */ |
| 628 | 629 | |
| 629 | − entry = msi_setup_entry(dev, nvec, affinity); | |
| 630 | + entry = msi_setup_entry(dev, nvec, affd); | |
| 630 | 631 | if (!entry) |
| 631 | 632 | return -ENOMEM; |
| 632 | 633 | |
| @@ -690,14 +691,14 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries) · 57 unmodified lines | ||
| 690 | 691 | |
| 691 | 692 | static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, |
| 692 | 693 | struct msix_entry *entries, int nvec, |
| 693 | − bool affinity) | |
| 694 | + const struct irq_affinity *affd) | |
| 694 | 695 | { |
| 695 | 696 | struct cpumask *curmsk, *masks = NULL; |
| 696 | 697 | struct msi_desc *entry; |
| 697 | 698 | int ret, i; |
| 698 | 699 | |
| 699 | − if (affinity) { | |
| 700 | − masks = irq_create_affinity_masks(dev->irq_affinity, nvec); | |
| 700 | + if (affd) { | |
| 701 | + masks = irq_create_affinity_masks(nvec, affd); | |
| 701 | 702 | if (!masks) |
| 702 | 703 | pr_err("Unable to allocate affinity masks, ignoring\n"); |
| 703 | 704 | } |
| @@ -753,14 +754,14 @@ static void msix_program_entries(struct pci_dev *dev, · 49 unmodified lines | ||
| 753 | 754 | * @dev: pointer to the pci_dev data structure of MSI-X device function |
| 754 | 755 | * @entries: pointer to an array of struct msix_entry entries |
| 755 | 756 | * @nvec: number of @entries |
| 756 | − * @affinity: flag to indicate cpu irq affinity mask should be set | |
| 757 | + * @affd: Optional pointer to enable automatic affinity assignement | |
| 757 | 758 | * |
| 758 | 759 | * Setup the MSI-X capability structure of device function with a |
| 759 | 760 | * single MSI-X irq. A return of zero indicates the successful setup of |
| 760 | 761 | * requested MSI-X entries with allocated irqs or non-zero for otherwise. |
| 761 | 762 | **/ |
| 762 | 763 | static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, |
| 763 | − int nvec, bool affinity) | |
| 764 | + int nvec, const struct irq_affinity *affd) | |
| 764 | 765 | { |
| 765 | 766 | int ret; |
| 766 | 767 | u16 control; |
| @@ -775,7 +776,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, · 8 unmodified lines | ||
| 775 | 776 | if (!base) |
| 776 | 777 | return -ENOMEM; |
| 777 | 778 | |
| 778 | − ret = msix_setup_entries(dev, base, entries, nvec, affinity); | |
| 779 | + ret = msix_setup_entries(dev, base, entries, nvec, affd); | |
| 779 | 780 | if (ret) |
| 780 | 781 | return ret; |
| 781 | 782 | |
| @@ -956,7 +957,7 @@ int pci_msix_vec_count(struct pci_dev *dev) · 174 unmodified lines | ||
| 956 | 957 | EXPORT_SYMBOL(pci_msix_vec_count); |
| 957 | 958 | |
| 958 | 959 | static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, |
| 959 | − int nvec, bool affinity) | |
| 960 | + int nvec, const struct irq_affinity *affd) | |
| 960 | 961 | { |
| 961 | 962 | int nr_entries; |
| 962 | 963 | int i, j; |
| @@ -988,7 +989,7 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, · 25 unmodified lines | ||
| 988 | 989 | dev_info(&dev->dev, "can't enable MSI-X (MSI IRQ already assigned)\n"); |
| 989 | 990 | return -EINVAL; |
| 990 | 991 | } |
| 991 | − return msix_capability_init(dev, entries, nvec, affinity); | |
| 992 | + return msix_capability_init(dev, entries, nvec, affd); | |
| 992 | 993 | } |
| 993 | 994 | |
| 994 | 995 | /** |
| @@ -1008,7 +1009,7 @@ static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, · 13 unmodified lines | ||
| 1008 | 1009 | **/ |
| 1009 | 1010 | int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) |
| 1010 | 1011 | { |
| 1011 | − return __pci_enable_msix(dev, entries, nvec, false); | |
| 1012 | + return __pci_enable_msix(dev, entries, nvec, NULL); | |
| 1012 | 1013 | } |
| 1013 | 1014 | EXPORT_SYMBOL(pci_enable_msix); |
| 1014 | 1015 | |
| @@ -1059,9 +1060,8 @@ int pci_msi_enabled(void) · 44 unmodified lines | ||
| 1059 | 1060 | EXPORT_SYMBOL(pci_msi_enabled); |
| 1060 | 1061 | |
| 1061 | 1062 | static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, |
| 1062 | − unsigned int flags) | |
| 1063 | + const struct irq_affinity *affd) | |
| 1063 | 1064 | { |
| 1064 | − bool affinity = flags & PCI_IRQ_AFFINITY; | |
| 1065 | 1065 | int nvec; |
| 1066 | 1066 | int rc; |
| 1067 | 1067 | |
| @@ -1090,14 +1090,13 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, · 22 unmodified lines | ||
| 1090 | 1090 | nvec = maxvec; |
| 1091 | 1091 | |
| 1092 | 1092 | for (;;) { |
| 1093 | − if (affinity) { | |
| 1094 | − nvec = irq_calc_affinity_vectors(dev->irq_affinity, | |
| 1095 | − nvec); | |
| 1093 | + if (affd) { | |
| 1094 | + nvec = irq_calc_affinity_vectors(nvec, affd); | |
| 1096 | 1095 | if (nvec < minvec) |
| 1097 | 1096 | return -ENOSPC; |
| 1098 | 1097 | } |
| 1099 | 1098 | |
| 1100 | − rc = msi_capability_init(dev, nvec, affinity); | |
| 1099 | + rc = msi_capability_init(dev, nvec, affd); | |
| 1101 | 1100 | if (rc == 0) |
| 1102 | 1101 | return nvec; |
| 1103 | 1102 | |
| @@ -1124,29 +1123,27 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, · 20 unmodified lines | ||
| 1124 | 1123 | **/ |
| 1125 | 1124 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) |
| 1126 | 1125 | { |
| 1127 | − return __pci_enable_msi_range(dev, minvec, maxvec, 0); | |
| 1126 | + return __pci_enable_msi_range(dev, minvec, maxvec, NULL); | |
| 1128 | 1127 | } |
| 1129 | 1128 | EXPORT_SYMBOL(pci_enable_msi_range); |
| 1130 | 1129 | |
| 1131 | 1130 | static int __pci_enable_msix_range(struct pci_dev *dev, |
| 1132 | − struct msix_entry *entries, int minvec, int maxvec, | |
| 1133 | − unsigned int flags) | |
| 1131 | + struct msix_entry *entries, int minvec, | |
| 1132 | + int maxvec, const struct irq_affinity *affd) | |
| 1134 | 1133 | { |
| 1135 | − bool affinity = flags & PCI_IRQ_AFFINITY; | |
| 1136 | 1134 | int rc, nvec = maxvec; |
| 1137 | 1135 | |
| 1138 | 1136 | if (maxvec < minvec) |
| 1139 | 1137 | return -ERANGE; |
| 1140 | 1138 | |
| 1141 | 1139 | for (;;) { |
| 1142 | − if (affinity) { | |
| 1143 | − nvec = irq_calc_affinity_vectors(dev->irq_affinity, | |
| 1144 | − nvec); | |
| 1140 | + if (affd) { | |
| 1141 | + nvec = irq_calc_affinity_vectors(nvec, affd); | |
| 1145 | 1142 | if (nvec < minvec) |
| 1146 | 1143 | return -ENOSPC; |
| 1147 | 1144 | } |
| 1148 | 1145 | |
| 1149 | − rc = __pci_enable_msix(dev, entries, nvec, affinity); | |
| 1146 | + rc = __pci_enable_msix(dev, entries, nvec, affd); | |
| 1150 | 1147 | if (rc == 0) |
| 1151 | 1148 | return nvec; |
| 1152 | 1149 | |
| @@ -1177,16 +1174,17 @@ static int __pci_enable_msix_range(struct pci_dev *dev, · 24 unmodified lines | ||
| 1177 | 1174 | int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, |
| 1178 | 1175 | int minvec, int maxvec) |
| 1179 | 1176 | { |
| 1180 | − return __pci_enable_msix_range(dev, entries, minvec, maxvec, 0); | |
| 1177 | + return __pci_enable_msix_range(dev, entries, minvec, maxvec, NULL); | |
| 1181 | 1178 | } |
| 1182 | 1179 | EXPORT_SYMBOL(pci_enable_msix_range); |
| 1183 | 1180 | |
| 1184 | 1181 | /** |
| 1185 | − * pci_alloc_irq_vectors - allocate multiple IRQs for a device | |
| 1182 | + * pci_alloc_irq_vectors_affinity - allocate multiple IRQs for a device | |
| 1186 | 1183 | * @dev: PCI device to operate on |
| 1187 | 1184 | * @min_vecs: minimum number of vectors required (must be >= 1) |
| 1188 | 1185 | * @max_vecs: maximum (desired) number of vectors |
| 1189 | 1186 | * @flags: flags or quirks for the allocation |
| 1187 | + * @affd: optional description of the affinity requirements | |
| 1190 | 1188 | * |
| 1191 | 1189 | * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI |
| 1192 | 1190 | * vectors if available, and fall back to a single legacy vector |
| @@ -1198,20 +1196,30 @@ EXPORT_SYMBOL(pci_enable_msix_range); · 5 unmodified lines | ||
| 1198 | 1196 | * To get the Linux IRQ number used for a vector that can be passed to |
| 1199 | 1197 | * request_irq() use the pci_irq_vector() helper. |
| 1200 | 1198 | */ |
| 1201 | −int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, | |
| 1202 | − unsigned int max_vecs, unsigned int flags) | |
| 1199 | +int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, | |
| 1200 | + unsigned int max_vecs, unsigned int flags, | |
| 1201 | + const struct irq_affinity *affd) | |
| 1203 | 1202 | { |
| 1203 | + static const struct irq_affinity msi_default_affd; | |
| 1204 | 1204 | int vecs = -ENOSPC; |
| 1205 | 1205 | |
| 1206 | + if (flags & PCI_IRQ_AFFINITY) { | |
| 1207 | + if (!affd) | |
| 1208 | + affd = &msi_default_affd; | |
| 1209 | + } else { | |
| 1210 | + if (WARN_ON(affd)) | |
| 1211 | + affd = NULL; | |
| 1212 | + } | |
| 1213 | + | |
| 1206 | 1214 | if (flags & PCI_IRQ_MSIX) { |
| 1207 | 1215 | vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, |
| 1208 | − flags); | |
| 1216 | + affd); | |
| 1209 | 1217 | if (vecs > 0) |
| 1210 | 1218 | return vecs; |
| 1211 | 1219 | } |
| 1212 | 1220 | |
| 1213 | 1221 | if (flags & PCI_IRQ_MSI) { |
| 1214 | − vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags); | |
| 1222 | + vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd); | |
| 1215 | 1223 | if (vecs > 0) |
| 1216 | 1224 | return vecs; |
| 1217 | 1225 | } |
| @@ -1224,7 +1232,7 @@ int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, · 6 unmodified lines | ||
| 1224 | 1232 | |
| 1225 | 1233 | return vecs; |
| 1226 | 1234 | } |
| 1227 | −EXPORT_SYMBOL(pci_alloc_irq_vectors); | |
| 1235 | +EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity); | |
| 1228 | 1236 | |
| 1229 | 1237 | /** |
| 1230 | 1238 | * pci_free_irq_vectors - free previously allocated IRQs for a device |
| @@ -232,6 +232,18 @@ struct irq_affinity_notify { · 231 unmodified lines | ||
| 232 | 232 | void (*release)(struct kref *ref); |
| 233 | 233 | }; |
| 234 | 234 | |
| 235 | +/** | |
| 236 | + * struct irq_affinity - Description for automatic irq affinity assignements | |
| 237 | + * @pre_vectors: Don't apply affinity to @pre_vectors at beginning of | |
| 238 | + * the MSI(-X) vector space | |
| 239 | + * @post_vectors: Don't apply affinity to @post_vectors at end of | |
| 240 | + * the MSI(-X) vector space | |
| 241 | + */ | |
| 242 | +struct irq_affinity { | |
| 243 | + int pre_vectors; | |
| 244 | + int post_vectors; | |
| 245 | +}; | |
| 246 | + | |
| 235 | 247 | #if defined(CONFIG_SMP) |
| 236 | 248 | |
| 237 | 249 | extern cpumask_var_t irq_default_affinity; |
| @@ -278,8 +290,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); · 40 unmodified lines | ||
| 278 | 290 | extern int |
| 279 | 291 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); |
| 280 | 292 | |
| 281 | −struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, int nvec); | |
| 282 | −int irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec); | |
| 293 | +struct cpumask *irq_create_affinity_masks(int nvec, const struct irq_affinity *affd); | |
| 294 | +int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd); | |
| 283 | 295 | |
| 284 | 296 | #else /* CONFIG_SMP */ |
| 285 | 297 | |
| @@ -313,13 +325,13 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) · 27 unmodified lines | ||
| 313 | 325 | } |
| 314 | 326 | |
| 315 | 327 | static inline struct cpumask * |
| 316 | −irq_create_affinity_masks(const struct cpumask *affinity, int nvec) | |
| 328 | +irq_create_affinity_masks(int nvec, const struct irq_affinity *affd) | |
| 317 | 329 | { |
| 318 | 330 | return NULL; |
| 319 | 331 | } |
| 320 | 332 | |
| 321 | 333 | static inline int |
| 322 | −irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec) | |
| 334 | +irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd) | |
| 323 | 335 | { |
| 324 | 336 | return maxvec; |
| 325 | 337 | } |
| @@ -239,7 +239,7 @@ · 238 unmodified lines | ||
| 239 | 239 | #define GITS_TYPER_PTA (1UL << 19) |
| 240 | 240 | #define GITS_TYPER_HWCOLLCNT_SHIFT 24 |
| 241 | 241 | |
| 242 | −#define GITS_CBASER_VALID (1UL << 63) | |
| 242 | +#define GITS_CBASER_VALID (1ULL << 63) | |
| 243 | 243 | #define GITS_CBASER_SHAREABILITY_SHIFT (10) |
| 244 | 244 | #define GITS_CBASER_INNER_CACHEABILITY_SHIFT (59) |
| 245 | 245 | #define GITS_CBASER_OUTER_CACHEABILITY_SHIFT (53) |
| @@ -265,7 +265,7 @@ · 19 unmodified lines | ||
| 265 | 265 | |
| 266 | 266 | #define GITS_BASER_NR_REGS 8 |
| 267 | 267 | |
| 268 | −#define GITS_BASER_VALID (1UL << 63) | |
| 268 | +#define GITS_BASER_VALID (1ULL << 63) | |
| 269 | 269 | #define GITS_BASER_INDIRECT (1ULL << 62) |
| 270 | 270 | |
| 271 | 271 | #define GITS_BASER_INNER_CACHEABILITY_SHIFT (59) |
| @@ -244,6 +244,7 @@ struct pci_cap_saved_state { · 243 unmodified lines | ||
| 244 | 244 | struct pci_cap_saved_data cap; |
| 245 | 245 | }; |
| 246 | 246 | |
| 247 | +struct irq_affinity; | |
| 247 | 248 | struct pcie_link_state; |
| 248 | 249 | struct pci_vpd; |
| 249 | 250 | struct pci_sriov; |
| @@ -332,7 +333,6 @@ struct pci_dev { · 82 unmodified lines | ||
| 332 | 333 | * directly, use the values stored here. They might be different! |
| 333 | 334 | */ |
| 334 | 335 | unsigned int irq; |
| 335 | − struct cpumask *irq_affinity; | |
| 336 | 336 | struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ |
| 337 | 337 | |
| 338 | 338 | bool match_driver; /* Skip attaching driver */ |
| @@ -1310,8 +1310,10 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev, · 971 unmodified lines | ||
| 1310 | 1310 | return rc; |
| 1311 | 1311 | return 0; |
| 1312 | 1312 | } |
| 1313 | −int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, | |
| 1314 | − unsigned int max_vecs, unsigned int flags); | |
| 1313 | +int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, | |
| 1314 | + unsigned int max_vecs, unsigned int flags, | |
| 1315 | + const struct irq_affinity *affd); | |
| 1316 | + | |
| 1315 | 1317 | void pci_free_irq_vectors(struct pci_dev *dev); |
| 1316 | 1318 | int pci_irq_vector(struct pci_dev *dev, unsigned int nr); |
| 1317 | 1319 | const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec); |
| @@ -1339,14 +1341,17 @@ static inline int pci_enable_msix_range(struct pci_dev *dev, · 21 unmodified lines | ||
| 1339 | 1341 | static inline int pci_enable_msix_exact(struct pci_dev *dev, |
| 1340 | 1342 | struct msix_entry *entries, int nvec) |
| 1341 | 1343 | { return -ENOSYS; } |
| 1342 | −static inline int pci_alloc_irq_vectors(struct pci_dev *dev, | |
| 1343 | − unsigned int min_vecs, unsigned int max_vecs, | |
| 1344 | − unsigned int flags) | |
| 1344 | + | |
| 1345 | +static inline int | |
| 1346 | +pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, | |
| 1347 | + unsigned int max_vecs, unsigned int flags, | |
| 1348 | + const struct irq_affinity *aff_desc) | |
| 1345 | 1349 | { |
| 1346 | 1350 | if (min_vecs > 1) |
| 1347 | 1351 | return -EINVAL; |
| 1348 | 1352 | return 1; |
| 1349 | 1353 | } |
| 1354 | + | |
| 1350 | 1355 | static inline void pci_free_irq_vectors(struct pci_dev *dev) |
| 1351 | 1356 | { |
| 1352 | 1357 | } |
| @@ -1364,6 +1369,14 @@ static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, · 11 unmodified lines | ||
| 1364 | 1369 | } |
| 1365 | 1370 | #endif |
| 1366 | 1371 | |
| 1372 | +static inline int | |
| 1373 | +pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, | |
| 1374 | + unsigned int max_vecs, unsigned int flags) | |
| 1375 | +{ | |
| 1376 | + return pci_alloc_irq_vectors_affinity(dev, min_vecs, max_vecs, flags, | |
| 1377 | + NULL); | |
| 1378 | +} | |
| 1379 | + | |
| 1367 | 1380 | #ifdef CONFIG_PCIEPORTBUS |
| 1368 | 1381 | extern bool pcie_ports_disabled; |
| 1369 | 1382 | extern bool pcie_ports_auto; |
| @@ -51,16 +51,17 @@ static int get_nodes_in_cpumask(const struct cpumask *mask, nodemask_t *nodemsk) · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | 53 | * irq_create_affinity_masks - Create affinity masks for multiqueue spreading |
| 54 | − * @affinity: The affinity mask to spread. If NULL cpu_online_mask | |
| 55 | − * is used | |
| 56 | − * @nvecs: The number of vectors | |
| 54 | + * @nvecs: The total number of vectors | |
| 55 | + * @affd: Description of the affinity requirements | |
| 57 | 56 | * |
| 58 | 57 | * Returns the masks pointer or NULL if allocation failed. |
| 59 | 58 | */ |
| 60 | −struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, | |
| 61 | − int nvec) | |
| 59 | +struct cpumask * | |
| 60 | +irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd) | |
| 62 | 61 | { |
| 63 | − int n, nodes, vecs_per_node, cpus_per_vec, extra_vecs, curvec = 0; | |
| 62 | + int n, nodes, vecs_per_node, cpus_per_vec, extra_vecs, curvec; | |
| 63 | + int affv = nvecs - affd->pre_vectors - affd->post_vectors; | |
| 64 | + int last_affv = affv + affd->pre_vectors; | |
| 64 | 65 | nodemask_t nodemsk = NODE_MASK_NONE; |
| 65 | 66 | struct cpumask *masks; |
| 66 | 67 | cpumask_var_t nmsk; |
| @@ -68,46 +69,47 @@ struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, · 1 unmodified line | ||
| 68 | 69 | if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) |
| 69 | 70 | return NULL; |
| 70 | 71 | |
| 71 | − masks = kzalloc(nvec * sizeof(*masks), GFP_KERNEL); | |
| 72 | + masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL); | |
| 72 | 73 | if (!masks) |
| 73 | 74 | goto out; |
| 74 | 75 | |
| 76 | + /* Fill out vectors at the beginning that don't need affinity */ | |
| 77 | + for (curvec = 0; curvec < affd->pre_vectors; curvec++) | |
| 78 | + cpumask_copy(masks + curvec, irq_default_affinity); | |
| 79 | + | |
| 75 | 80 | /* Stabilize the cpumasks */ |
| 76 | 81 | get_online_cpus(); |
| 77 | − /* If the supplied affinity mask is NULL, use cpu online mask */ | |
| 78 | − if (!affinity) | |
| 79 | − affinity = cpu_online_mask; | |
| 80 | − | |
| 81 | − nodes = get_nodes_in_cpumask(affinity, &nodemsk); | |
| 82 | + nodes = get_nodes_in_cpumask(cpu_online_mask, &nodemsk); | |
| 82 | 83 | |
| 83 | 84 | /* |
| 84 | 85 | * If the number of nodes in the mask is less than or equal the |
| 85 | 86 | * number of vectors we just spread the vectors across the nodes. |
| 86 | 87 | */ |
| 87 | − if (nvec <= nodes) { | |
| 88 | + if (affv <= nodes) { | |
| 88 | 89 | for_each_node_mask(n, nodemsk) { |
| 89 | 90 | cpumask_copy(masks + curvec, cpumask_of_node(n)); |
| 90 | − if (++curvec == nvec) | |
| 91 | + if (++curvec == last_affv) | |
| 91 | 92 | break; |
| 92 | 93 | } |
| 93 | − goto outonl; | |
| 94 | + goto done; | |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | 97 | /* Spread the vectors per node */ |
| 97 | − vecs_per_node = nvec / nodes; | |
| 98 | + vecs_per_node = affv / nodes; | |
| 98 | 99 | /* Account for rounding errors */ |
| 99 | − extra_vecs = nvec - (nodes * vecs_per_node); | |
| 100 | + extra_vecs = affv - (nodes * vecs_per_node); | |
| 100 | 101 | |
| 101 | 102 | for_each_node_mask(n, nodemsk) { |
| 102 | 103 | int ncpus, v, vecs_to_assign = vecs_per_node; |
| 103 | 104 | |
| 104 | 105 | /* Get the cpus on this node which are in the mask */ |
| 105 | − cpumask_and(nmsk, affinity, cpumask_of_node(n)); | |
| 106 | + cpumask_and(nmsk, cpu_online_mask, cpumask_of_node(n)); | |
| 106 | 107 | |
| 107 | 108 | /* Calculate the number of cpus per vector */ |
| 108 | 109 | ncpus = cpumask_weight(nmsk); |
| 109 | 110 | |
| 110 | − for (v = 0; curvec < nvec && v < vecs_to_assign; curvec++, v++) { | |
| 111 | + for (v = 0; curvec < last_affv && v < vecs_to_assign; | |
| 112 | + curvec++, v++) { | |
| 111 | 113 | cpus_per_vec = ncpus / vecs_to_assign; |
| 112 | 114 | |
| 113 | 115 | /* Account for extra vectors to compensate rounding errors */ |
| @@ -119,36 +121,36 @@ struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, · 5 unmodified lines | ||
| 119 | 121 | irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec); |
| 120 | 122 | } |
| 121 | 123 | |
| 122 | − if (curvec >= nvec) | |
| 124 | + if (curvec >= last_affv) | |
| 123 | 125 | break; |
| 124 | 126 | } |
| 125 | 127 | |
| 126 | −outonl: | |
| 128 | +done: | |
| 127 | 129 | put_online_cpus(); |
| 130 | + | |
| 131 | + /* Fill out vectors at the end that don't need affinity */ | |
| 132 | + for (; curvec < nvecs; curvec++) | |
| 133 | + cpumask_copy(masks + curvec, irq_default_affinity); | |
| 128 | 134 | out: |
| 129 | 135 | free_cpumask_var(nmsk); |
| 130 | 136 | return masks; |
| 131 | 137 | } |
| 132 | 138 | |
| 133 | 139 | /** |
| 134 | − * irq_calc_affinity_vectors - Calculate to optimal number of vectors for a given affinity mask | |
| 135 | − * @affinity: The affinity mask to spread. If NULL cpu_online_mask | |
| 136 | − * is used | |
| 137 | − * @maxvec: The maximum number of vectors available | |
| 140 | + * irq_calc_affinity_vectors - Calculate the optimal number of vectors | |
| 141 | + * @maxvec: The maximum number of vectors available | |
| 142 | + * @affd: Description of the affinity requirements | |
| 138 | 143 | */ |
| 139 | −int irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec) | |
| 144 | +int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd) | |
| 140 | 145 | { |
| 141 | − int cpus, ret; | |
| 146 | + int resv = affd->pre_vectors + affd->post_vectors; | |
| 147 | + int vecs = maxvec - resv; | |
| 148 | + int cpus; | |
| 142 | 149 | |
| 143 | 150 | /* Stabilize the cpumasks */ |
| 144 | 151 | get_online_cpus(); |
| 145 | − /* If the supplied affinity mask is NULL, use cpu online mask */ | |
| 146 | − if (!affinity) | |
| 147 | − affinity = cpu_online_mask; | |
| 148 | − | |
| 149 | − cpus = cpumask_weight(affinity); | |
| 150 | − ret = (cpus < maxvec) ? cpus : maxvec; | |
| 151 | − | |
| 152 | + cpus = cpumask_weight(cpu_online_mask); | |
| 152 | 153 | put_online_cpus(); |
| 153 | − return ret; | |
| 154 | + | |
| 155 | + return min(cpus, vecs) + resv; | |
| 154 | 156 | } |
| @@ -14,9 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/irq.h> |
| 15 | 15 | #include <linux/irqdomain.h> |
| 16 | 16 | #include <linux/msi.h> |
| 17 | − | |
| 18 | −/* Temparory solution for building, will be removed later */ | |
| 19 | −#include <linux/pci.h> | |
| 17 | +#include <linux/slab.h> | |
| 20 | 18 | |
| 21 | 19 | /** |
| 22 | 20 | * alloc_msi_entry - Allocate an initialize msi_entry |