0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/cpumask.h>
0012 #include <linux/bsearch.h>
0013 #include <linux/io.h>
0014 #include "internals.h"
0015
0016 void _intc_enable(struct irq_data *data, unsigned long handle)
0017 {
0018 unsigned int irq = data->irq;
0019 struct intc_desc_int *d = get_intc_desc(irq);
0020 unsigned long addr;
0021 unsigned int cpu;
0022
0023 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
0024 #ifdef CONFIG_SMP
0025 if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
0026 continue;
0027 #endif
0028 addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
0029 intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
0030 [_INTC_FN(handle)], irq);
0031 }
0032
0033 intc_balancing_enable(irq);
0034 }
0035
0036 static void intc_enable(struct irq_data *data)
0037 {
0038 _intc_enable(data, (unsigned long)irq_data_get_irq_chip_data(data));
0039 }
0040
0041 static void intc_disable(struct irq_data *data)
0042 {
0043 unsigned int irq = data->irq;
0044 struct intc_desc_int *d = get_intc_desc(irq);
0045 unsigned long handle = (unsigned long)irq_data_get_irq_chip_data(data);
0046 unsigned long addr;
0047 unsigned int cpu;
0048
0049 intc_balancing_disable(irq);
0050
0051 for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
0052 #ifdef CONFIG_SMP
0053 if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
0054 continue;
0055 #endif
0056 addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
0057 intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
0058 [_INTC_FN(handle)], irq);
0059 }
0060 }
0061
0062 #ifdef CONFIG_SMP
0063
0064
0065
0066
0067
0068 static int intc_set_affinity(struct irq_data *data,
0069 const struct cpumask *cpumask,
0070 bool force)
0071 {
0072 if (!cpumask_intersects(cpumask, cpu_online_mask))
0073 return -1;
0074
0075 irq_data_update_affinity(data, cpumask);
0076
0077 return IRQ_SET_MASK_OK_NOCOPY;
0078 }
0079 #endif
0080
0081 static void intc_mask_ack(struct irq_data *data)
0082 {
0083 unsigned int irq = data->irq;
0084 struct intc_desc_int *d = get_intc_desc(irq);
0085 unsigned long handle = intc_get_ack_handle(irq);
0086 void __iomem *addr;
0087
0088 intc_disable(data);
0089
0090
0091 if (handle) {
0092 unsigned int value;
0093
0094 addr = (void __iomem *)INTC_REG(d, _INTC_ADDR_D(handle), 0);
0095 value = intc_set_field_from_handle(0, 1, handle);
0096
0097 switch (_INTC_FN(handle)) {
0098 case REG_FN_MODIFY_BASE + 0:
0099 __raw_readb(addr);
0100 __raw_writeb(0xff ^ value, addr);
0101 break;
0102 case REG_FN_MODIFY_BASE + 1:
0103 __raw_readw(addr);
0104 __raw_writew(0xffff ^ value, addr);
0105 break;
0106 case REG_FN_MODIFY_BASE + 3:
0107 __raw_readl(addr);
0108 __raw_writel(0xffffffff ^ value, addr);
0109 break;
0110 default:
0111 BUG();
0112 break;
0113 }
0114 }
0115 }
0116
0117 static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
0118 unsigned int nr_hp,
0119 unsigned int irq)
0120 {
0121 struct intc_handle_int key;
0122
0123 key.irq = irq;
0124 key.handle = 0;
0125
0126 return bsearch(&key, hp, nr_hp, sizeof(*hp), intc_handle_int_cmp);
0127 }
0128
0129 int intc_set_priority(unsigned int irq, unsigned int prio)
0130 {
0131 struct intc_desc_int *d = get_intc_desc(irq);
0132 struct irq_data *data = irq_get_irq_data(irq);
0133 struct intc_handle_int *ihp;
0134
0135 if (!intc_get_prio_level(irq) || prio <= 1)
0136 return -EINVAL;
0137
0138 ihp = intc_find_irq(d->prio, d->nr_prio, irq);
0139 if (ihp) {
0140 if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
0141 return -EINVAL;
0142
0143 intc_set_prio_level(irq, prio);
0144
0145
0146
0147
0148
0149
0150 if (_INTC_FN(ihp->handle) != REG_FN_ERR)
0151 _intc_enable(data, ihp->handle);
0152 }
0153 return 0;
0154 }
0155
0156 #define SENSE_VALID_FLAG 0x80
0157 #define VALID(x) (x | SENSE_VALID_FLAG)
0158
0159 static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
0160 [IRQ_TYPE_EDGE_FALLING] = VALID(0),
0161 [IRQ_TYPE_EDGE_RISING] = VALID(1),
0162 [IRQ_TYPE_LEVEL_LOW] = VALID(2),
0163
0164 #if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
0165 !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
0166 !defined(CONFIG_CPU_SUBTYPE_SH7709)
0167 [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
0168 #endif
0169 #if defined(CONFIG_ARM)
0170 [IRQ_TYPE_EDGE_BOTH] = VALID(4),
0171 #endif
0172 };
0173
0174 static int intc_set_type(struct irq_data *data, unsigned int type)
0175 {
0176 unsigned int irq = data->irq;
0177 struct intc_desc_int *d = get_intc_desc(irq);
0178 unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
0179 struct intc_handle_int *ihp;
0180 unsigned long addr;
0181
0182 if (!value)
0183 return -EINVAL;
0184
0185 value &= ~SENSE_VALID_FLAG;
0186
0187 ihp = intc_find_irq(d->sense, d->nr_sense, irq);
0188 if (ihp) {
0189
0190 if (value >= (1 << _INTC_WIDTH(ihp->handle)))
0191 return -EINVAL;
0192
0193 addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
0194 intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
0195 }
0196
0197 return 0;
0198 }
0199
0200 struct irq_chip intc_irq_chip = {
0201 .irq_mask = intc_disable,
0202 .irq_unmask = intc_enable,
0203 .irq_mask_ack = intc_mask_ack,
0204 .irq_enable = intc_enable,
0205 .irq_disable = intc_disable,
0206 .irq_set_type = intc_set_type,
0207 #ifdef CONFIG_SMP
0208 .irq_set_affinity = intc_set_affinity,
0209 #endif
0210 .flags = IRQCHIP_SKIP_SET_WAKE,
0211 };