aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-09-23 07:09:38 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-04 12:15:47 -0400
commit44629f57accccbb8e6d443246fe6f51b42f7f781 (patch)
treeb75bab4a39a2be40f58a9d6daac4a208035300fe
parente8184a47c9cc04380553114815356d1042a27788 (diff)
sh: intc: Implement reverse mapping for IRQs to per-controller IDs.
This implements a scheme roughly analogous to the PowerPC virtual to hardware IRQ mapping, which we use for IRQ to per-controller ID mapping. This makes it possible for drivers to use the IDs directly for lookup instead of hardcoding the vector. The main motivation for this work is as a building block for dynamically allocating virtual IRQs for demuxing INTC events sharing a single INTEVT in addition to a common masking source. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--drivers/sh/Kconfig9
-rw-r--r--drivers/sh/intc.c91
-rw-r--r--include/linux/sh_intc.h1
3 files changed, 100 insertions, 1 deletions
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
index 1dc8b7ae35fb..e01ae42774af 100644
--- a/drivers/sh/Kconfig
+++ b/drivers/sh/Kconfig
@@ -22,3 +22,12 @@ config INTC_BALANCING
22 vectors. 22 vectors.
23 23
24 If in doubt, say N. 24 If in doubt, say N.
25
26config INTC_MAPPING_DEBUG
27 bool "Expose IRQ to per-controller id mapping via debugfs"
28 depends on DEBUG_FS
29 help
30 This will create a debugfs entry for showing the relationship
31 between system IRQs and the per-controller id tables.
32
33 If in doubt, say N.
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 4e01d65e5edb..a27dcb4254c7 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -30,6 +30,11 @@
30#include <linux/topology.h> 30#include <linux/topology.h>
31#include <linux/bitmap.h> 31#include <linux/bitmap.h>
32#include <linux/cpumask.h> 32#include <linux/cpumask.h>
33#include <linux/spinlock.h>
34#include <linux/debugfs.h>
35#include <linux/seq_file.h>
36#include <linux/radix-tree.h>
37#include <linux/mutex.h>
33#include <asm/sizes.h> 38#include <asm/sizes.h>
34 39
35#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ 40#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
@@ -54,9 +59,15 @@ struct intc_window {
54 unsigned long size; 59 unsigned long size;
55}; 60};
56 61
62struct intc_map_entry {
63 intc_enum enum_id;
64 struct intc_desc_int *desc;
65};
66
57struct intc_desc_int { 67struct intc_desc_int {
58 struct list_head list; 68 struct list_head list;
59 struct sys_device sysdev; 69 struct sys_device sysdev;
70 struct radix_tree_root tree;
60 pm_message_t state; 71 pm_message_t state;
61 unsigned long *reg; 72 unsigned long *reg;
62#ifdef CONFIG_SMP 73#ifdef CONFIG_SMP
@@ -86,7 +97,9 @@ static LIST_HEAD(intc_list);
86 * unused irq_desc positions in the sparse array. 97 * unused irq_desc positions in the sparse array.
87 */ 98 */
88static DECLARE_BITMAP(intc_irq_map, NR_IRQS); 99static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
100static struct intc_map_entry intc_irq_xlate[NR_IRQS];
89static DEFINE_SPINLOCK(vector_lock); 101static DEFINE_SPINLOCK(vector_lock);
102static DEFINE_MUTEX(irq_xlate_mutex);
90 103
91#ifdef CONFIG_SMP 104#ifdef CONFIG_SMP
92#define IS_SMP(x) x.smp 105#define IS_SMP(x) x.smp
@@ -828,6 +841,26 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,
828 return 0; 841 return 0;
829} 842}
830 843
844unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id)
845{
846 struct intc_map_entry *ptr;
847 struct intc_desc_int *d;
848 unsigned int irq = 0;
849
850 list_for_each_entry(d, &intc_list, list) {
851 if (strcmp(d->chip.name, chipname) == 0) {
852 ptr = radix_tree_lookup(&d->tree, enum_id);
853 if (ptr) {
854 irq = ptr - intc_irq_xlate;
855 break;
856 }
857 }
858 }
859
860 return irq;
861}
862EXPORT_SYMBOL_GPL(intc_irq_lookup);
863
831static void __init intc_register_irq(struct intc_desc *desc, 864static void __init intc_register_irq(struct intc_desc *desc,
832 struct intc_desc_int *d, 865 struct intc_desc_int *d,
833 intc_enum enum_id, 866 intc_enum enum_id,
@@ -837,10 +870,15 @@ static void __init intc_register_irq(struct intc_desc *desc,
837 unsigned int data[2], primary; 870 unsigned int data[2], primary;
838 871
839 /* 872 /*
840 * Register the IRQ position with the global IRQ map 873 * Register the IRQ position with the global IRQ map, then insert
874 * it in to the radix tree.
841 */ 875 */
842 set_bit(irq, intc_irq_map); 876 set_bit(irq, intc_irq_map);
843 877
878 mutex_lock(&irq_xlate_mutex);
879 radix_tree_insert(&d->tree, enum_id, &intc_irq_xlate[irq]);
880 mutex_unlock(&irq_xlate_mutex);
881
844 /* 882 /*
845 * Prefer single interrupt source bitmap over other combinations: 883 * Prefer single interrupt source bitmap over other combinations:
846 * 884 *
@@ -1082,6 +1120,9 @@ int __init register_intc_controller(struct intc_desc *desc)
1082 continue; 1120 continue;
1083 } 1121 }
1084 1122
1123 intc_irq_xlate[irq].enum_id = vect->enum_id;
1124 intc_irq_xlate[irq].desc = d;
1125
1085 intc_register_irq(desc, d, vect->enum_id, irq); 1126 intc_register_irq(desc, d, vect->enum_id, irq);
1086 1127
1087 for (k = i + 1; k < hw->nr_vectors; k++) { 1128 for (k = i + 1; k < hw->nr_vectors; k++) {
@@ -1196,6 +1237,54 @@ static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
1196 show_intc_userimask, store_intc_userimask); 1237 show_intc_userimask, store_intc_userimask);
1197#endif 1238#endif
1198 1239
1240#ifdef CONFIG_INTC_MAPPING_DEBUG
1241static int intc_irq_xlate_debug(struct seq_file *m, void *priv)
1242{
1243 int i;
1244
1245 seq_printf(m, "%-5s %-7s %-15s\n", "irq", "enum", "chip name");
1246
1247 for (i = 1; i < nr_irqs; i++) {
1248 struct intc_desc_int *desc = intc_irq_xlate[i].desc;
1249
1250 if (!desc)
1251 continue;
1252
1253 seq_printf(m, "%5d ", i);
1254 seq_printf(m, "0x%05x ", intc_irq_xlate[i].enum_id);
1255 seq_printf(m, "%-15s\n", desc->chip.name);
1256 }
1257
1258 return 0;
1259}
1260
1261static int intc_irq_xlate_open(struct inode *inode, struct file *file)
1262{
1263 return single_open(file, intc_irq_xlate_debug, inode->i_private);
1264}
1265
1266static const struct file_operations intc_irq_xlate_fops = {
1267 .open = intc_irq_xlate_open,
1268 .read = seq_read,
1269 .llseek = seq_lseek,
1270 .release = single_release,
1271};
1272
1273static int __init intc_irq_xlate_init(void)
1274{
1275 /*
1276 * XXX.. use arch_debugfs_dir here when all of the intc users are
1277 * converted.
1278 */
1279 if (debugfs_create_file("intc_irq_xlate", S_IRUGO, NULL, NULL,
1280 &intc_irq_xlate_fops) == NULL)
1281 return -ENOMEM;
1282
1283 return 0;
1284}
1285fs_initcall(intc_irq_xlate_init);
1286#endif
1287
1199static ssize_t 1288static ssize_t
1200show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) 1289show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
1201{ 1290{
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index bff2f286ca61..d40fd77fa75c 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -108,6 +108,7 @@ struct intc_desc symbol __initdata = { \
108int __init register_intc_controller(struct intc_desc *desc); 108int __init register_intc_controller(struct intc_desc *desc);
109void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs); 109void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
110int intc_set_priority(unsigned int irq, unsigned int prio); 110int intc_set_priority(unsigned int irq, unsigned int prio);
111unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id);
111 112
112#ifdef CONFIG_INTC_USERIMASK 113#ifdef CONFIG_INTC_USERIMASK
113int register_intc_userimask(unsigned long addr); 114int register_intc_userimask(unsigned long addr);