Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irq_domain/microblaze: Convert microblaze to use irq_domains

This patch converts Microblaze to use the irq_domain remapper and get
away from hard coding the offset between hwirq number and the linux irq
number space. This also paves the way for multiple interrupt controllers.

v2: Don't enable SPARSE_IRQ and keep NR_IRQS set to 33

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: John Williams <john.williams@petalogix.com>
Cc: John Linn <john.linn@xilinx.com>

+46 -100
+1
arch/microblaze/Kconfig
··· 14 14 select TRACING_SUPPORT 15 15 select OF 16 16 select OF_EARLY_FLATTREE 17 + select IRQ_DOMAIN 17 18 select HAVE_GENERIC_HARDIRQS 18 19 select GENERIC_IRQ_PROBE 19 20 select GENERIC_IRQ_SHOW
-16
arch/microblaze/include/asm/hardirq.h
··· 1 - /* 2 - * Copyright (C) 2006 Atmark Techno, Inc. 3 - * 4 - * This file is subject to the terms and conditions of the GNU General Public 5 - * License. See the file "COPYING" in the main directory of this archive 6 - * for more details. 7 - */ 8 - 9 - #ifndef _ASM_MICROBLAZE_HARDIRQ_H 10 - #define _ASM_MICROBLAZE_HARDIRQ_H 11 - 12 - /* should be defined in each interrupt controller driver */ 13 - extern unsigned int get_irq(struct pt_regs *regs); 14 - 15 1 #include <asm-generic/hardirq.h> 16 - 17 - #endif /* _ASM_MICROBLAZE_HARDIRQ_H */
+3 -39
arch/microblaze/include/asm/irq.h
··· 9 9 #ifndef _ASM_MICROBLAZE_IRQ_H 10 10 #define _ASM_MICROBLAZE_IRQ_H 11 11 12 - 13 - /* 14 - * Linux IRQ# is currently offset by one to map to the hardware 15 - * irq number. So hardware IRQ0 maps to Linux irq 1. 16 - */ 17 - #define NO_IRQ_OFFSET 1 18 - #define IRQ_OFFSET NO_IRQ_OFFSET 19 - #define NR_IRQS (32 + IRQ_OFFSET) 12 + #define NR_IRQS (32 + 1) 20 13 #include <asm-generic/irq.h> 21 - 22 - /* This type is the placeholder for a hardware interrupt number. It has to 23 - * be big enough to enclose whatever representation is used by a given 24 - * platform. 25 - */ 26 - typedef unsigned long irq_hw_number_t; 27 - 28 - extern unsigned int nr_irq; 29 14 30 15 struct pt_regs; 31 16 extern void do_IRQ(struct pt_regs *regs); 32 17 33 - /** FIXME - not implement 34 - * irq_dispose_mapping - Unmap an interrupt 35 - * @virq: linux virq number of the interrupt to unmap 36 - */ 37 - static inline void irq_dispose_mapping(unsigned int virq) 38 - { 39 - return; 40 - } 41 - 42 - struct irq_domain; 43 - 44 - /** 45 - * irq_create_mapping - Map a hardware interrupt into linux virq space 46 - * @host: host owning this hardware interrupt or NULL for default host 47 - * @hwirq: hardware irq number in that host space 48 - * 49 - * Only one mapping per hardware interrupt is permitted. Returns a linux 50 - * virq number. 51 - * If the sense/trigger is to be specified, set_irq_type() should be called 52 - * on the number returned from that call. 53 - */ 54 - extern unsigned int irq_create_mapping(struct irq_domain *host, 55 - irq_hw_number_t hwirq); 18 + /* should be defined in each interrupt controller driver */ 19 + extern unsigned int get_irq(void); 56 20 57 21 #endif /* _ASM_MICROBLAZE_IRQ_H */
+38 -25
arch/microblaze/kernel/intc.c
··· 9 9 */ 10 10 11 11 #include <linux/init.h> 12 + #include <linux/irqdomain.h> 12 13 #include <linux/irq.h> 13 14 #include <asm/page.h> 14 15 #include <linux/io.h> ··· 25 24 static unsigned int intc_baseaddr; 26 25 #define INTC_BASE intc_baseaddr 27 26 #endif 28 - 29 - unsigned int nr_irq; 30 27 31 28 /* No one else should require these constants, so define them locally here. */ 32 29 #define ISR 0x00 /* Interrupt Status Register */ ··· 83 84 .irq_mask_ack = intc_mask_ack, 84 85 }; 85 86 86 - unsigned int get_irq(struct pt_regs *regs) 87 - { 88 - int irq; 87 + static struct irq_domain *root_domain; 89 88 90 - /* 91 - * NOTE: This function is the one that needs to be improved in 92 - * order to handle multiple interrupt controllers. It currently 93 - * is hardcoded to check for interrupts only on the first INTC. 94 - */ 95 - irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET; 96 - pr_debug("get_irq: %d\n", irq); 89 + unsigned int get_irq(void) 90 + { 91 + unsigned int hwirq, irq = -1; 92 + 93 + hwirq = in_be32(INTC_BASE + IVR); 94 + if (hwirq != -1U) 95 + irq = irq_find_mapping(root_domain, hwirq); 96 + 97 + pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); 97 98 98 99 return irq; 99 100 } 100 101 102 + int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 103 + { 104 + u32 intr_mask = (u32)d->host_data; 105 + 106 + if (intr_mask & (1 << hw)) { 107 + irq_set_chip_and_handler_name(irq, &intc_dev, 108 + handle_edge_irq, "edge"); 109 + irq_clear_status_flags(irq, IRQ_LEVEL); 110 + } else { 111 + irq_set_chip_and_handler_name(irq, &intc_dev, 112 + handle_level_irq, "level"); 113 + irq_set_status_flags(irq, IRQ_LEVEL); 114 + } 115 + return 0; 116 + } 117 + 118 + static const struct irq_domain_ops xintc_irq_domain_ops = { 119 + .xlate = irq_domain_xlate_onetwocell, 120 + .map = xintc_map, 121 + }; 122 + 101 123 void __init init_IRQ(void) 102 124 { 103 - u32 i, intr_mask; 125 + u32 nr_irq, intr_mask; 104 126 struct device_node *intc = NULL; 105 127 #ifdef CONFIG_SELFMOD_INTC 106 128 unsigned int intc_baseaddr = 0; ··· 166 146 /* Turn on the Master Enable. */ 167 147 out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); 168 148 169 - for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) { 170 - if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) { 171 - irq_set_chip_and_handler_name(i, &intc_dev, 172 - handle_edge_irq, "edge"); 173 - irq_clear_status_flags(i, IRQ_LEVEL); 174 - } else { 175 - irq_set_chip_and_handler_name(i, &intc_dev, 176 - handle_level_irq, "level"); 177 - irq_set_status_flags(i, IRQ_LEVEL); 178 - } 179 - irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET; 180 - } 149 + /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm 150 + * lazy and Michal can clean it up to something nicer when he tests 151 + * and commits this patch. ~~gcl */ 152 + root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, 153 + (void *)intr_mask); 181 154 }
+4 -20
arch/microblaze/kernel/irq.c
··· 31 31 trace_hardirqs_off(); 32 32 33 33 irq_enter(); 34 - irq = get_irq(regs); 34 + irq = get_irq(); 35 35 next_irq: 36 36 BUG_ON(!irq); 37 - /* Substract 1 because of get_irq */ 38 - generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET); 37 + generic_handle_irq(irq); 39 38 40 - irq = get_irq(regs); 41 - if (irq) { 39 + irq = get_irq(); 40 + if (irq != -1U) { 42 41 pr_debug("next irq: %d\n", irq); 43 42 ++concurrent_irq; 44 43 goto next_irq; ··· 47 48 set_irq_regs(old_regs); 48 49 trace_hardirqs_on(); 49 50 } 50 - 51 - /* MS: There is no any advance mapping mechanism. We are using simple 32bit 52 - intc without any cascades or any connection that's why mapping is 1:1 */ 53 - unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq) 54 - { 55 - return hwirq + IRQ_OFFSET; 56 - } 57 - EXPORT_SYMBOL_GPL(irq_create_mapping); 58 - 59 - unsigned int irq_create_of_mapping(struct device_node *controller, 60 - const u32 *intspec, unsigned int intsize) 61 - { 62 - return intspec[0] + IRQ_OFFSET; 63 - } 64 - EXPORT_SYMBOL_GPL(irq_create_of_mapping);