diff options
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/Kconfig | 24 | ||||
-rw-r--r-- | drivers/sh/intc.c | 333 |
2 files changed, 326 insertions, 31 deletions
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig new file mode 100644 index 000000000000..a54de0b9b3df --- /dev/null +++ b/drivers/sh/Kconfig | |||
@@ -0,0 +1,24 @@ | |||
1 | config INTC_USERIMASK | ||
2 | bool "Userspace interrupt masking support" | ||
3 | depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A) | ||
4 | help | ||
5 | This enables support for hardware-assisted userspace hardirq | ||
6 | masking. | ||
7 | |||
8 | SH-4A and newer interrupt blocks all support a special shadowed | ||
9 | page with all non-masking registers obscured when mapped in to | ||
10 | userspace. This is primarily for use by userspace device | ||
11 | drivers that are using special priority levels. | ||
12 | |||
13 | If in doubt, say N. | ||
14 | |||
15 | config INTC_BALANCING | ||
16 | bool "Hardware IRQ balancing support" | ||
17 | depends on SMP && SUPERH && CPU_SUBTYPE_SH7786 | ||
18 | help | ||
19 | This enables support for IRQ auto-distribution mode on SH-X3 | ||
20 | SMP parts. All of the balancing and CPU wakeup decisions are | ||
21 | taken care of automatically by hardware for distributed | ||
22 | vectors. | ||
23 | |||
24 | If in doubt, say N. | ||
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 94ad6bd86a00..c585574b9aed 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/topology.h> | 28 | #include <linux/topology.h> |
29 | #include <linux/bitmap.h> | 29 | #include <linux/bitmap.h> |
30 | #include <linux/cpumask.h> | 30 | #include <linux/cpumask.h> |
31 | #include <asm/sizes.h> | ||
31 | 32 | ||
32 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ | 33 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ |
33 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ | 34 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ |
@@ -45,6 +46,12 @@ struct intc_handle_int { | |||
45 | unsigned long handle; | 46 | unsigned long handle; |
46 | }; | 47 | }; |
47 | 48 | ||
49 | struct intc_window { | ||
50 | phys_addr_t phys; | ||
51 | void __iomem *virt; | ||
52 | unsigned long size; | ||
53 | }; | ||
54 | |||
48 | struct intc_desc_int { | 55 | struct intc_desc_int { |
49 | struct list_head list; | 56 | struct list_head list; |
50 | struct sys_device sysdev; | 57 | struct sys_device sysdev; |
@@ -58,6 +65,8 @@ struct intc_desc_int { | |||
58 | unsigned int nr_prio; | 65 | unsigned int nr_prio; |
59 | struct intc_handle_int *sense; | 66 | struct intc_handle_int *sense; |
60 | unsigned int nr_sense; | 67 | unsigned int nr_sense; |
68 | struct intc_window *window; | ||
69 | unsigned int nr_windows; | ||
61 | struct irq_chip chip; | 70 | struct irq_chip chip; |
62 | }; | 71 | }; |
63 | 72 | ||
@@ -87,8 +96,12 @@ static DEFINE_SPINLOCK(vector_lock); | |||
87 | #define SMP_NR(d, x) 1 | 96 | #define SMP_NR(d, x) 1 |
88 | #endif | 97 | #endif |
89 | 98 | ||
90 | static unsigned int intc_prio_level[NR_IRQS]; /* for now */ | 99 | static unsigned int intc_prio_level[NR_IRQS]; /* for now */ |
100 | static unsigned int default_prio_level = 2; /* 2 - 16 */ | ||
91 | static unsigned long ack_handle[NR_IRQS]; | 101 | static unsigned long ack_handle[NR_IRQS]; |
102 | #ifdef CONFIG_INTC_BALANCING | ||
103 | static unsigned long dist_handle[NR_IRQS]; | ||
104 | #endif | ||
92 | 105 | ||
93 | static inline struct intc_desc_int *get_intc_desc(unsigned int irq) | 106 | static inline struct intc_desc_int *get_intc_desc(unsigned int irq) |
94 | { | 107 | { |
@@ -96,6 +109,47 @@ static inline struct intc_desc_int *get_intc_desc(unsigned int irq) | |||
96 | return container_of(chip, struct intc_desc_int, chip); | 109 | return container_of(chip, struct intc_desc_int, chip); |
97 | } | 110 | } |
98 | 111 | ||
112 | static unsigned long intc_phys_to_virt(struct intc_desc_int *d, | ||
113 | unsigned long address) | ||
114 | { | ||
115 | struct intc_window *window; | ||
116 | int k; | ||
117 | |||
118 | /* scan through physical windows and convert address */ | ||
119 | for (k = 0; k < d->nr_windows; k++) { | ||
120 | window = d->window + k; | ||
121 | |||
122 | if (address < window->phys) | ||
123 | continue; | ||
124 | |||
125 | if (address >= (window->phys + window->size)) | ||
126 | continue; | ||
127 | |||
128 | address -= window->phys; | ||
129 | address += (unsigned long)window->virt; | ||
130 | |||
131 | return address; | ||
132 | } | ||
133 | |||
134 | /* no windows defined, register must be 1:1 mapped virt:phys */ | ||
135 | return address; | ||
136 | } | ||
137 | |||
138 | static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address) | ||
139 | { | ||
140 | unsigned int k; | ||
141 | |||
142 | address = intc_phys_to_virt(d, address); | ||
143 | |||
144 | for (k = 0; k < d->nr_reg; k++) { | ||
145 | if (d->reg[k] == address) | ||
146 | return k; | ||
147 | } | ||
148 | |||
149 | BUG(); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
99 | static inline unsigned int set_field(unsigned int value, | 153 | static inline unsigned int set_field(unsigned int value, |
100 | unsigned int field_value, | 154 | unsigned int field_value, |
101 | unsigned int handle) | 155 | unsigned int handle) |
@@ -229,6 +283,85 @@ static void (*intc_disable_fns[])(unsigned long addr, | |||
229 | [MODE_PCLR_REG] = intc_mode_field, | 283 | [MODE_PCLR_REG] = intc_mode_field, |
230 | }; | 284 | }; |
231 | 285 | ||
286 | #ifdef CONFIG_INTC_BALANCING | ||
287 | static inline void intc_balancing_enable(unsigned int irq) | ||
288 | { | ||
289 | struct intc_desc_int *d = get_intc_desc(irq); | ||
290 | unsigned long handle = dist_handle[irq]; | ||
291 | unsigned long addr; | ||
292 | |||
293 | if (irq_balancing_disabled(irq) || !handle) | ||
294 | return; | ||
295 | |||
296 | addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); | ||
297 | intc_reg_fns[_INTC_FN(handle)](addr, handle, 1); | ||
298 | } | ||
299 | |||
300 | static inline void intc_balancing_disable(unsigned int irq) | ||
301 | { | ||
302 | struct intc_desc_int *d = get_intc_desc(irq); | ||
303 | unsigned long handle = dist_handle[irq]; | ||
304 | unsigned long addr; | ||
305 | |||
306 | if (irq_balancing_disabled(irq) || !handle) | ||
307 | return; | ||
308 | |||
309 | addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); | ||
310 | intc_reg_fns[_INTC_FN(handle)](addr, handle, 0); | ||
311 | } | ||
312 | |||
313 | static unsigned int intc_dist_data(struct intc_desc *desc, | ||
314 | struct intc_desc_int *d, | ||
315 | intc_enum enum_id) | ||
316 | { | ||
317 | struct intc_mask_reg *mr = desc->hw.mask_regs; | ||
318 | unsigned int i, j, fn, mode; | ||
319 | unsigned long reg_e, reg_d; | ||
320 | |||
321 | for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) { | ||
322 | mr = desc->hw.mask_regs + i; | ||
323 | |||
324 | /* | ||
325 | * Skip this entry if there's no auto-distribution | ||
326 | * register associated with it. | ||
327 | */ | ||
328 | if (!mr->dist_reg) | ||
329 | continue; | ||
330 | |||
331 | for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) { | ||
332 | if (mr->enum_ids[j] != enum_id) | ||
333 | continue; | ||
334 | |||
335 | fn = REG_FN_MODIFY_BASE; | ||
336 | mode = MODE_ENABLE_REG; | ||
337 | reg_e = mr->dist_reg; | ||
338 | reg_d = mr->dist_reg; | ||
339 | |||
340 | fn += (mr->reg_width >> 3) - 1; | ||
341 | return _INTC_MK(fn, mode, | ||
342 | intc_get_reg(d, reg_e), | ||
343 | intc_get_reg(d, reg_d), | ||
344 | 1, | ||
345 | (mr->reg_width - 1) - j); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * It's possible we've gotten here with no distribution options | ||
351 | * available for the IRQ in question, so we just skip over those. | ||
352 | */ | ||
353 | return 0; | ||
354 | } | ||
355 | #else | ||
356 | static inline void intc_balancing_enable(unsigned int irq) | ||
357 | { | ||
358 | } | ||
359 | |||
360 | static inline void intc_balancing_disable(unsigned int irq) | ||
361 | { | ||
362 | } | ||
363 | #endif | ||
364 | |||
232 | static inline void _intc_enable(unsigned int irq, unsigned long handle) | 365 | static inline void _intc_enable(unsigned int irq, unsigned long handle) |
233 | { | 366 | { |
234 | struct intc_desc_int *d = get_intc_desc(irq); | 367 | struct intc_desc_int *d = get_intc_desc(irq); |
@@ -244,6 +377,8 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle) | |||
244 | intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ | 377 | intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\ |
245 | [_INTC_FN(handle)], irq); | 378 | [_INTC_FN(handle)], irq); |
246 | } | 379 | } |
380 | |||
381 | intc_balancing_enable(irq); | ||
247 | } | 382 | } |
248 | 383 | ||
249 | static void intc_enable(unsigned int irq) | 384 | static void intc_enable(unsigned int irq) |
@@ -254,10 +389,12 @@ static void intc_enable(unsigned int irq) | |||
254 | static void intc_disable(unsigned int irq) | 389 | static void intc_disable(unsigned int irq) |
255 | { | 390 | { |
256 | struct intc_desc_int *d = get_intc_desc(irq); | 391 | struct intc_desc_int *d = get_intc_desc(irq); |
257 | unsigned long handle = (unsigned long) get_irq_chip_data(irq); | 392 | unsigned long handle = (unsigned long)get_irq_chip_data(irq); |
258 | unsigned long addr; | 393 | unsigned long addr; |
259 | unsigned int cpu; | 394 | unsigned int cpu; |
260 | 395 | ||
396 | intc_balancing_disable(irq); | ||
397 | |||
261 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { | 398 | for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { |
262 | #ifdef CONFIG_SMP | 399 | #ifdef CONFIG_SMP |
263 | if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) | 400 | if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity)) |
@@ -336,8 +473,7 @@ static void intc_mask_ack(unsigned int irq) | |||
336 | 473 | ||
337 | intc_disable(irq); | 474 | intc_disable(irq); |
338 | 475 | ||
339 | /* read register and write zero only to the assocaited bit */ | 476 | /* read register and write zero only to the associated bit */ |
340 | |||
341 | if (handle) { | 477 | if (handle) { |
342 | addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); | 478 | addr = INTC_REG(d, _INTC_ADDR_D(handle), 0); |
343 | switch (_INTC_FN(handle)) { | 479 | switch (_INTC_FN(handle)) { |
@@ -366,7 +502,8 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, | |||
366 | { | 502 | { |
367 | int i; | 503 | int i; |
368 | 504 | ||
369 | /* this doesn't scale well, but... | 505 | /* |
506 | * this doesn't scale well, but... | ||
370 | * | 507 | * |
371 | * this function should only be used for cerain uncommon | 508 | * this function should only be used for cerain uncommon |
372 | * operations such as intc_set_priority() and intc_set_sense() | 509 | * operations such as intc_set_priority() and intc_set_sense() |
@@ -377,7 +514,6 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp, | |||
377 | * memory footprint down is to make sure the array is sorted | 514 | * memory footprint down is to make sure the array is sorted |
378 | * and then perform a bisect to lookup the irq. | 515 | * and then perform a bisect to lookup the irq. |
379 | */ | 516 | */ |
380 | |||
381 | for (i = 0; i < nr_hp; i++) { | 517 | for (i = 0; i < nr_hp; i++) { |
382 | if ((hp + i)->irq != irq) | 518 | if ((hp + i)->irq != irq) |
383 | continue; | 519 | continue; |
@@ -408,7 +544,6 @@ int intc_set_priority(unsigned int irq, unsigned int prio) | |||
408 | * primary masking method is using intc_prio_level[irq] | 544 | * primary masking method is using intc_prio_level[irq] |
409 | * priority level will be set during next enable() | 545 | * priority level will be set during next enable() |
410 | */ | 546 | */ |
411 | |||
412 | if (_INTC_FN(ihp->handle) != REG_FN_ERR) | 547 | if (_INTC_FN(ihp->handle) != REG_FN_ERR) |
413 | _intc_enable(irq, ihp->handle); | 548 | _intc_enable(irq, ihp->handle); |
414 | } | 549 | } |
@@ -447,20 +582,6 @@ static int intc_set_sense(unsigned int irq, unsigned int type) | |||
447 | return 0; | 582 | return 0; |
448 | } | 583 | } |
449 | 584 | ||
450 | static unsigned int __init intc_get_reg(struct intc_desc_int *d, | ||
451 | unsigned long address) | ||
452 | { | ||
453 | unsigned int k; | ||
454 | |||
455 | for (k = 0; k < d->nr_reg; k++) { | ||
456 | if (d->reg[k] == address) | ||
457 | return k; | ||
458 | } | ||
459 | |||
460 | BUG(); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static intc_enum __init intc_grp_id(struct intc_desc *desc, | 585 | static intc_enum __init intc_grp_id(struct intc_desc *desc, |
465 | intc_enum enum_id) | 586 | intc_enum enum_id) |
466 | { | 587 | { |
@@ -718,13 +839,14 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
718 | */ | 839 | */ |
719 | set_bit(irq, intc_irq_map); | 840 | set_bit(irq, intc_irq_map); |
720 | 841 | ||
721 | /* Prefer single interrupt source bitmap over other combinations: | 842 | /* |
843 | * Prefer single interrupt source bitmap over other combinations: | ||
844 | * | ||
722 | * 1. bitmap, single interrupt source | 845 | * 1. bitmap, single interrupt source |
723 | * 2. priority, single interrupt source | 846 | * 2. priority, single interrupt source |
724 | * 3. bitmap, multiple interrupt sources (groups) | 847 | * 3. bitmap, multiple interrupt sources (groups) |
725 | * 4. priority, multiple interrupt sources (groups) | 848 | * 4. priority, multiple interrupt sources (groups) |
726 | */ | 849 | */ |
727 | |||
728 | data[0] = intc_mask_data(desc, d, enum_id, 0); | 850 | data[0] = intc_mask_data(desc, d, enum_id, 0); |
729 | data[1] = intc_prio_data(desc, d, enum_id, 0); | 851 | data[1] = intc_prio_data(desc, d, enum_id, 0); |
730 | 852 | ||
@@ -749,10 +871,11 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
749 | handle_level_irq, "level"); | 871 | handle_level_irq, "level"); |
750 | set_irq_chip_data(irq, (void *)data[primary]); | 872 | set_irq_chip_data(irq, (void *)data[primary]); |
751 | 873 | ||
752 | /* set priority level | 874 | /* |
875 | * set priority level | ||
753 | * - this needs to be at least 2 for 5-bit priorities on 7780 | 876 | * - this needs to be at least 2 for 5-bit priorities on 7780 |
754 | */ | 877 | */ |
755 | intc_prio_level[irq] = 2; | 878 | intc_prio_level[irq] = default_prio_level; |
756 | 879 | ||
757 | /* enable secondary masking method if present */ | 880 | /* enable secondary masking method if present */ |
758 | if (data[!primary]) | 881 | if (data[!primary]) |
@@ -769,7 +892,6 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
769 | * only secondary priority should access registers, so | 892 | * only secondary priority should access registers, so |
770 | * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() | 893 | * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() |
771 | */ | 894 | */ |
772 | |||
773 | hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); | 895 | hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); |
774 | hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); | 896 | hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); |
775 | } | 897 | } |
@@ -790,6 +912,11 @@ static void __init intc_register_irq(struct intc_desc *desc, | |||
790 | if (desc->hw.ack_regs) | 912 | if (desc->hw.ack_regs) |
791 | ack_handle[irq] = intc_ack_data(desc, d, enum_id); | 913 | ack_handle[irq] = intc_ack_data(desc, d, enum_id); |
792 | 914 | ||
915 | #ifdef CONFIG_INTC_BALANCING | ||
916 | if (desc->hw.mask_regs) | ||
917 | dist_handle[irq] = intc_dist_data(desc, d, enum_id); | ||
918 | #endif | ||
919 | |||
793 | #ifdef CONFIG_ARM | 920 | #ifdef CONFIG_ARM |
794 | set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */ | 921 | set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */ |
795 | #endif | 922 | #endif |
@@ -801,6 +928,8 @@ static unsigned int __init save_reg(struct intc_desc_int *d, | |||
801 | unsigned int smp) | 928 | unsigned int smp) |
802 | { | 929 | { |
803 | if (value) { | 930 | if (value) { |
931 | value = intc_phys_to_virt(d, value); | ||
932 | |||
804 | d->reg[cnt] = value; | 933 | d->reg[cnt] = value; |
805 | #ifdef CONFIG_SMP | 934 | #ifdef CONFIG_SMP |
806 | d->smp[cnt] = smp; | 935 | d->smp[cnt] = smp; |
@@ -816,25 +945,59 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) | |||
816 | generic_handle_irq((unsigned int)get_irq_data(irq)); | 945 | generic_handle_irq((unsigned int)get_irq_data(irq)); |
817 | } | 946 | } |
818 | 947 | ||
819 | void __init register_intc_controller(struct intc_desc *desc) | 948 | int __init register_intc_controller(struct intc_desc *desc) |
820 | { | 949 | { |
821 | unsigned int i, k, smp; | 950 | unsigned int i, k, smp; |
822 | struct intc_hw_desc *hw = &desc->hw; | 951 | struct intc_hw_desc *hw = &desc->hw; |
823 | struct intc_desc_int *d; | 952 | struct intc_desc_int *d; |
953 | struct resource *res; | ||
954 | |||
955 | pr_info("intc: Registered controller '%s' with %u IRQs\n", | ||
956 | desc->name, hw->nr_vectors); | ||
824 | 957 | ||
825 | d = kzalloc(sizeof(*d), GFP_NOWAIT); | 958 | d = kzalloc(sizeof(*d), GFP_NOWAIT); |
959 | if (!d) | ||
960 | goto err0; | ||
826 | 961 | ||
827 | INIT_LIST_HEAD(&d->list); | 962 | INIT_LIST_HEAD(&d->list); |
828 | list_add(&d->list, &intc_list); | 963 | list_add(&d->list, &intc_list); |
829 | 964 | ||
965 | if (desc->num_resources) { | ||
966 | d->nr_windows = desc->num_resources; | ||
967 | d->window = kzalloc(d->nr_windows * sizeof(*d->window), | ||
968 | GFP_NOWAIT); | ||
969 | if (!d->window) | ||
970 | goto err1; | ||
971 | |||
972 | for (k = 0; k < d->nr_windows; k++) { | ||
973 | res = desc->resource + k; | ||
974 | WARN_ON(resource_type(res) != IORESOURCE_MEM); | ||
975 | d->window[k].phys = res->start; | ||
976 | d->window[k].size = resource_size(res); | ||
977 | d->window[k].virt = ioremap_nocache(res->start, | ||
978 | resource_size(res)); | ||
979 | if (!d->window[k].virt) | ||
980 | goto err2; | ||
981 | } | ||
982 | } | ||
983 | |||
830 | d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; | 984 | d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; |
985 | #ifdef CONFIG_INTC_BALANCING | ||
986 | if (d->nr_reg) | ||
987 | d->nr_reg += hw->nr_mask_regs; | ||
988 | #endif | ||
831 | d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; | 989 | d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; |
832 | d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; | 990 | d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; |
833 | d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; | 991 | d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; |
834 | 992 | ||
835 | d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); | 993 | d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); |
994 | if (!d->reg) | ||
995 | goto err2; | ||
996 | |||
836 | #ifdef CONFIG_SMP | 997 | #ifdef CONFIG_SMP |
837 | d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); | 998 | d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); |
999 | if (!d->smp) | ||
1000 | goto err3; | ||
838 | #endif | 1001 | #endif |
839 | k = 0; | 1002 | k = 0; |
840 | 1003 | ||
@@ -843,12 +1006,17 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
843 | smp = IS_SMP(hw->mask_regs[i]); | 1006 | smp = IS_SMP(hw->mask_regs[i]); |
844 | k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); | 1007 | k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); |
845 | k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); | 1008 | k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); |
1009 | #ifdef CONFIG_INTC_BALANCING | ||
1010 | k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0); | ||
1011 | #endif | ||
846 | } | 1012 | } |
847 | } | 1013 | } |
848 | 1014 | ||
849 | if (hw->prio_regs) { | 1015 | if (hw->prio_regs) { |
850 | d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), | 1016 | d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), |
851 | GFP_NOWAIT); | 1017 | GFP_NOWAIT); |
1018 | if (!d->prio) | ||
1019 | goto err4; | ||
852 | 1020 | ||
853 | for (i = 0; i < hw->nr_prio_regs; i++) { | 1021 | for (i = 0; i < hw->nr_prio_regs; i++) { |
854 | smp = IS_SMP(hw->prio_regs[i]); | 1022 | smp = IS_SMP(hw->prio_regs[i]); |
@@ -860,6 +1028,8 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
860 | if (hw->sense_regs) { | 1028 | if (hw->sense_regs) { |
861 | d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), | 1029 | d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), |
862 | GFP_NOWAIT); | 1030 | GFP_NOWAIT); |
1031 | if (!d->sense) | ||
1032 | goto err5; | ||
863 | 1033 | ||
864 | for (i = 0; i < hw->nr_sense_regs; i++) | 1034 | for (i = 0; i < hw->nr_sense_regs; i++) |
865 | k += save_reg(d, k, hw->sense_regs[i].reg, 0); | 1035 | k += save_reg(d, k, hw->sense_regs[i].reg, 0); |
@@ -906,7 +1076,7 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
906 | 1076 | ||
907 | irq_desc = irq_to_desc_alloc_node(irq, numa_node_id()); | 1077 | irq_desc = irq_to_desc_alloc_node(irq, numa_node_id()); |
908 | if (unlikely(!irq_desc)) { | 1078 | if (unlikely(!irq_desc)) { |
909 | pr_info("can't get irq_desc for %d\n", irq); | 1079 | pr_err("can't get irq_desc for %d\n", irq); |
910 | continue; | 1080 | continue; |
911 | } | 1081 | } |
912 | 1082 | ||
@@ -926,7 +1096,7 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
926 | */ | 1096 | */ |
927 | irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id()); | 1097 | irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id()); |
928 | if (unlikely(!irq_desc)) { | 1098 | if (unlikely(!irq_desc)) { |
929 | pr_info("can't get irq_desc for %d\n", irq2); | 1099 | pr_err("can't get irq_desc for %d\n", irq2); |
930 | continue; | 1100 | continue; |
931 | } | 1101 | } |
932 | 1102 | ||
@@ -942,8 +1112,100 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
942 | /* enable bits matching force_enable after registering irqs */ | 1112 | /* enable bits matching force_enable after registering irqs */ |
943 | if (desc->force_enable) | 1113 | if (desc->force_enable) |
944 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); | 1114 | intc_enable_disable_enum(desc, d, desc->force_enable, 1); |
1115 | |||
1116 | return 0; | ||
1117 | err5: | ||
1118 | kfree(d->prio); | ||
1119 | err4: | ||
1120 | #ifdef CONFIG_SMP | ||
1121 | kfree(d->smp); | ||
1122 | err3: | ||
1123 | #endif | ||
1124 | kfree(d->reg); | ||
1125 | err2: | ||
1126 | for (k = 0; k < d->nr_windows; k++) | ||
1127 | if (d->window[k].virt) | ||
1128 | iounmap(d->window[k].virt); | ||
1129 | |||
1130 | kfree(d->window); | ||
1131 | err1: | ||
1132 | kfree(d); | ||
1133 | err0: | ||
1134 | pr_err("unable to allocate INTC memory\n"); | ||
1135 | |||
1136 | return -ENOMEM; | ||
1137 | } | ||
1138 | |||
1139 | #ifdef CONFIG_INTC_USERIMASK | ||
1140 | static void __iomem *uimask; | ||
1141 | |||
1142 | int register_intc_userimask(unsigned long addr) | ||
1143 | { | ||
1144 | if (unlikely(uimask)) | ||
1145 | return -EBUSY; | ||
1146 | |||
1147 | uimask = ioremap_nocache(addr, SZ_4K); | ||
1148 | if (unlikely(!uimask)) | ||
1149 | return -ENOMEM; | ||
1150 | |||
1151 | pr_info("intc: userimask support registered for levels 0 -> %d\n", | ||
1152 | default_prio_level - 1); | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static ssize_t | ||
1158 | show_intc_userimask(struct sysdev_class *cls, | ||
1159 | struct sysdev_class_attribute *attr, char *buf) | ||
1160 | { | ||
1161 | return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf); | ||
1162 | } | ||
1163 | |||
1164 | static ssize_t | ||
1165 | store_intc_userimask(struct sysdev_class *cls, | ||
1166 | struct sysdev_class_attribute *attr, | ||
1167 | const char *buf, size_t count) | ||
1168 | { | ||
1169 | unsigned long level; | ||
1170 | |||
1171 | level = simple_strtoul(buf, NULL, 10); | ||
1172 | |||
1173 | /* | ||
1174 | * Minimal acceptable IRQ levels are in the 2 - 16 range, but | ||
1175 | * these are chomped so as to not interfere with normal IRQs. | ||
1176 | * | ||
1177 | * Level 1 is a special case on some CPUs in that it's not | ||
1178 | * directly settable, but given that USERIMASK cuts off below a | ||
1179 | * certain level, we don't care about this limitation here. | ||
1180 | * Level 0 on the other hand equates to user masking disabled. | ||
1181 | * | ||
1182 | * We use default_prio_level as a cut off so that only special | ||
1183 | * case opt-in IRQs can be mangled. | ||
1184 | */ | ||
1185 | if (level >= default_prio_level) | ||
1186 | return -EINVAL; | ||
1187 | |||
1188 | __raw_writel(0xa5 << 24 | level << 4, uimask); | ||
1189 | |||
1190 | return count; | ||
945 | } | 1191 | } |
946 | 1192 | ||
1193 | static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR, | ||
1194 | show_intc_userimask, store_intc_userimask); | ||
1195 | #endif | ||
1196 | |||
1197 | static ssize_t | ||
1198 | show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) | ||
1199 | { | ||
1200 | struct intc_desc_int *d; | ||
1201 | |||
1202 | d = container_of(dev, struct intc_desc_int, sysdev); | ||
1203 | |||
1204 | return sprintf(buf, "%s\n", d->chip.name); | ||
1205 | } | ||
1206 | |||
1207 | static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); | ||
1208 | |||
947 | static int intc_suspend(struct sys_device *dev, pm_message_t state) | 1209 | static int intc_suspend(struct sys_device *dev, pm_message_t state) |
948 | { | 1210 | { |
949 | struct intc_desc_int *d; | 1211 | struct intc_desc_int *d; |
@@ -1003,19 +1265,28 @@ static int __init register_intc_sysdevs(void) | |||
1003 | int id = 0; | 1265 | int id = 0; |
1004 | 1266 | ||
1005 | error = sysdev_class_register(&intc_sysdev_class); | 1267 | error = sysdev_class_register(&intc_sysdev_class); |
1268 | #ifdef CONFIG_INTC_USERIMASK | ||
1269 | if (!error && uimask) | ||
1270 | error = sysdev_class_create_file(&intc_sysdev_class, | ||
1271 | &attr_userimask); | ||
1272 | #endif | ||
1006 | if (!error) { | 1273 | if (!error) { |
1007 | list_for_each_entry(d, &intc_list, list) { | 1274 | list_for_each_entry(d, &intc_list, list) { |
1008 | d->sysdev.id = id; | 1275 | d->sysdev.id = id; |
1009 | d->sysdev.cls = &intc_sysdev_class; | 1276 | d->sysdev.cls = &intc_sysdev_class; |
1010 | error = sysdev_register(&d->sysdev); | 1277 | error = sysdev_register(&d->sysdev); |
1278 | if (error == 0) | ||
1279 | error = sysdev_create_file(&d->sysdev, | ||
1280 | &attr_name); | ||
1011 | if (error) | 1281 | if (error) |
1012 | break; | 1282 | break; |
1283 | |||
1013 | id++; | 1284 | id++; |
1014 | } | 1285 | } |
1015 | } | 1286 | } |
1016 | 1287 | ||
1017 | if (error) | 1288 | if (error) |
1018 | pr_warning("intc: sysdev registration error\n"); | 1289 | pr_err("intc: sysdev registration error\n"); |
1019 | 1290 | ||
1020 | return error; | 1291 | return error; |
1021 | } | 1292 | } |
@@ -1048,7 +1319,7 @@ unsigned int create_irq_nr(unsigned int irq_want, int node) | |||
1048 | 1319 | ||
1049 | desc = irq_to_desc_alloc_node(new, node); | 1320 | desc = irq_to_desc_alloc_node(new, node); |
1050 | if (unlikely(!desc)) { | 1321 | if (unlikely(!desc)) { |
1051 | pr_info("can't get irq_desc for %d\n", new); | 1322 | pr_err("can't get irq_desc for %d\n", new); |
1052 | goto out_unlock; | 1323 | goto out_unlock; |
1053 | } | 1324 | } |
1054 | 1325 | ||