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 | select ARM_GIC | 703 | select ARM_GIC |
| 704 | select ARM_GIC_V2M if PCI | 704 | select ARM_GIC_V2M if PCI |
| 705 | select ARM_GIC_V3 | 705 | select ARM_GIC_V3 |
| 706 | select ARM_GIC_V3_ITS if PCI | ||
| 706 | select ARM_PSCI | 707 | select ARM_PSCI |
| 707 | select HAVE_ARM_ARCH_TIMER | 708 | select HAVE_ARM_ARCH_TIMER |
| 708 | 709 | ||
| @@ -22,6 +22,7 @@ · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <asm/barrier.h> | 24 | #include <asm/barrier.h> |
| 25 | #include <asm/cacheflush.h> | ||
| 25 | #include <asm/cp15.h> | 26 | #include <asm/cp15.h> |
| 26 | 27 | ||
| 27 | #define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) | 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 | * AArch32, since the syndrome register doesn't provide any information for | 231 | * AArch32, since the syndrome register doesn't provide any information for |
| 231 | * them. | 232 | * them. |
| 232 | * Consequently, the following IO helpers use 32bit accesses. | 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 | writel_relaxed((u32)val, addr); | 237 | writel_relaxed((u32)val, addr); |
| 242 | writel_relaxed((u32)(val >> 32), addr + 4); | 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 | u64 val; | 243 | u64 val; |
| 248 | 244 | ||
| @@ -251,5 +247,49 @@ static inline u64 gic_read_typer(const volatile void __iomem *addr) · 2 unmodified lines | |||
| 251 | return val; | 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 | #endif /* !__ASSEMBLY__ */ | 294 | #endif /* !__ASSEMBLY__ */ |
| 255 | #endif /* !__ASM_ARCH_GICV3_H */ | 295 | #endif /* !__ASM_ARCH_GICV3_H */ |
| @@ -79,19 +79,10 @@ · 78 unmodified lines | |||
| 79 | 79 | ||
| 80 | #include <linux/stringify.h> | 80 | #include <linux/stringify.h> |
| 81 | #include <asm/barrier.h> | 81 | #include <asm/barrier.h> |
| 82 | #include <asm/cacheflush.h> | ||
| 82 | 83 | ||
| 83 | #define read_gicreg(r) \ | 84 | #define read_gicreg read_sysreg_s |
| 84 | ({ \ | 85 | #define write_gicreg write_sysreg_s |
| 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) | ||
| 95 | 86 | ||
| 96 | /* | 87 | /* |
| 97 | * Low-level accessors | 88 | * Low-level accessors |
| @@ -102,13 +93,13 @@ · 4 unmodified lines | |||
| 102 | 93 | ||
| 103 | static inline void gic_write_eoir(u32 irq) | 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 | isb(); | 97 | isb(); |
| 107 | } | 98 | } |
| 108 | 99 | ||
| 109 | static inline void gic_write_dir(u32 irq) | 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 | isb(); | 103 | isb(); |
| 113 | } | 104 | } |
| 114 | 105 | ||
| @@ -116,7 +107,7 @@ static inline u64 gic_read_iar_common(void) · 1 unmodified line | |||
| 116 | { | 107 | { |
| 117 | u64 irqstat; | 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 | dsb(sy); | 111 | dsb(sy); |
| 121 | return irqstat; | 112 | return irqstat; |
| 122 | } | 113 | } |
| @@ -132,12 +123,9 @@ static inline u64 gic_read_iar_cavium_thunderx(void) · 9 unmodified lines | |||
| 132 | { | 123 | { |
| 133 | u64 irqstat; | 124 | u64 irqstat; |
| 134 | 125 | ||
| 135 | asm volatile( | 126 | nops(8); |
| 136 | "nop;nop;nop;nop\n\t" | 127 | irqstat = read_sysreg_s(ICC_IAR1_EL1); |
| 137 | "nop;nop;nop;nop\n\t" | 128 | nops(4); |
| 138 | "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" | ||
| 139 | "nop;nop;nop;nop" | ||
| 140 | : "=r" (irqstat)); | ||
| 141 | mb(); | 129 | mb(); |
| 142 | 130 | ||
| 143 | return irqstat; | 131 | return irqstat; |
| @@ -145,37 +133,34 @@ static inline u64 gic_read_iar_cavium_thunderx(void) · 1 unmodified line | |||
| 145 | 133 | ||
| 146 | static inline void gic_write_pmr(u32 val) | 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 | static inline void gic_write_ctlr(u32 val) | 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 | isb(); | 142 | isb(); |
| 155 | } | 143 | } |
| 156 | 144 | ||
| 157 | static inline void gic_write_grpen1(u32 val) | 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 | isb(); | 148 | isb(); |
| 161 | } | 149 | } |
| 162 | 150 | ||
| 163 | static inline void gic_write_sgi1r(u64 val) | 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 | static inline u32 gic_read_sre(void) | 156 | static inline u32 gic_read_sre(void) |
| 169 | { | 157 | { |
| 170 | u64 val; | 158 | return read_sysreg_s(ICC_SRE_EL1); |
| 171 | |||
| 172 | asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); | ||
| 173 | return val; | ||
| 174 | } | 159 | } |
| 175 | 160 | ||
| 176 | static inline void gic_write_sre(u32 val) | 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 | isb(); | 164 | isb(); |
| 180 | } | 165 | } |
| 181 | 166 | ||
| @@ -187,5 +172,21 @@ static inline void gic_write_bpr1(u32 val) · 5 unmodified lines | |||
| 187 | #define gic_read_typer(c) readq_relaxed(c) | 172 | #define gic_read_typer(c) readq_relaxed(c) |
| 188 | #define gic_write_irouter(v, c) writeq_relaxed(v, c) | 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 | #endif /* __ASSEMBLY__ */ | 191 | #endif /* __ASSEMBLY__ */ |
| 191 | #endif /* __ASM_ARCH_GICV3_H */ | 192 | #endif /* __ASM_ARCH_GICV3_H */ |
| @@ -27,6 +27,7 @@ config MICROBLAZE · 26 unmodified lines | |||
| 27 | select HAVE_MEMBLOCK_NODE_MAP | 27 | select HAVE_MEMBLOCK_NODE_MAP |
| 28 | select HAVE_OPROFILE | 28 | select HAVE_OPROFILE |
| 29 | select IRQ_DOMAIN | 29 | select IRQ_DOMAIN |
| 30 | select XILINX_INTC | ||
| 30 | select MODULES_USE_ELF_RELA | 31 | select MODULES_USE_ELF_RELA |
| 31 | select OF | 32 | select OF |
| 32 | select OF_EARLY_FLATTREE | 33 | select OF_EARLY_FLATTREE |
| @@ -16,6 +16,6 @@ struct pt_regs; · 15 unmodified lines | |||
| 16 | extern void do_IRQ(struct pt_regs *regs); | 16 | extern void do_IRQ(struct pt_regs *regs); |
| 17 | 17 | ||
| 18 | /* should be defined in each interrupt controller driver */ | 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 | #endif /* _ASM_MICROBLAZE_IRQ_H */ | 21 | #endif /* _ASM_MICROBLAZE_IRQ_H */ |
| @@ -15,7 +15,7 @@ endif · 14 unmodified lines | |||
| 15 | extra-y := head.o vmlinux.lds | 15 | extra-y := head.o vmlinux.lds |
| 16 | 16 | ||
| 17 | obj-y += dma.o exceptions.o \ | 17 | obj-y += dma.o exceptions.o \ |
| 18 | hw_exception_handler.o intc.o irq.o \ | 18 | hw_exception_handler.o irq.o \ |
| 19 | platform.o process.o prom.o ptrace.o \ | 19 | platform.o process.o prom.o ptrace.o \ |
| 20 | reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o | 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 | trace_hardirqs_off(); | 29 | trace_hardirqs_off(); |
| 30 | 30 | ||
| 31 | irq_enter(); | 31 | irq_enter(); |
| 32 | irq = get_irq(); | 32 | irq = xintc_get_irq(); |
| 33 | next_irq: | 33 | next_irq: |
| 34 | BUG_ON(!irq); | 34 | BUG_ON(!irq); |
| 35 | generic_handle_irq(irq); | 35 | generic_handle_irq(irq); |
| 36 | 36 | ||
| 37 | irq = get_irq(); | 37 | irq = xintc_get_irq(); |
| 38 | if (irq != -1U) { | 38 | if (irq != -1U) { |
| 39 | pr_debug("next irq: %d\n", irq); | 39 | pr_debug("next irq: %d\n", irq); |
| 40 | ++concurrent_irq; | 40 | ++concurrent_irq; |
| @@ -14,7 +14,7 @@ · 13 unmodified lines | |||
| 14 | #ifdef __KERNEL__ | 14 | #ifdef __KERNEL__ |
| 15 | 15 | ||
| 16 | extern void __init xilinx_intc_init_tree(void); | 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 | #endif /* __KERNEL__ */ | 19 | #endif /* __KERNEL__ */ |
| 20 | #endif /* _ASM_POWERPC_XILINX_INTC_H */ | 20 | #endif /* _ASM_POWERPC_XILINX_INTC_H */ |
| @@ -64,6 +64,7 @@ config XILINX_VIRTEX_GENERIC_BOARD · 63 unmodified lines | |||
| 64 | default n | 64 | default n |
| 65 | select XILINX_VIRTEX_II_PRO | 65 | select XILINX_VIRTEX_II_PRO |
| 66 | select XILINX_VIRTEX_4_FX | 66 | select XILINX_VIRTEX_4_FX |
| 67 | select XILINX_INTC | ||
| 67 | help | 68 | help |
| 68 | This option enables generic support for Xilinx Virtex based boards. | 69 | This option enables generic support for Xilinx Virtex based boards. |
| 69 | 70 | ||
| @@ -48,7 +48,7 @@ define_machine(virtex) { · 47 unmodified lines | |||
| 48 | .probe = virtex_probe, | 48 | .probe = virtex_probe, |
| 49 | .setup_arch = xilinx_pci_init, | 49 | .setup_arch = xilinx_pci_init, |
| 50 | .init_IRQ = xilinx_intc_init_tree, | 50 | .init_IRQ = xilinx_intc_init_tree, |
| 51 | .get_irq = xilinx_intc_get_irq, | 51 | .get_irq = xintc_get_irq, |
| 52 | .restart = ppc4xx_reset_system, | 52 | .restart = ppc4xx_reset_system, |
| 53 | .calibrate_decr = generic_calibrate_decr, | 53 | .calibrate_decr = generic_calibrate_decr, |
| 54 | }; | 54 | }; |
| @@ -241,6 +241,7 @@ config XILINX_VIRTEX440_GENERIC_BOARD · 240 unmodified lines | |||
| 241 | depends on 44x | 241 | depends on 44x |
| 242 | default n | 242 | default n |
| 243 | select XILINX_VIRTEX_5_FXT | 243 | select XILINX_VIRTEX_5_FXT |
| 244 | select XILINX_INTC | ||
| 244 | help | 245 | help |
| 245 | This option enables generic support for Xilinx Virtex based boards | 246 | This option enables generic support for Xilinx Virtex based boards |
| 246 | that use a 440 based processor in the Virtex 5 FXT FPGA architecture. | 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 | .probe = virtex_probe, | 54 | .probe = virtex_probe, |
| 55 | .setup_arch = xilinx_pci_init, | 55 | .setup_arch = xilinx_pci_init, |
| 56 | .init_IRQ = xilinx_intc_init_tree, | 56 | .init_IRQ = xilinx_intc_init_tree, |
| 57 | .get_irq = xilinx_intc_get_irq, | 57 | .get_irq = xintc_get_irq, |
| 58 | .calibrate_decr = generic_calibrate_decr, | 58 | .calibrate_decr = generic_calibrate_decr, |
| 59 | .restart = ppc4xx_reset_system, | 59 | .restart = ppc4xx_reset_system, |
| 60 | }; | 60 | }; |
| @@ -29,194 +29,7 @@ · 28 unmodified lines | |||
| 29 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
| 30 | #include <asm/i8259.h> | 30 | #include <asm/i8259.h> |
| 31 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
| 32 | 32 | #include <linux/irqchip.h> | |
| 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 | } | ||
| 220 | 33 | ||
| 221 | #if defined(CONFIG_PPC_I8259) | 34 | #if defined(CONFIG_PPC_I8259) |
| 222 | /* | 35 | /* |
| @@ -265,31 +78,11 @@ static void __init xilinx_i8259_setup_cascade(void) · 42 unmodified lines | |||
| 265 | static inline void xilinx_i8259_setup_cascade(void) { return; } | 78 | static inline void xilinx_i8259_setup_cascade(void) { return; } |
| 266 | #endif /* defined(CONFIG_PPC_I8259) */ | 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 | * Initialize master Xilinx interrupt controller | 82 | * Initialize master Xilinx interrupt controller |
| 276 | */ | 83 | */ |
| 277 | void __init xilinx_intc_init_tree(void) | 84 | void __init xilinx_intc_init_tree(void) |
| 278 | { | 85 | { |
| 279 | struct device_node *np; | 86 | irqchip_init(); |
| 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 | |||
| 294 | xilinx_i8259_setup_cascade(); | 87 | xilinx_i8259_setup_cascade(); |
| 295 | } | 88 | } |
| @@ -211,6 +211,10 @@ config XTENSA_MX · 210 unmodified lines | |||
| 211 | bool | 211 | bool |
| 212 | select IRQ_DOMAIN | 212 | select IRQ_DOMAIN |
| 213 | 213 | ||
| 214 | config XILINX_INTC | ||
| 215 | bool | ||
| 216 | select IRQ_DOMAIN | ||
| 217 | |||
| 214 | config IRQ_CROSSBAR | 218 | config IRQ_CROSSBAR |
| 215 | bool | 219 | bool |
| 216 | help | 220 | help |
| @@ -52,6 +52,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o · 51 unmodified lines | |||
| 52 | obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o | 52 | obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o |
| 53 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | 53 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
| 54 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 54 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
| 55 | obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o | ||
| 55 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o | 56 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
| 56 | obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o | 57 | obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o |
| 57 | obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o | 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 | return 0; | 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 | static int __init bcm7038_l1_init_one(struct device_node *dn, | 243 | static int __init bcm7038_l1_init_one(struct device_node *dn, |
| 219 | unsigned int idx, | 244 | unsigned int idx, |
| 220 | struct bcm7038_l1_chip *intc) | 245 | struct bcm7038_l1_chip *intc) |
| @@ -266,6 +291,7 @@ static struct irq_chip bcm7038_l1_irq_chip = { · 45 unmodified lines | |||
| 266 | .irq_mask = bcm7038_l1_mask, | 291 | .irq_mask = bcm7038_l1_mask, |
| 267 | .irq_unmask = bcm7038_l1_unmask, | 292 | .irq_unmask = bcm7038_l1_unmask, |
| 268 | .irq_set_affinity = bcm7038_l1_set_affinity, | 293 | .irq_set_affinity = bcm7038_l1_set_affinity, |
| 294 | .irq_cpu_offline = bcm7038_l1_cpu_offline, | ||
| 269 | }; | 295 | }; |
| 270 | 296 | ||
| 271 | static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, | 297 | static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, |
| @@ -37,7 +37,6 @@ · 36 unmodified lines | |||
| 37 | #include <linux/irqchip.h> | 37 | #include <linux/irqchip.h> |
| 38 | #include <linux/irqchip/arm-gic-v3.h> | 38 | #include <linux/irqchip/arm-gic-v3.h> |
| 39 | 39 | ||
| 40 | #include <asm/cacheflush.h> | ||
| 41 | #include <asm/cputype.h> | 40 | #include <asm/cputype.h> |
| 42 | #include <asm/exception.h> | 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 | static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) | 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 | cmd->raw_cmd[0] |= cmd_nr; | 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 | static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) | 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 | cmd->raw_cmd[1] |= id; | 211 | cmd->raw_cmd[1] |= id; |
| 213 | } | 212 | } |
| 214 | 213 | ||
| 215 | static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) | 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 | cmd->raw_cmd[1] |= ((u64)phys_id) << 32; | 217 | cmd->raw_cmd[1] |= ((u64)phys_id) << 32; |
| 219 | } | 218 | } |
| 220 | 219 | ||
| 221 | static void its_encode_size(struct its_cmd_block *cmd, u8 size) | 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 | cmd->raw_cmd[1] |= size & 0x1f; | 223 | cmd->raw_cmd[1] |= size & 0x1f; |
| 225 | } | 224 | } |
| 226 | 225 | ||
| 227 | static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) | 226 | static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) |
| 228 | { | 227 | { |
| 229 | cmd->raw_cmd[2] &= ~0xffffffffffffUL; | 228 | cmd->raw_cmd[2] &= ~0xffffffffffffULL; |
| 230 | cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00UL; | 229 | cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL; |
| 231 | } | 230 | } |
| 232 | 231 | ||
| 233 | static void its_encode_valid(struct its_cmd_block *cmd, int valid) | 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 | cmd->raw_cmd[2] |= ((u64)!!valid) << 63; | 235 | cmd->raw_cmd[2] |= ((u64)!!valid) << 63; |
| 237 | } | 236 | } |
| 238 | 237 | ||
| 239 | static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) | 238 | static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) |
| 240 | { | 239 | { |
| 241 | cmd->raw_cmd[2] &= ~(0xffffffffUL << 16); | 240 | cmd->raw_cmd[2] &= ~(0xffffffffULL << 16); |
| 242 | cmd->raw_cmd[2] |= (target_addr & (0xffffffffUL << 16)); | 241 | cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16)); |
| 243 | } | 242 | } |
| 244 | 243 | ||
| 245 | static void its_encode_collection(struct its_cmd_block *cmd, u16 col) | 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 | cmd->raw_cmd[2] |= col; | 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 | * the ITS. | 432 | * the ITS. |
| 434 | */ | 433 | */ |
| 435 | if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING) | 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 | else | 436 | else |
| 438 | dsb(ishst); | 437 | dsb(ishst); |
| 439 | } | 438 | } |
| @@ -602,7 +601,7 @@ static void lpi_set_config(struct irq_data *d, bool enable) · 162 unmodified lines | |||
| 602 | * Humpf... | 601 | * Humpf... |
| 603 | */ | 602 | */ |
| 604 | if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING) | 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 | else | 605 | else |
| 607 | dsb(ishst); | 606 | dsb(ishst); |
| 608 | its_send_inv(its_dev, id); | 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 | its = its_dev->its; | 656 | its = its_dev->its; |
| 658 | addr = its->phys_base + GITS_TRANSLATER; | 657 | addr = its->phys_base + GITS_TRANSLATER; |
| 659 | 658 | ||
| 660 | msg->address_lo = addr & ((1UL << 32) - 1); | 659 | msg->address_lo = lower_32_bits(addr); |
| 661 | msg->address_hi = addr >> 32; | 660 | msg->address_hi = upper_32_bits(addr); |
| 662 | msg->data = its_get_event_id(d); | 661 | msg->data = its_get_event_id(d); |
| 663 | 662 | ||
| 664 | iommu_dma_map_msi_msg(d->irq, msg); | 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 | LPI_PROPBASE_SZ); | 816 | LPI_PROPBASE_SZ); |
| 818 | 817 | ||
| 819 | /* Make sure the GIC will observe the written configuration */ | 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 | return 0; | 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 | u32 idx = baser - its->tables; | 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 | static void its_write_baser(struct its_node *its, struct its_baser *baser, | 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 | u32 idx = baser - its->tables; | 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 | baser->val = its_read_baser(its, baser); | 847 | baser->val = its_read_baser(its, baser); |
| 849 | } | 848 | } |
| 850 | 849 | ||
| @@ -910,7 +909,7 @@ retry_baser: · 59 unmodified lines | |||
| 910 | shr = tmp & GITS_BASER_SHAREABILITY_MASK; | 909 | shr = tmp & GITS_BASER_SHAREABILITY_MASK; |
| 911 | if (!shr) { | 910 | if (!shr) { |
| 912 | cache = GITS_BASER_nC; | 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 | goto retry_baser; | 914 | goto retry_baser; |
| 916 | } | 915 | } |
| @@ -935,9 +934,9 @@ retry_baser: · 18 unmodified lines | |||
| 935 | } | 934 | } |
| 936 | 935 | ||
| 937 | if (val != tmp) { | 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 | &its->phys_base, its_base_type_string[type], | 938 | &its->phys_base, its_base_type_string[type], |
| 940 | (unsigned long) val, (unsigned long) tmp); | 939 | val, tmp); |
| 941 | free_pages((unsigned long)base, order); | 940 | free_pages((unsigned long)base, order); |
| 942 | return -ENXIO; | 941 | return -ENXIO; |
| 943 | } | 942 | } |
| @@ -948,7 +947,7 @@ retry_baser: · 4 unmodified lines | |||
| 948 | tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; | 947 | tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; |
| 949 | 948 | ||
| 950 | pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", | 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 | its_base_type_string[type], | 951 | its_base_type_string[type], |
| 953 | (unsigned long)virt_to_phys(base), | 952 | (unsigned long)virt_to_phys(base), |
| 954 | indirect ? "indirect" : "flat", (int)esz, | 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 | * which is reported by ITS hardware times lvl1 table | 982 | * which is reported by ITS hardware times lvl1 table |
| 984 | * entry size. | 983 | * entry size. |
| 985 | */ | 984 | */ |
| 986 | ids -= ilog2(psz / esz); | 985 | ids -= ilog2(psz / (int)esz); |
| 987 | esz = GITS_LVL1_ENTRY_SIZE; | 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 | new_order = max_t(u32, get_order(esz << ids), new_order); | 997 | new_order = max_t(u32, get_order(esz << ids), new_order); |
| 999 | if (new_order >= MAX_ORDER) { | 998 | if (new_order >= MAX_ORDER) { |
| 1000 | new_order = MAX_ORDER - 1; | 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 | pr_warn("ITS@%pa: Device Table too large, reduce ids %u->%u\n", | 1001 | pr_warn("ITS@%pa: Device Table too large, reduce ids %u->%u\n", |
| 1003 | &its->phys_base, its->device_ids, ids); | 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 | /* Make sure the GIC will observe the zero-ed page */ | 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 | paddr = page_to_phys(pend_page); | 1106 | paddr = page_to_phys(pend_page); |
| 1108 | pr_info("CPU%d: using LPI pending table @%pa\n", | 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 | GICR_PROPBASER_WaWb | | 1125 | GICR_PROPBASER_WaWb | |
| 1127 | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); | 1126 | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); |
| 1128 | 1127 | ||
| 1129 | writeq_relaxed(val, rbase + GICR_PROPBASER); | 1128 | gicr_write_propbaser(val, rbase + GICR_PROPBASER); |
| 1130 | tmp = readq_relaxed(rbase + GICR_PROPBASER); | 1129 | tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); |
| 1131 | 1130 | ||
| 1132 | if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { | 1131 | if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { |
| 1133 | if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { | 1132 | if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { |
| @@ -1139,7 +1138,7 @@ static void its_cpu_init_lpis(void) · 5 unmodified lines | |||
| 1139 | val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | | 1138 | val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | |
| 1140 | GICR_PROPBASER_CACHEABILITY_MASK); | 1139 | GICR_PROPBASER_CACHEABILITY_MASK); |
| 1141 | val |= GICR_PROPBASER_nC; | 1140 | val |= GICR_PROPBASER_nC; |
| 1142 | writeq_relaxed(val, rbase + GICR_PROPBASER); | 1141 | gicr_write_propbaser(val, rbase + GICR_PROPBASER); |
| 1143 | } | 1142 | } |
| 1144 | pr_info_once("GIC: using cache flushing for LPI property table\n"); | 1143 | pr_info_once("GIC: using cache flushing for LPI property table\n"); |
| 1145 | gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; | 1144 | gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; |
| @@ -1150,8 +1149,8 @@ static void its_cpu_init_lpis(void) · 4 unmodified lines | |||
| 1150 | GICR_PENDBASER_InnerShareable | | 1149 | GICR_PENDBASER_InnerShareable | |
| 1151 | GICR_PENDBASER_WaWb); | 1150 | GICR_PENDBASER_WaWb); |
| 1152 | 1151 | ||
| 1153 | writeq_relaxed(val, rbase + GICR_PENDBASER); | 1152 | gicr_write_pendbaser(val, rbase + GICR_PENDBASER); |
| 1154 | tmp = readq_relaxed(rbase + GICR_PENDBASER); | 1153 | tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); |
| 1155 | 1154 | ||
| 1156 | if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { | 1155 | if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { |
| 1157 | /* | 1156 | /* |
| @@ -1161,7 +1160,7 @@ static void its_cpu_init_lpis(void) · 3 unmodified lines | |||
| 1161 | val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | | 1160 | val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | |
| 1162 | GICR_PENDBASER_CACHEABILITY_MASK); | 1161 | GICR_PENDBASER_CACHEABILITY_MASK); |
| 1163 | val |= GICR_PENDBASER_nC; | 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 | /* Enable LPIs */ | 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 | /* Flush Lvl2 table to PoC if hw doesn't support coherency */ | 1287 | /* Flush Lvl2 table to PoC if hw doesn't support coherency */ |
| 1289 | if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) | 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 | table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); | 1291 | table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); |
| 1293 | 1292 | ||
| 1294 | /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ | 1293 | /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ |
| 1295 | if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) | 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 | /* Ensure updated table contents are visible to ITS hardware */ | 1297 | /* Ensure updated table contents are visible to ITS hardware */ |
| 1299 | dsb(sy); | 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 | return NULL; | 1339 | return NULL; |
| 1341 | } | 1340 | } |
| 1342 | 1341 | ||
| 1343 | __flush_dcache_area(itt, sz); | 1342 | gic_flush_dcache_to_poc(itt, sz); |
| 1344 | 1343 | ||
| 1345 | dev->its = its; | 1344 | dev->its = its; |
| 1346 | dev->itt = itt; | 1345 | dev->itt = itt; |
| @@ -1717,8 +1716,8 @@ static int __init its_probe_one(struct resource *res, · 370 unmodified lines | |||
| 1717 | (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | | 1716 | (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | |
| 1718 | GITS_CBASER_VALID); | 1717 | GITS_CBASER_VALID); |
| 1719 | 1718 | ||
| 1720 | writeq_relaxed(baser, its->base + GITS_CBASER); | 1719 | gits_write_cbaser(baser, its->base + GITS_CBASER); |
| 1721 | tmp = readq_relaxed(its->base + GITS_CBASER); | 1720 | tmp = gits_read_cbaser(its->base + GITS_CBASER); |
| 1722 | 1721 | ||
| 1723 | if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { | 1722 | if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { |
| 1724 | if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { | 1723 | if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { |
| @@ -1730,13 +1729,13 @@ static int __init its_probe_one(struct resource *res, · 5 unmodified lines | |||
| 1730 | baser &= ~(GITS_CBASER_SHAREABILITY_MASK | | 1729 | baser &= ~(GITS_CBASER_SHAREABILITY_MASK | |
| 1731 | GITS_CBASER_CACHEABILITY_MASK); | 1730 | GITS_CBASER_CACHEABILITY_MASK); |
| 1732 | baser |= GITS_CBASER_nC; | 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 | pr_info("ITS: using cache flushing for cmd queue\n"); | 1734 | pr_info("ITS: using cache flushing for cmd queue\n"); |
| 1736 | its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; | 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 | writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); | 1739 | writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); |
| 1741 | 1740 | ||
| 1742 | err = its_init_domain(handle, its); | 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 | static struct msi_desc * | 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 | struct cpumask *masks = NULL; | 556 | struct cpumask *masks = NULL; |
| 557 | struct msi_desc *entry; | 557 | struct msi_desc *entry; |
| 558 | u16 control; | 558 | u16 control; |
| 559 | 559 | ||
| 560 | if (affinity) { | 560 | if (affd) { |
| 561 | masks = irq_create_affinity_masks(dev->irq_affinity, nvec); | 561 | masks = irq_create_affinity_masks(nvec, affd); |
| 562 | if (!masks) | 562 | if (!masks) |
| 563 | pr_err("Unable to allocate affinity masks, ignoring\n"); | 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 | * an error, and a positive return value indicates the number of interrupts | 618 | * an error, and a positive return value indicates the number of interrupts |
| 619 | * which could have been allocated. | 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 | struct msi_desc *entry; | 624 | struct msi_desc *entry; |
| 624 | int ret; | 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 | pci_msi_set_enable(dev, 0); /* Disable MSI during set up */ | 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 | if (!entry) | 631 | if (!entry) |
| 631 | return -ENOMEM; | 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 | static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, | 692 | static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, |
| 692 | struct msix_entry *entries, int nvec, | 693 | struct msix_entry *entries, int nvec, |
| 693 | bool affinity) | 694 | const struct irq_affinity *affd) |
| 694 | { | 695 | { |
| 695 | struct cpumask *curmsk, *masks = NULL; | 696 | struct cpumask *curmsk, *masks = NULL; |
| 696 | struct msi_desc *entry; | 697 | struct msi_desc *entry; |
| 697 | int ret, i; | 698 | int ret, i; |
| 698 | 699 | ||
| 699 | if (affinity) { | 700 | if (affd) { |
| 700 | masks = irq_create_affinity_masks(dev->irq_affinity, nvec); | 701 | masks = irq_create_affinity_masks(nvec, affd); |
| 701 | if (!masks) | 702 | if (!masks) |
| 702 | pr_err("Unable to allocate affinity masks, ignoring\n"); | 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 | * @dev: pointer to the pci_dev data structure of MSI-X device function | 754 | * @dev: pointer to the pci_dev data structure of MSI-X device function |
| 754 | * @entries: pointer to an array of struct msix_entry entries | 755 | * @entries: pointer to an array of struct msix_entry entries |
| 755 | * @nvec: number of @entries | 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 | * Setup the MSI-X capability structure of device function with a | 759 | * Setup the MSI-X capability structure of device function with a |
| 759 | * single MSI-X irq. A return of zero indicates the successful setup of | 760 | * single MSI-X irq. A return of zero indicates the successful setup of |
| 760 | * requested MSI-X entries with allocated irqs or non-zero for otherwise. | 761 | * requested MSI-X entries with allocated irqs or non-zero for otherwise. |
| 761 | **/ | 762 | **/ |
| 762 | static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, | 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 | int ret; | 766 | int ret; |
| 766 | u16 control; | 767 | u16 control; |
| @@ -775,7 +776,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, · 8 unmodified lines | |||
| 775 | if (!base) | 776 | if (!base) |
| 776 | return -ENOMEM; | 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 | if (ret) | 780 | if (ret) |
| 780 | return ret; | 781 | return ret; |
| 781 | 782 | ||
| @@ -956,7 +957,7 @@ int pci_msix_vec_count(struct pci_dev *dev) · 174 unmodified lines | |||
| 956 | EXPORT_SYMBOL(pci_msix_vec_count); | 957 | EXPORT_SYMBOL(pci_msix_vec_count); |
| 957 | 958 | ||
| 958 | static int __pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, | 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 | int nr_entries; | 962 | int nr_entries; |
| 962 | int i, j; | 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 | dev_info(&dev->dev, "can't enable MSI-X (MSI IRQ already assigned)\n"); | 989 | dev_info(&dev->dev, "can't enable MSI-X (MSI IRQ already assigned)\n"); |
| 989 | return -EINVAL; | 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 | int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) | 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 | EXPORT_SYMBOL(pci_enable_msix); | 1014 | EXPORT_SYMBOL(pci_enable_msix); |
| 1014 | 1015 | ||
| @@ -1059,9 +1060,8 @@ int pci_msi_enabled(void) · 44 unmodified lines | |||
| 1059 | EXPORT_SYMBOL(pci_msi_enabled); | 1060 | EXPORT_SYMBOL(pci_msi_enabled); |
| 1060 | 1061 | ||
| 1061 | static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, | 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 | int nvec; | 1065 | int nvec; |
| 1066 | int rc; | 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 | nvec = maxvec; | 1090 | nvec = maxvec; |
| 1091 | 1091 | ||
| 1092 | for (;;) { | 1092 | for (;;) { |
| 1093 | if (affinity) { | 1093 | if (affd) { |
| 1094 | nvec = irq_calc_affinity_vectors(dev->irq_affinity, | 1094 | nvec = irq_calc_affinity_vectors(nvec, affd); |
| 1095 | nvec); | ||
| 1096 | if (nvec < minvec) | 1095 | if (nvec < minvec) |
| 1097 | return -ENOSPC; | 1096 | return -ENOSPC; |
| 1098 | } | 1097 | } |
| 1099 | 1098 | ||
| 1100 | rc = msi_capability_init(dev, nvec, affinity); | 1099 | rc = msi_capability_init(dev, nvec, affd); |
| 1101 | if (rc == 0) | 1100 | if (rc == 0) |
| 1102 | return nvec; | 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 | int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) | 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 | EXPORT_SYMBOL(pci_enable_msi_range); | 1128 | EXPORT_SYMBOL(pci_enable_msi_range); |
| 1130 | 1129 | ||
| 1131 | static int __pci_enable_msix_range(struct pci_dev *dev, | 1130 | static int __pci_enable_msix_range(struct pci_dev *dev, |
| 1132 | struct msix_entry *entries, int minvec, int maxvec, | 1131 | struct msix_entry *entries, int minvec, |
| 1133 | unsigned int flags) | 1132 | int maxvec, const struct irq_affinity *affd) |
| 1134 | { | 1133 | { |
| 1135 | bool affinity = flags & PCI_IRQ_AFFINITY; | ||
| 1136 | int rc, nvec = maxvec; | 1134 | int rc, nvec = maxvec; |
| 1137 | 1135 | ||
| 1138 | if (maxvec < minvec) | 1136 | if (maxvec < minvec) |
| 1139 | return -ERANGE; | 1137 | return -ERANGE; |
| 1140 | 1138 | ||
| 1141 | for (;;) { | 1139 | for (;;) { |
| 1142 | if (affinity) { | 1140 | if (affd) { |
| 1143 | nvec = irq_calc_affinity_vectors(dev->irq_affinity, | 1141 | nvec = irq_calc_affinity_vectors(nvec, affd); |
| 1144 | nvec); | ||
| 1145 | if (nvec < minvec) | 1142 | if (nvec < minvec) |
| 1146 | return -ENOSPC; | 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 | if (rc == 0) | 1147 | if (rc == 0) |
| 1151 | return nvec; | 1148 | return nvec; |
| 1152 | 1149 | ||
| @@ -1177,16 +1174,17 @@ static int __pci_enable_msix_range(struct pci_dev *dev, · 24 unmodified lines | |||
| 1177 | int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, | 1174 | int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, |
| 1178 | int minvec, int maxvec) | 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 | EXPORT_SYMBOL(pci_enable_msix_range); | 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 | * @dev: PCI device to operate on | 1183 | * @dev: PCI device to operate on |
| 1187 | * @min_vecs: minimum number of vectors required (must be >= 1) | 1184 | * @min_vecs: minimum number of vectors required (must be >= 1) |
| 1188 | * @max_vecs: maximum (desired) number of vectors | 1185 | * @max_vecs: maximum (desired) number of vectors |
| 1189 | * @flags: flags or quirks for the allocation | 1186 | * @flags: flags or quirks for the allocation |
| 1187 | * @affd: optional description of the affinity requirements | ||
| 1190 | * | 1188 | * |
| 1191 | * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI | 1189 | * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI |
| 1192 | * vectors if available, and fall back to a single legacy vector | 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 | * To get the Linux IRQ number used for a vector that can be passed to | 1196 | * To get the Linux IRQ number used for a vector that can be passed to |
| 1199 | * request_irq() use the pci_irq_vector() helper. | 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, | 1199 | int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, |
| 1202 | unsigned int max_vecs, unsigned int flags) | 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 | int vecs = -ENOSPC; | 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 | if (flags & PCI_IRQ_MSIX) { | 1214 | if (flags & PCI_IRQ_MSIX) { |
| 1207 | vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, | 1215 | vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, |
| 1208 | flags); | 1216 | affd); |
| 1209 | if (vecs > 0) | 1217 | if (vecs > 0) |
| 1210 | return vecs; | 1218 | return vecs; |
| 1211 | } | 1219 | } |
| 1212 | 1220 | ||
| 1213 | if (flags & PCI_IRQ_MSI) { | 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 | if (vecs > 0) | 1223 | if (vecs > 0) |
| 1216 | return vecs; | 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 | return vecs; | 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 | * pci_free_irq_vectors - free previously allocated IRQs for a device | 1238 | * pci_free_irq_vectors - free previously allocated IRQs for a device |
| @@ -232,6 +232,18 @@ struct irq_affinity_notify { · 231 unmodified lines | |||
| 232 | void (*release)(struct kref *ref); | 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 | #if defined(CONFIG_SMP) | 247 | #if defined(CONFIG_SMP) |
| 236 | 248 | ||
| 237 | extern cpumask_var_t irq_default_affinity; | 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 | extern int | 290 | extern int |
| 279 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); | 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); | 293 | struct cpumask *irq_create_affinity_masks(int nvec, const struct irq_affinity *affd); |
| 282 | int irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec); | 294 | int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd); |
| 283 | 295 | ||
| 284 | #else /* CONFIG_SMP */ | 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 | static inline struct cpumask * | 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 | return NULL; | 330 | return NULL; |
| 319 | } | 331 | } |
| 320 | 332 | ||
| 321 | static inline int | 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 | return maxvec; | 336 | return maxvec; |
| 325 | } | 337 | } |
| @@ -239,7 +239,7 @@ · 238 unmodified lines | |||
| 239 | #define GITS_TYPER_PTA (1UL << 19) | 239 | #define GITS_TYPER_PTA (1UL << 19) |
| 240 | #define GITS_TYPER_HWCOLLCNT_SHIFT 24 | 240 | #define GITS_TYPER_HWCOLLCNT_SHIFT 24 |
| 241 | 241 | ||
| 242 | #define GITS_CBASER_VALID (1UL << 63) | 242 | #define GITS_CBASER_VALID (1ULL << 63) |
| 243 | #define GITS_CBASER_SHAREABILITY_SHIFT (10) | 243 | #define GITS_CBASER_SHAREABILITY_SHIFT (10) |
| 244 | #define GITS_CBASER_INNER_CACHEABILITY_SHIFT (59) | 244 | #define GITS_CBASER_INNER_CACHEABILITY_SHIFT (59) |
| 245 | #define GITS_CBASER_OUTER_CACHEABILITY_SHIFT (53) | 245 | #define GITS_CBASER_OUTER_CACHEABILITY_SHIFT (53) |
| @@ -265,7 +265,7 @@ · 19 unmodified lines | |||
| 265 | 265 | ||
| 266 | #define GITS_BASER_NR_REGS 8 | 266 | #define GITS_BASER_NR_REGS 8 |
| 267 | 267 | ||
| 268 | #define GITS_BASER_VALID (1UL << 63) | 268 | #define GITS_BASER_VALID (1ULL << 63) |
| 269 | #define GITS_BASER_INDIRECT (1ULL << 62) | 269 | #define GITS_BASER_INDIRECT (1ULL << 62) |
| 270 | 270 | ||
| 271 | #define GITS_BASER_INNER_CACHEABILITY_SHIFT (59) | 271 | #define GITS_BASER_INNER_CACHEABILITY_SHIFT (59) |
| @@ -244,6 +244,7 @@ struct pci_cap_saved_state { · 243 unmodified lines | |||
| 244 | struct pci_cap_saved_data cap; | 244 | struct pci_cap_saved_data cap; |
| 245 | }; | 245 | }; |
| 246 | 246 | ||
| 247 | struct irq_affinity; | ||
| 247 | struct pcie_link_state; | 248 | struct pcie_link_state; |
| 248 | struct pci_vpd; | 249 | struct pci_vpd; |
| 249 | struct pci_sriov; | 250 | struct pci_sriov; |
| @@ -332,7 +333,6 @@ struct pci_dev { · 82 unmodified lines | |||
| 332 | * directly, use the values stored here. They might be different! | 333 | * directly, use the values stored here. They might be different! |
| 333 | */ | 334 | */ |
| 334 | unsigned int irq; | 335 | unsigned int irq; |
| 335 | struct cpumask *irq_affinity; | ||
| 336 | struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ | 336 | struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ |
| 337 | 337 | ||
| 338 | bool match_driver; /* Skip attaching driver */ | 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 | return rc; | 1310 | return rc; |
| 1311 | return 0; | 1311 | return 0; |
| 1312 | } | 1312 | } |
| 1313 | int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, | 1313 | int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, |
| 1314 | unsigned int max_vecs, unsigned int flags); | 1314 | unsigned int max_vecs, unsigned int flags, |
| 1315 | const struct irq_affinity *affd); | ||
| 1316 | |||
| 1315 | void pci_free_irq_vectors(struct pci_dev *dev); | 1317 | void pci_free_irq_vectors(struct pci_dev *dev); |
| 1316 | int pci_irq_vector(struct pci_dev *dev, unsigned int nr); | 1318 | int pci_irq_vector(struct pci_dev *dev, unsigned int nr); |
| 1317 | const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec); | 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 | static inline int pci_enable_msix_exact(struct pci_dev *dev, | 1341 | static inline int pci_enable_msix_exact(struct pci_dev *dev, |
| 1340 | struct msix_entry *entries, int nvec) | 1342 | struct msix_entry *entries, int nvec) |
| 1341 | { return -ENOSYS; } | 1343 | { return -ENOSYS; } |
| 1342 | static inline int pci_alloc_irq_vectors(struct pci_dev *dev, | 1344 | |
| 1343 | unsigned int min_vecs, unsigned int max_vecs, | 1345 | static inline int |
| 1344 | unsigned int flags) | 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 | if (min_vecs > 1) | 1350 | if (min_vecs > 1) |
| 1347 | return -EINVAL; | 1351 | return -EINVAL; |
| 1348 | return 1; | 1352 | return 1; |
| 1349 | } | 1353 | } |
| 1354 | |||
| 1350 | static inline void pci_free_irq_vectors(struct pci_dev *dev) | 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 | #endif | 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 | #ifdef CONFIG_PCIEPORTBUS | 1380 | #ifdef CONFIG_PCIEPORTBUS |
| 1368 | extern bool pcie_ports_disabled; | 1381 | extern bool pcie_ports_disabled; |
| 1369 | extern bool pcie_ports_auto; | 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 | * irq_create_affinity_masks - Create affinity masks for multiqueue spreading | 53 | * irq_create_affinity_masks - Create affinity masks for multiqueue spreading |
| 54 | * @affinity: The affinity mask to spread. If NULL cpu_online_mask | 54 | * @nvecs: The total number of vectors |
| 55 | * is used | 55 | * @affd: Description of the affinity requirements |
| 56 | * @nvecs: The number of vectors | ||
| 57 | * | 56 | * |
| 58 | * Returns the masks pointer or NULL if allocation failed. | 57 | * Returns the masks pointer or NULL if allocation failed. |
| 59 | */ | 58 | */ |
| 60 | struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, | 59 | struct cpumask * |
| 61 | int nvec) | 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 | nodemask_t nodemsk = NODE_MASK_NONE; | 65 | nodemask_t nodemsk = NODE_MASK_NONE; |
| 65 | struct cpumask *masks; | 66 | struct cpumask *masks; |
| 66 | cpumask_var_t nmsk; | 67 | cpumask_var_t nmsk; |
| @@ -68,46 +69,47 @@ struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, · 1 unmodified line | |||
| 68 | if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) | 69 | if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) |
| 69 | return NULL; | 70 | return NULL; |
| 70 | 71 | ||
| 71 | masks = kzalloc(nvec * sizeof(*masks), GFP_KERNEL); | 72 | masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL); |
| 72 | if (!masks) | 73 | if (!masks) |
| 73 | goto out; | 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 | /* Stabilize the cpumasks */ | 80 | /* Stabilize the cpumasks */ |
| 76 | get_online_cpus(); | 81 | get_online_cpus(); |
| 77 | /* If the supplied affinity mask is NULL, use cpu online mask */ | 82 | nodes = get_nodes_in_cpumask(cpu_online_mask, &nodemsk); |
| 78 | if (!affinity) | ||
| 79 | affinity = cpu_online_mask; | ||
| 80 | |||
| 81 | nodes = get_nodes_in_cpumask(affinity, &nodemsk); | ||
| 82 | 83 | ||
| 83 | /* | 84 | /* |
| 84 | * If the number of nodes in the mask is less than or equal the | 85 | * If the number of nodes in the mask is less than or equal the |
| 85 | * number of vectors we just spread the vectors across the nodes. | 86 | * number of vectors we just spread the vectors across the nodes. |
| 86 | */ | 87 | */ |
| 87 | if (nvec <= nodes) { | 88 | if (affv <= nodes) { |
| 88 | for_each_node_mask(n, nodemsk) { | 89 | for_each_node_mask(n, nodemsk) { |
| 89 | cpumask_copy(masks + curvec, cpumask_of_node(n)); | 90 | cpumask_copy(masks + curvec, cpumask_of_node(n)); |
| 90 | if (++curvec == nvec) | 91 | if (++curvec == last_affv) |
| 91 | break; | 92 | break; |
| 92 | } | 93 | } |
| 93 | goto outonl; | 94 | goto done; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | /* Spread the vectors per node */ | 97 | /* Spread the vectors per node */ |
| 97 | vecs_per_node = nvec / nodes; | 98 | vecs_per_node = affv / nodes; |
| 98 | /* Account for rounding errors */ | 99 | /* Account for rounding errors */ |
| 99 | extra_vecs = nvec - (nodes * vecs_per_node); | 100 | extra_vecs = affv - (nodes * vecs_per_node); |
| 100 | 101 | ||
| 101 | for_each_node_mask(n, nodemsk) { | 102 | for_each_node_mask(n, nodemsk) { |
| 102 | int ncpus, v, vecs_to_assign = vecs_per_node; | 103 | int ncpus, v, vecs_to_assign = vecs_per_node; |
| 103 | 104 | ||
| 104 | /* Get the cpus on this node which are in the mask */ | 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 | /* Calculate the number of cpus per vector */ | 108 | /* Calculate the number of cpus per vector */ |
| 108 | ncpus = cpumask_weight(nmsk); | 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 | cpus_per_vec = ncpus / vecs_to_assign; | 113 | cpus_per_vec = ncpus / vecs_to_assign; |
| 112 | 114 | ||
| 113 | /* Account for extra vectors to compensate rounding errors */ | 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 | irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec); | 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 | break; | 125 | break; |
| 124 | } | 126 | } |
| 125 | 127 | ||
| 126 | outonl: | 128 | done: |
| 127 | put_online_cpus(); | 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 | out: | 134 | out: |
| 129 | free_cpumask_var(nmsk); | 135 | free_cpumask_var(nmsk); |
| 130 | return masks; | 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 | 140 | * irq_calc_affinity_vectors - Calculate the optimal number of vectors |
| 135 | * @affinity: The affinity mask to spread. If NULL cpu_online_mask | 141 | * @maxvec: The maximum number of vectors available |
| 136 | * is used | 142 | * @affd: Description of the affinity requirements |
| 137 | * @maxvec: The maximum number of vectors available | ||
| 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 | /* Stabilize the cpumasks */ | 150 | /* Stabilize the cpumasks */ |
| 144 | get_online_cpus(); | 151 | get_online_cpus(); |
| 145 | /* If the supplied affinity mask is NULL, use cpu online mask */ | 152 | cpus = cpumask_weight(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 | put_online_cpus(); | 153 | put_online_cpus(); |
| 153 | return ret; | 154 | |
| 155 | return min(cpus, vecs) + resv; | ||
| 154 | } | 156 | } |
| @@ -14,9 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
| 15 | #include <linux/irqdomain.h> | 15 | #include <linux/irqdomain.h> |
| 16 | #include <linux/msi.h> | 16 | #include <linux/msi.h> |
| 17 | 17 | #include <linux/slab.h> | |
| 18 | /* Temparory solution for building, will be removed later */ | ||
| 19 | #include <linux/pci.h> | ||
| 20 | 18 | ||
| 21 | /** | 19 | /** |
| 22 | * alloc_msi_entry - Allocate an initialize msi_entry | 20 | * alloc_msi_entry - Allocate an initialize msi_entry |