diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 172 |
1 files changed, 130 insertions, 42 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index ba4833f57d47..411480d5c626 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -147,33 +147,51 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
147 | */ | 147 | */ |
148 | 148 | ||
149 | 149 | ||
150 | static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, | 150 | static inline u32 _mpic_read(enum mpic_reg_type type, |
151 | unsigned int reg) | 151 | struct mpic_reg_bank *rb, |
152 | unsigned int reg) | ||
152 | { | 153 | { |
153 | if (be) | 154 | switch(type) { |
154 | return in_be32(base + (reg >> 2)); | 155 | #ifdef CONFIG_PPC_DCR |
155 | else | 156 | case mpic_access_dcr: |
156 | return in_le32(base + (reg >> 2)); | 157 | return dcr_read(rb->dhost, |
158 | rb->dbase + reg + rb->doff); | ||
159 | #endif | ||
160 | case mpic_access_mmio_be: | ||
161 | return in_be32(rb->base + (reg >> 2)); | ||
162 | case mpic_access_mmio_le: | ||
163 | default: | ||
164 | return in_le32(rb->base + (reg >> 2)); | ||
165 | } | ||
157 | } | 166 | } |
158 | 167 | ||
159 | static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, | 168 | static inline void _mpic_write(enum mpic_reg_type type, |
160 | unsigned int reg, u32 value) | 169 | struct mpic_reg_bank *rb, |
170 | unsigned int reg, u32 value) | ||
161 | { | 171 | { |
162 | if (be) | 172 | switch(type) { |
163 | out_be32(base + (reg >> 2), value); | 173 | #ifdef CONFIG_PPC_DCR |
164 | else | 174 | case mpic_access_dcr: |
165 | out_le32(base + (reg >> 2), value); | 175 | return dcr_write(rb->dhost, |
176 | rb->dbase + reg + rb->doff, value); | ||
177 | #endif | ||
178 | case mpic_access_mmio_be: | ||
179 | return out_be32(rb->base + (reg >> 2), value); | ||
180 | case mpic_access_mmio_le: | ||
181 | default: | ||
182 | return out_le32(rb->base + (reg >> 2), value); | ||
183 | } | ||
166 | } | 184 | } |
167 | 185 | ||
168 | static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) | 186 | static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) |
169 | { | 187 | { |
170 | unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; | 188 | enum mpic_reg_type type = mpic->reg_type; |
171 | unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + | 189 | unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + |
172 | (ipi * MPIC_INFO(GREG_IPI_STRIDE)); | 190 | (ipi * MPIC_INFO(GREG_IPI_STRIDE)); |
173 | 191 | ||
174 | if (mpic->flags & MPIC_BROKEN_IPI) | 192 | if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) |
175 | be = !be; | 193 | type = mpic_access_mmio_be; |
176 | return _mpic_read(be, mpic->gregs, offset); | 194 | return _mpic_read(type, &mpic->gregs, offset); |
177 | } | 195 | } |
178 | 196 | ||
179 | static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) | 197 | static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) |
@@ -181,7 +199,7 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu | |||
181 | unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + | 199 | unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + |
182 | (ipi * MPIC_INFO(GREG_IPI_STRIDE)); | 200 | (ipi * MPIC_INFO(GREG_IPI_STRIDE)); |
183 | 201 | ||
184 | _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); | 202 | _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); |
185 | } | 203 | } |
186 | 204 | ||
187 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | 205 | static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) |
@@ -190,8 +208,7 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | |||
190 | 208 | ||
191 | if (mpic->flags & MPIC_PRIMARY) | 209 | if (mpic->flags & MPIC_PRIMARY) |
192 | cpu = hard_smp_processor_id(); | 210 | cpu = hard_smp_processor_id(); |
193 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, | 211 | return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); |
194 | mpic->cpuregs[cpu], reg); | ||
195 | } | 212 | } |
196 | 213 | ||
197 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 214 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
@@ -201,7 +218,7 @@ static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 valu | |||
201 | if (mpic->flags & MPIC_PRIMARY) | 218 | if (mpic->flags & MPIC_PRIMARY) |
202 | cpu = hard_smp_processor_id(); | 219 | cpu = hard_smp_processor_id(); |
203 | 220 | ||
204 | _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); | 221 | _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); |
205 | } | 222 | } |
206 | 223 | ||
207 | static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) | 224 | static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) |
@@ -209,7 +226,7 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne | |||
209 | unsigned int isu = src_no >> mpic->isu_shift; | 226 | unsigned int isu = src_no >> mpic->isu_shift; |
210 | unsigned int idx = src_no & mpic->isu_mask; | 227 | unsigned int idx = src_no & mpic->isu_mask; |
211 | 228 | ||
212 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], | 229 | return _mpic_read(mpic->reg_type, &mpic->isus[isu], |
213 | reg + (idx * MPIC_INFO(IRQ_STRIDE))); | 230 | reg + (idx * MPIC_INFO(IRQ_STRIDE))); |
214 | } | 231 | } |
215 | 232 | ||
@@ -219,12 +236,12 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, | |||
219 | unsigned int isu = src_no >> mpic->isu_shift; | 236 | unsigned int isu = src_no >> mpic->isu_shift; |
220 | unsigned int idx = src_no & mpic->isu_mask; | 237 | unsigned int idx = src_no & mpic->isu_mask; |
221 | 238 | ||
222 | _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], | 239 | _mpic_write(mpic->reg_type, &mpic->isus[isu], |
223 | reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); | 240 | reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); |
224 | } | 241 | } |
225 | 242 | ||
226 | #define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) | 243 | #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) |
227 | #define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) | 244 | #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) |
228 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) | 245 | #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) |
229 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) | 246 | #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) |
230 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) | 247 | #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) |
@@ -238,6 +255,38 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, | |||
238 | */ | 255 | */ |
239 | 256 | ||
240 | 257 | ||
258 | static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr, | ||
259 | struct mpic_reg_bank *rb, unsigned int offset, | ||
260 | unsigned int size) | ||
261 | { | ||
262 | rb->base = ioremap(phys_addr + offset, size); | ||
263 | BUG_ON(rb->base == NULL); | ||
264 | } | ||
265 | |||
266 | #ifdef CONFIG_PPC_DCR | ||
267 | static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, | ||
268 | unsigned int offset, unsigned int size) | ||
269 | { | ||
270 | rb->dbase = mpic->dcr_base; | ||
271 | rb->doff = offset; | ||
272 | rb->dhost = dcr_map(mpic->of_node, rb->dbase + rb->doff, size); | ||
273 | BUG_ON(!DCR_MAP_OK(rb->dhost)); | ||
274 | } | ||
275 | |||
276 | static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr, | ||
277 | struct mpic_reg_bank *rb, unsigned int offset, | ||
278 | unsigned int size) | ||
279 | { | ||
280 | if (mpic->flags & MPIC_USES_DCR) | ||
281 | _mpic_map_dcr(mpic, rb, offset, size); | ||
282 | else | ||
283 | _mpic_map_mmio(mpic, phys_addr, rb, offset, size); | ||
284 | } | ||
285 | #else /* CONFIG_PPC_DCR */ | ||
286 | #define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) | ||
287 | #endif /* !CONFIG_PPC_DCR */ | ||
288 | |||
289 | |||
241 | 290 | ||
242 | /* Check if we have one of those nice broken MPICs with a flipped endian on | 291 | /* Check if we have one of those nice broken MPICs with a flipped endian on |
243 | * reads from IPI registers | 292 | * reads from IPI registers |
@@ -845,7 +894,7 @@ static struct irq_host_ops mpic_host_ops = { | |||
845 | */ | 894 | */ |
846 | 895 | ||
847 | struct mpic * __init mpic_alloc(struct device_node *node, | 896 | struct mpic * __init mpic_alloc(struct device_node *node, |
848 | unsigned long phys_addr, | 897 | phys_addr_t phys_addr, |
849 | unsigned int flags, | 898 | unsigned int flags, |
850 | unsigned int isu_size, | 899 | unsigned int isu_size, |
851 | unsigned int irq_count, | 900 | unsigned int irq_count, |
@@ -855,6 +904,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
855 | u32 reg; | 904 | u32 reg; |
856 | const char *vers; | 905 | const char *vers; |
857 | int i; | 906 | int i; |
907 | u64 paddr = phys_addr; | ||
858 | 908 | ||
859 | mpic = alloc_bootmem(sizeof(struct mpic)); | 909 | mpic = alloc_bootmem(sizeof(struct mpic)); |
860 | if (mpic == NULL) | 910 | if (mpic == NULL) |
@@ -883,6 +933,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
883 | if (flags & MPIC_PRIMARY) | 933 | if (flags & MPIC_PRIMARY) |
884 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | 934 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; |
885 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 935 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
936 | |||
886 | #ifdef CONFIG_SMP | 937 | #ifdef CONFIG_SMP |
887 | mpic->hc_ipi = mpic_ipi_chip; | 938 | mpic->hc_ipi = mpic_ipi_chip; |
888 | mpic->hc_ipi.typename = name; | 939 | mpic->hc_ipi.typename = name; |
@@ -893,15 +944,52 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
893 | mpic->irq_count = irq_count; | 944 | mpic->irq_count = irq_count; |
894 | mpic->num_sources = 0; /* so far */ | 945 | mpic->num_sources = 0; /* so far */ |
895 | 946 | ||
947 | /* Check for "big-endian" in device-tree */ | ||
948 | if (node && get_property(node, "big-endian", NULL) != NULL) | ||
949 | mpic->flags |= MPIC_BIG_ENDIAN; | ||
950 | |||
951 | |||
896 | #ifdef CONFIG_MPIC_WEIRD | 952 | #ifdef CONFIG_MPIC_WEIRD |
897 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; | 953 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; |
898 | #endif | 954 | #endif |
899 | 955 | ||
956 | /* default register type */ | ||
957 | mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? | ||
958 | mpic_access_mmio_be : mpic_access_mmio_le; | ||
959 | |||
960 | /* If no physical address is passed in, a device-node is mandatory */ | ||
961 | BUG_ON(paddr == 0 && node == NULL); | ||
962 | |||
963 | /* If no physical address passed in, check if it's dcr based */ | ||
964 | if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL) | ||
965 | mpic->flags |= MPIC_USES_DCR; | ||
966 | |||
967 | #ifdef CONFIG_PPC_DCR | ||
968 | if (mpic->flags & MPIC_USES_DCR) { | ||
969 | const u32 *dbasep; | ||
970 | dbasep = get_property(node, "dcr-reg", NULL); | ||
971 | BUG_ON(dbasep == NULL); | ||
972 | mpic->dcr_base = *dbasep; | ||
973 | mpic->reg_type = mpic_access_dcr; | ||
974 | } | ||
975 | #else | ||
976 | BUG_ON (mpic->flags & MPIC_USES_DCR); | ||
977 | #endif /* CONFIG_PPC_DCR */ | ||
978 | |||
979 | /* If the MPIC is not DCR based, and no physical address was passed | ||
980 | * in, try to obtain one | ||
981 | */ | ||
982 | if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { | ||
983 | const u32 *reg; | ||
984 | reg = get_property(node, "reg", NULL); | ||
985 | BUG_ON(reg == NULL); | ||
986 | paddr = of_translate_address(node, reg); | ||
987 | BUG_ON(paddr == OF_BAD_ADDR); | ||
988 | } | ||
989 | |||
900 | /* Map the global registers */ | 990 | /* Map the global registers */ |
901 | mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000); | 991 | mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); |
902 | mpic->tmregs = mpic->gregs + | 992 | mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); |
903 | ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2); | ||
904 | BUG_ON(mpic->gregs == NULL); | ||
905 | 993 | ||
906 | /* Reset */ | 994 | /* Reset */ |
907 | if (flags & MPIC_WANTS_RESET) { | 995 | if (flags & MPIC_WANTS_RESET) { |
@@ -926,17 +1014,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
926 | 1014 | ||
927 | /* Map the per-CPU registers */ | 1015 | /* Map the per-CPU registers */ |
928 | for (i = 0; i < mpic->num_cpus; i++) { | 1016 | for (i = 0; i < mpic->num_cpus; i++) { |
929 | mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) + | 1017 | mpic_map(mpic, paddr, &mpic->cpuregs[i], |
930 | i * MPIC_INFO(CPU_STRIDE), 0x1000); | 1018 | MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), |
931 | BUG_ON(mpic->cpuregs[i] == NULL); | 1019 | 0x1000); |
932 | } | 1020 | } |
933 | 1021 | ||
934 | /* Initialize main ISU if none provided */ | 1022 | /* Initialize main ISU if none provided */ |
935 | if (mpic->isu_size == 0) { | 1023 | if (mpic->isu_size == 0) { |
936 | mpic->isu_size = mpic->num_sources; | 1024 | mpic->isu_size = mpic->num_sources; |
937 | mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE), | 1025 | mpic_map(mpic, paddr, &mpic->isus[0], |
938 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1026 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
939 | BUG_ON(mpic->isus[0] == NULL); | ||
940 | } | 1027 | } |
941 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); | 1028 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); |
942 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; | 1029 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; |
@@ -956,10 +1043,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
956 | vers = "<unknown>"; | 1043 | vers = "<unknown>"; |
957 | break; | 1044 | break; |
958 | } | 1045 | } |
959 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", | 1046 | printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," |
960 | name, vers, phys_addr, mpic->num_cpus); | 1047 | " max %d CPUs\n", |
961 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, | 1048 | name, vers, (unsigned long long)paddr, mpic->num_cpus); |
962 | mpic->isu_shift, mpic->isu_mask); | 1049 | printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", |
1050 | mpic->isu_size, mpic->isu_shift, mpic->isu_mask); | ||
963 | 1051 | ||
964 | mpic->next = mpics; | 1052 | mpic->next = mpics; |
965 | mpics = mpic; | 1053 | mpics = mpic; |
@@ -973,14 +1061,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
973 | } | 1061 | } |
974 | 1062 | ||
975 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | 1063 | void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, |
976 | unsigned long phys_addr) | 1064 | phys_addr_t paddr) |
977 | { | 1065 | { |
978 | unsigned int isu_first = isu_num * mpic->isu_size; | 1066 | unsigned int isu_first = isu_num * mpic->isu_size; |
979 | 1067 | ||
980 | BUG_ON(isu_num >= MPIC_MAX_ISU); | 1068 | BUG_ON(isu_num >= MPIC_MAX_ISU); |
981 | 1069 | ||
982 | mpic->isus[isu_num] = ioremap(phys_addr, | 1070 | mpic_map(mpic, paddr, &mpic->isus[isu_num], 0, |
983 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1071 | MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); |
984 | if ((isu_first + mpic->isu_size) > mpic->num_sources) | 1072 | if ((isu_first + mpic->isu_size) > mpic->num_sources) |
985 | mpic->num_sources = isu_first + mpic->isu_size; | 1073 | mpic->num_sources = isu_first + mpic->isu_size; |
986 | } | 1074 | } |