diff options
-rw-r--r-- | arch/powerpc/boot/addnote.c | 144 | ||||
-rwxr-xr-x | arch/powerpc/boot/wrapper | 4 | ||||
-rw-r--r-- | arch/powerpc/include/asm/smp.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_32.S | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_64.S | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 3 | ||||
-rw-r--r-- | arch/powerpc/mm/numa.c | 108 | ||||
-rw-r--r-- | arch/powerpc/oprofile/cell/vma_map.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 11 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/smp.c | 32 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 539 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.h | 12 | ||||
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 3 | ||||
-rw-r--r-- | drivers/ata/pata_of_platform.c | 2 | ||||
-rw-r--r-- | drivers/of/base.c | 134 | ||||
-rw-r--r-- | drivers/of/gpio.c | 81 | ||||
-rw-r--r-- | include/linux/of.h | 3 |
20 files changed, 650 insertions, 462 deletions
diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c index b1e5611b2ab1..dcc9ab2ca823 100644 --- a/arch/powerpc/boot/addnote.c +++ b/arch/powerpc/boot/addnote.c | |||
@@ -11,7 +11,12 @@ | |||
11 | * as published by the Free Software Foundation; either version | 11 | * as published by the Free Software Foundation; either version |
12 | * 2 of the License, or (at your option) any later version. | 12 | * 2 of the License, or (at your option) any later version. |
13 | * | 13 | * |
14 | * Usage: addnote zImage | 14 | * Usage: addnote zImage [note.elf] |
15 | * | ||
16 | * If note.elf is supplied, it is the name of an ELF file that contains | ||
17 | * an RPA note to use instead of the built-in one. Alternatively, the | ||
18 | * note.elf file may be empty, in which case the built-in RPA note is | ||
19 | * used (this is to simplify how this is invoked from the wrapper script). | ||
15 | */ | 20 | */ |
16 | #include <stdio.h> | 21 | #include <stdio.h> |
17 | #include <stdlib.h> | 22 | #include <stdlib.h> |
@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config"; | |||
43 | */ | 48 | */ |
44 | #define N_RPA_DESCR 8 | 49 | #define N_RPA_DESCR 8 |
45 | unsigned int rpanote[N_RPA_DESCR] = { | 50 | unsigned int rpanote[N_RPA_DESCR] = { |
46 | 0, /* lparaffinity */ | 51 | 1, /* lparaffinity */ |
47 | 64, /* min_rmo_size */ | 52 | 128, /* min_rmo_size */ |
48 | 0, /* min_rmo_percent */ | 53 | 0, /* min_rmo_percent */ |
49 | 40, /* max_pft_size */ | 54 | 46, /* max_pft_size */ |
50 | 1, /* splpar */ | 55 | 1, /* splpar */ |
51 | -1, /* min_load */ | 56 | -1, /* min_load */ |
52 | 0, /* new_mem_def */ | 57 | 1, /* new_mem_def */ |
53 | 1, /* ignore_my_client_config */ | 58 | 0, /* ignore_my_client_config */ |
54 | }; | 59 | }; |
55 | 60 | ||
56 | #define ROUNDUP(len) (((len) + 3) & ~3) | 61 | #define ROUNDUP(len) (((len) + 3) & ~3) |
57 | 62 | ||
58 | unsigned char buf[512]; | 63 | unsigned char buf[512]; |
64 | unsigned char notebuf[512]; | ||
59 | 65 | ||
60 | #define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) | 66 | #define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1])) |
61 | #define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) | 67 | #define GET_32BE(b, off) ((GET_16BE((b), (off)) << 16) + \ |
68 | GET_16BE((b), (off)+2)) | ||
62 | 69 | ||
63 | #define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ | 70 | #define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \ |
64 | buf[(off) + 1] = (v) & 0xff) | 71 | (b)[(off) + 1] = (v) & 0xff) |
65 | #define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ | 72 | #define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \ |
66 | PUT_16BE((off) + 2, (v))) | 73 | PUT_16BE((b), (off) + 2, (v))) |
67 | 74 | ||
68 | /* Structure of an ELF file */ | 75 | /* Structure of an ELF file */ |
69 | #define E_IDENT 0 /* ELF header */ | 76 | #define E_IDENT 0 /* ELF header */ |
@@ -88,15 +95,71 @@ unsigned char buf[512]; | |||
88 | 95 | ||
89 | unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; | 96 | unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; |
90 | 97 | ||
98 | unsigned char *read_rpanote(const char *fname, int *nnp) | ||
99 | { | ||
100 | int notefd, nr, i; | ||
101 | int ph, ps, np; | ||
102 | int note, notesize; | ||
103 | |||
104 | notefd = open(fname, O_RDONLY); | ||
105 | if (notefd < 0) { | ||
106 | perror(fname); | ||
107 | exit(1); | ||
108 | } | ||
109 | nr = read(notefd, notebuf, sizeof(notebuf)); | ||
110 | if (nr < 0) { | ||
111 | perror("read note"); | ||
112 | exit(1); | ||
113 | } | ||
114 | if (nr == 0) /* empty file */ | ||
115 | return NULL; | ||
116 | if (nr < E_HSIZE || | ||
117 | memcmp(¬ebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 || | ||
118 | notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 || | ||
119 | notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB) | ||
120 | goto notelf; | ||
121 | close(notefd); | ||
122 | |||
123 | /* now look for the RPA-note */ | ||
124 | ph = GET_32BE(notebuf, E_PHOFF); | ||
125 | ps = GET_16BE(notebuf, E_PHENTSIZE); | ||
126 | np = GET_16BE(notebuf, E_PHNUM); | ||
127 | if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) | ||
128 | goto notelf; | ||
129 | |||
130 | for (i = 0; i < np; ++i, ph += ps) { | ||
131 | if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE) | ||
132 | continue; | ||
133 | note = GET_32BE(notebuf, ph + PH_OFFSET); | ||
134 | notesize = GET_32BE(notebuf, ph + PH_FILESZ); | ||
135 | if (notesize < 34 || note + notesize > nr) | ||
136 | continue; | ||
137 | if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 || | ||
138 | GET_32BE(notebuf, note + 8) != 0x12759999 || | ||
139 | strcmp((char *)¬ebuf[note + 12], rpaname) != 0) | ||
140 | continue; | ||
141 | /* looks like an RPA note, return it */ | ||
142 | *nnp = notesize; | ||
143 | return ¬ebuf[note]; | ||
144 | } | ||
145 | /* no RPA note found */ | ||
146 | return NULL; | ||
147 | |||
148 | notelf: | ||
149 | fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname); | ||
150 | exit(1); | ||
151 | } | ||
152 | |||
91 | int | 153 | int |
92 | main(int ac, char **av) | 154 | main(int ac, char **av) |
93 | { | 155 | { |
94 | int fd, n, i; | 156 | int fd, n, i; |
95 | int ph, ps, np; | 157 | int ph, ps, np; |
96 | int nnote, nnote2, ns; | 158 | int nnote, nnote2, ns; |
159 | unsigned char *rpap; | ||
97 | 160 | ||
98 | if (ac != 2) { | 161 | if (ac != 2 && ac != 3) { |
99 | fprintf(stderr, "Usage: %s elf-file\n", av[0]); | 162 | fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]); |
100 | exit(1); | 163 | exit(1); |
101 | } | 164 | } |
102 | fd = open(av[1], O_RDWR); | 165 | fd = open(av[1], O_RDWR); |
@@ -107,6 +170,7 @@ main(int ac, char **av) | |||
107 | 170 | ||
108 | nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); | 171 | nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); |
109 | nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); | 172 | nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); |
173 | rpap = NULL; | ||
110 | 174 | ||
111 | n = read(fd, buf, sizeof(buf)); | 175 | n = read(fd, buf, sizeof(buf)); |
112 | if (n < 0) { | 176 | if (n < 0) { |
@@ -124,16 +188,19 @@ main(int ac, char **av) | |||
124 | exit(1); | 188 | exit(1); |
125 | } | 189 | } |
126 | 190 | ||
127 | ph = GET_32BE(E_PHOFF); | 191 | if (ac == 3) |
128 | ps = GET_16BE(E_PHENTSIZE); | 192 | rpap = read_rpanote(av[2], &nnote2); |
129 | np = GET_16BE(E_PHNUM); | 193 | |
194 | ph = GET_32BE(buf, E_PHOFF); | ||
195 | ps = GET_16BE(buf, E_PHENTSIZE); | ||
196 | np = GET_16BE(buf, E_PHNUM); | ||
130 | if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) | 197 | if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) |
131 | goto notelf; | 198 | goto notelf; |
132 | if (ph + (np + 2) * ps + nnote + nnote2 > n) | 199 | if (ph + (np + 2) * ps + nnote + nnote2 > n) |
133 | goto nospace; | 200 | goto nospace; |
134 | 201 | ||
135 | for (i = 0; i < np; ++i) { | 202 | for (i = 0; i < np; ++i) { |
136 | if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { | 203 | if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) { |
137 | fprintf(stderr, "%s already has a note entry\n", | 204 | fprintf(stderr, "%s already has a note entry\n", |
138 | av[1]); | 205 | av[1]); |
139 | exit(0); | 206 | exit(0); |
@@ -148,37 +215,42 @@ main(int ac, char **av) | |||
148 | 215 | ||
149 | /* fill in the program header entry */ | 216 | /* fill in the program header entry */ |
150 | ns = ph + 2 * ps; | 217 | ns = ph + 2 * ps; |
151 | PUT_32BE(ph + PH_TYPE, PT_NOTE); | 218 | PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); |
152 | PUT_32BE(ph + PH_OFFSET, ns); | 219 | PUT_32BE(buf, ph + PH_OFFSET, ns); |
153 | PUT_32BE(ph + PH_FILESZ, nnote); | 220 | PUT_32BE(buf, ph + PH_FILESZ, nnote); |
154 | 221 | ||
155 | /* fill in the note area we point to */ | 222 | /* fill in the note area we point to */ |
156 | /* XXX we should probably make this a proper section */ | 223 | /* XXX we should probably make this a proper section */ |
157 | PUT_32BE(ns, strlen(arch) + 1); | 224 | PUT_32BE(buf, ns, strlen(arch) + 1); |
158 | PUT_32BE(ns + 4, N_DESCR * 4); | 225 | PUT_32BE(buf, ns + 4, N_DESCR * 4); |
159 | PUT_32BE(ns + 8, 0x1275); | 226 | PUT_32BE(buf, ns + 8, 0x1275); |
160 | strcpy((char *) &buf[ns + 12], arch); | 227 | strcpy((char *) &buf[ns + 12], arch); |
161 | ns += 12 + strlen(arch) + 1; | 228 | ns += 12 + strlen(arch) + 1; |
162 | for (i = 0; i < N_DESCR; ++i, ns += 4) | 229 | for (i = 0; i < N_DESCR; ++i, ns += 4) |
163 | PUT_32BE(ns, descr[i]); | 230 | PUT_32BE(buf, ns, descr[i]); |
164 | 231 | ||
165 | /* fill in the second program header entry and the RPA note area */ | 232 | /* fill in the second program header entry and the RPA note area */ |
166 | ph += ps; | 233 | ph += ps; |
167 | PUT_32BE(ph + PH_TYPE, PT_NOTE); | 234 | PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); |
168 | PUT_32BE(ph + PH_OFFSET, ns); | 235 | PUT_32BE(buf, ph + PH_OFFSET, ns); |
169 | PUT_32BE(ph + PH_FILESZ, nnote2); | 236 | PUT_32BE(buf, ph + PH_FILESZ, nnote2); |
170 | 237 | ||
171 | /* fill in the note area we point to */ | 238 | /* fill in the note area we point to */ |
172 | PUT_32BE(ns, strlen(rpaname) + 1); | 239 | if (rpap) { |
173 | PUT_32BE(ns + 4, sizeof(rpanote)); | 240 | /* RPA note supplied in file, just copy the whole thing over */ |
174 | PUT_32BE(ns + 8, 0x12759999); | 241 | memcpy(buf + ns, rpap, nnote2); |
175 | strcpy((char *) &buf[ns + 12], rpaname); | 242 | } else { |
176 | ns += 12 + ROUNDUP(strlen(rpaname) + 1); | 243 | PUT_32BE(buf, ns, strlen(rpaname) + 1); |
177 | for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) | 244 | PUT_32BE(buf, ns + 4, sizeof(rpanote)); |
178 | PUT_32BE(ns, rpanote[i]); | 245 | PUT_32BE(buf, ns + 8, 0x12759999); |
246 | strcpy((char *) &buf[ns + 12], rpaname); | ||
247 | ns += 12 + ROUNDUP(strlen(rpaname) + 1); | ||
248 | for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) | ||
249 | PUT_32BE(buf, ns, rpanote[i]); | ||
250 | } | ||
179 | 251 | ||
180 | /* Update the number of program headers */ | 252 | /* Update the number of program headers */ |
181 | PUT_16BE(E_PHNUM, np + 2); | 253 | PUT_16BE(buf, E_PHNUM, np + 2); |
182 | 254 | ||
183 | /* write back */ | 255 | /* write back */ |
184 | lseek(fd, (long) 0, SEEK_SET); | 256 | lseek(fd, (long) 0, SEEK_SET); |
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 965c237c122d..ee0dc41d7c56 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper | |||
@@ -307,7 +307,9 @@ fi | |||
307 | # post-processing needed for some platforms | 307 | # post-processing needed for some platforms |
308 | case "$platform" in | 308 | case "$platform" in |
309 | pseries|chrp) | 309 | pseries|chrp) |
310 | $objbin/addnote "$ofile" | 310 | ${CROSS}objcopy -O binary -j .fakeelf "$kernel" "$ofile".rpanote |
311 | $objbin/addnote "$ofile" "$ofile".rpanote | ||
312 | rm -r "$ofile".rpanote | ||
311 | ;; | 313 | ;; |
312 | coff) | 314 | coff) |
313 | ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" | 315 | ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" |
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index c092f84302fd..1866cec4f967 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h | |||
@@ -93,7 +93,7 @@ extern void __cpu_die(unsigned int cpu); | |||
93 | 93 | ||
94 | #else | 94 | #else |
95 | /* for UP */ | 95 | /* for UP */ |
96 | #define hard_smp_processor_id() 0 | 96 | #define hard_smp_processor_id() get_hard_smp_processor_id(0) |
97 | #define smp_setup_cpu_maps() | 97 | #define smp_setup_cpu_maps() |
98 | 98 | ||
99 | #endif /* CONFIG_SMP */ | 99 | #endif /* CONFIG_SMP */ |
@@ -122,6 +122,7 @@ static inline int get_hard_smp_processor_id(int cpu) | |||
122 | 122 | ||
123 | static inline void set_hard_smp_processor_id(int cpu, int phys) | 123 | static inline void set_hard_smp_processor_id(int cpu, int phys) |
124 | { | 124 | { |
125 | boot_cpuid_phys = phys; | ||
125 | } | 126 | } |
126 | #endif /* !CONFIG_SMP */ | 127 | #endif /* !CONFIG_SMP */ |
127 | #endif /* !CONFIG_PPC64 */ | 128 | #endif /* !CONFIG_PPC64 */ |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index e9c8ab6eabfe..6a9b4bf0d173 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -900,8 +900,10 @@ _GLOBAL(kernel_thread) | |||
900 | li r4,0 /* new sp (unused) */ | 900 | li r4,0 /* new sp (unused) */ |
901 | li r0,__NR_clone | 901 | li r0,__NR_clone |
902 | sc | 902 | sc |
903 | cmpwi 0,r3,0 /* parent or child? */ | 903 | bns+ 1f /* did system call indicate error? */ |
904 | bne 1f /* return if parent */ | 904 | neg r3,r3 /* if so, make return code negative */ |
905 | 1: cmpwi 0,r3,0 /* parent or child? */ | ||
906 | bne 2f /* return if parent */ | ||
905 | li r0,0 /* make top-level stack frame */ | 907 | li r0,0 /* make top-level stack frame */ |
906 | stwu r0,-16(r1) | 908 | stwu r0,-16(r1) |
907 | mtlr r30 /* fn addr in lr */ | 909 | mtlr r30 /* fn addr in lr */ |
@@ -911,7 +913,7 @@ _GLOBAL(kernel_thread) | |||
911 | li r0,__NR_exit /* exit if function returns */ | 913 | li r0,__NR_exit /* exit if function returns */ |
912 | li r3,0 | 914 | li r3,0 |
913 | sc | 915 | sc |
914 | 1: lwz r30,8(r1) | 916 | 2: lwz r30,8(r1) |
915 | lwz r31,12(r1) | 917 | lwz r31,12(r1) |
916 | addi r1,r1,16 | 918 | addi r1,r1,16 |
917 | blr | 919 | blr |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 4dd70cf7bb4e..3053fe5c62f2 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -426,8 +426,10 @@ _GLOBAL(kernel_thread) | |||
426 | li r4,0 /* new sp (unused) */ | 426 | li r4,0 /* new sp (unused) */ |
427 | li r0,__NR_clone | 427 | li r0,__NR_clone |
428 | sc | 428 | sc |
429 | cmpdi 0,r3,0 /* parent or child? */ | 429 | bns+ 1f /* did system call indicate error? */ |
430 | bne 1f /* return if parent */ | 430 | neg r3,r3 /* if so, make return code negative */ |
431 | 1: cmpdi 0,r3,0 /* parent or child? */ | ||
432 | bne 2f /* return if parent */ | ||
431 | li r0,0 | 433 | li r0,0 |
432 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | 434 | stdu r0,-STACK_FRAME_OVERHEAD(r1) |
433 | ld r2,8(r29) | 435 | ld r2,8(r29) |
@@ -438,7 +440,7 @@ _GLOBAL(kernel_thread) | |||
438 | li r0,__NR_exit /* exit after child exits */ | 440 | li r0,__NR_exit /* exit after child exits */ |
439 | li r3,0 | 441 | li r3,0 |
440 | sc | 442 | sc |
441 | 1: addi r1,r1,STACK_FRAME_OVERHEAD | 443 | 2: addi r1,r1,STACK_FRAME_OVERHEAD |
442 | ld r29,-24(r1) | 444 | ld r29,-24(r1) |
443 | ld r30,-16(r1) | 445 | ld r30,-16(r1) |
444 | blr | 446 | blr |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 7cf274a2b334..2fdbc18ae94a 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -732,7 +732,7 @@ static struct fake_elf { | |||
732 | u32 ignore_me; | 732 | u32 ignore_me; |
733 | } rpadesc; | 733 | } rpadesc; |
734 | } rpanote; | 734 | } rpanote; |
735 | } fake_elf = { | 735 | } fake_elf __section(.fakeelf) = { |
736 | .elfhdr = { | 736 | .elfhdr = { |
737 | .e_ident = { 0x7f, 'E', 'L', 'F', | 737 | .e_ident = { 0x7f, 'E', 'L', 'F', |
738 | ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, | 738 | ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, |
@@ -774,13 +774,13 @@ static struct fake_elf { | |||
774 | .type = 0x12759999, | 774 | .type = 0x12759999, |
775 | .name = "IBM,RPA-Client-Config", | 775 | .name = "IBM,RPA-Client-Config", |
776 | .rpadesc = { | 776 | .rpadesc = { |
777 | .lpar_affinity = 0, | 777 | .lpar_affinity = 1, |
778 | .min_rmo_size = 64, /* in megabytes */ | 778 | .min_rmo_size = 128, /* in megabytes */ |
779 | .min_rmo_percent = 0, | 779 | .min_rmo_percent = 0, |
780 | .max_pft_size = 48, /* 2^48 bytes max PFT size */ | 780 | .max_pft_size = 46, /* 2^46 bytes max PFT size */ |
781 | .splpar = 1, | 781 | .splpar = 1, |
782 | .min_load = ~0U, | 782 | .min_load = ~0U, |
783 | .new_mem_def = 0 | 783 | .new_mem_def = 1 |
784 | } | 784 | } |
785 | } | 785 | } |
786 | }; | 786 | }; |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 5337ca7bb649..3ee736fa8b1d 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -101,8 +101,7 @@ void smp_message_recv(int msg) | |||
101 | generic_smp_call_function_interrupt(); | 101 | generic_smp_call_function_interrupt(); |
102 | break; | 102 | break; |
103 | case PPC_MSG_RESCHEDULE: | 103 | case PPC_MSG_RESCHEDULE: |
104 | /* XXX Do we have to do this? */ | 104 | /* we notice need_resched on exit */ |
105 | set_need_resched(); | ||
106 | break; | 105 | break; |
107 | case PPC_MSG_CALL_FUNC_SINGLE: | 106 | case PPC_MSG_CALL_FUNC_SINGLE: |
108 | generic_smp_call_function_single_interrupt(); | 107 | generic_smp_call_function_single_interrupt(); |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index e6927fb2e655..b39c27ed7919 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -203,6 +203,9 @@ SECTIONS | |||
203 | *(.rela*) | 203 | *(.rela*) |
204 | } | 204 | } |
205 | 205 | ||
206 | /* Fake ELF header containing RPA note; for addnote */ | ||
207 | .fakeelf : AT(ADDR(.fakeelf) - LOAD_OFFSET) { *(.fakeelf) } | ||
208 | |||
206 | /* freed after init ends here */ | 209 | /* freed after init ends here */ |
207 | . = ALIGN(PAGE_SIZE); | 210 | . = ALIGN(PAGE_SIZE); |
208 | __init_end = .; | 211 | __init_end = .; |
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index be05457631d4..6cf5c71c431f 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
@@ -89,6 +89,46 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn, | |||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | ||
93 | * get_active_region_work_fn - A helper function for get_node_active_region | ||
94 | * Returns datax set to the start_pfn and end_pfn if they contain | ||
95 | * the initial value of datax->start_pfn between them | ||
96 | * @start_pfn: start page(inclusive) of region to check | ||
97 | * @end_pfn: end page(exclusive) of region to check | ||
98 | * @datax: comes in with ->start_pfn set to value to search for and | ||
99 | * goes out with active range if it contains it | ||
100 | * Returns 1 if search value is in range else 0 | ||
101 | */ | ||
102 | static int __init get_active_region_work_fn(unsigned long start_pfn, | ||
103 | unsigned long end_pfn, void *datax) | ||
104 | { | ||
105 | struct node_active_region *data; | ||
106 | data = (struct node_active_region *)datax; | ||
107 | |||
108 | if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) { | ||
109 | data->start_pfn = start_pfn; | ||
110 | data->end_pfn = end_pfn; | ||
111 | return 1; | ||
112 | } | ||
113 | return 0; | ||
114 | |||
115 | } | ||
116 | |||
117 | /* | ||
118 | * get_node_active_region - Return active region containing start_pfn | ||
119 | * @start_pfn: The page to return the region for. | ||
120 | * @node_ar: Returned set to the active region containing start_pfn | ||
121 | */ | ||
122 | static void __init get_node_active_region(unsigned long start_pfn, | ||
123 | struct node_active_region *node_ar) | ||
124 | { | ||
125 | int nid = early_pfn_to_nid(start_pfn); | ||
126 | |||
127 | node_ar->nid = nid; | ||
128 | node_ar->start_pfn = start_pfn; | ||
129 | work_with_active_regions(nid, get_active_region_work_fn, node_ar); | ||
130 | } | ||
131 | |||
92 | static void __cpuinit map_cpu_to_node(int cpu, int node) | 132 | static void __cpuinit map_cpu_to_node(int cpu, int node) |
93 | { | 133 | { |
94 | numa_cpu_lookup_table[cpu] = node; | 134 | numa_cpu_lookup_table[cpu] = node; |
@@ -882,38 +922,50 @@ void __init do_init_bootmem(void) | |||
882 | start_pfn, end_pfn); | 922 | start_pfn, end_pfn); |
883 | 923 | ||
884 | free_bootmem_with_active_regions(nid, end_pfn); | 924 | free_bootmem_with_active_regions(nid, end_pfn); |
925 | } | ||
885 | 926 | ||
886 | /* Mark reserved regions on this node */ | 927 | /* Mark reserved regions */ |
887 | for (i = 0; i < lmb.reserved.cnt; i++) { | 928 | for (i = 0; i < lmb.reserved.cnt; i++) { |
888 | unsigned long physbase = lmb.reserved.region[i].base; | 929 | unsigned long physbase = lmb.reserved.region[i].base; |
889 | unsigned long size = lmb.reserved.region[i].size; | 930 | unsigned long size = lmb.reserved.region[i].size; |
890 | unsigned long start_paddr = start_pfn << PAGE_SHIFT; | 931 | unsigned long start_pfn = physbase >> PAGE_SHIFT; |
891 | unsigned long end_paddr = end_pfn << PAGE_SHIFT; | 932 | unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT); |
892 | 933 | struct node_active_region node_ar; | |
893 | if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid && | 934 | |
894 | early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid) | 935 | get_node_active_region(start_pfn, &node_ar); |
895 | continue; | 936 | while (start_pfn < end_pfn) { |
896 | 937 | /* | |
897 | if (physbase < end_paddr && | 938 | * if reserved region extends past active region |
898 | (physbase+size) > start_paddr) { | 939 | * then trim size to active region |
899 | /* overlaps */ | 940 | */ |
900 | if (physbase < start_paddr) { | 941 | if (end_pfn > node_ar.end_pfn) |
901 | size -= start_paddr - physbase; | 942 | size = (node_ar.end_pfn << PAGE_SHIFT) |
902 | physbase = start_paddr; | 943 | - (start_pfn << PAGE_SHIFT); |
903 | } | 944 | dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, size, |
904 | 945 | node_ar.nid); | |
905 | if (size > end_paddr - physbase) | 946 | reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase, |
906 | size = end_paddr - physbase; | 947 | size, BOOTMEM_DEFAULT); |
907 | 948 | /* | |
908 | dbg("reserve_bootmem %lx %lx\n", physbase, | 949 | * if reserved region is contained in the active region |
909 | size); | 950 | * then done. |
910 | reserve_bootmem_node(NODE_DATA(nid), physbase, | 951 | */ |
911 | size, BOOTMEM_DEFAULT); | 952 | if (end_pfn <= node_ar.end_pfn) |
912 | } | 953 | break; |
954 | |||
955 | /* | ||
956 | * reserved region extends past the active region | ||
957 | * get next active region that contains this | ||
958 | * reserved region | ||
959 | */ | ||
960 | start_pfn = node_ar.end_pfn; | ||
961 | physbase = start_pfn << PAGE_SHIFT; | ||
962 | get_node_active_region(start_pfn, &node_ar); | ||
913 | } | 963 | } |
914 | 964 | ||
915 | sparse_memory_present_with_active_regions(nid); | ||
916 | } | 965 | } |
966 | |||
967 | for_each_online_node(nid) | ||
968 | sparse_memory_present_with_active_regions(nid); | ||
917 | } | 969 | } |
918 | 970 | ||
919 | void __init paging_init(void) | 971 | void __init paging_init(void) |
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c index fff66662d021..258fa4411e9e 100644 --- a/arch/powerpc/oprofile/cell/vma_map.c +++ b/arch/powerpc/oprofile/cell/vma_map.c | |||
@@ -229,7 +229,7 @@ struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu, | |||
229 | */ | 229 | */ |
230 | overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym, | 230 | overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym, |
231 | aSpu, &grd_val); | 231 | aSpu, &grd_val); |
232 | if (overlay_tbl_offset < 0) { | 232 | if (overlay_tbl_offset > 0x10000000) { |
233 | printk(KERN_ERR "SPU_PROF: " | 233 | printk(KERN_ERR "SPU_PROF: " |
234 | "%s, line %d: Error finding SPU overlay table\n", | 234 | "%s, line %d: Error finding SPU overlay table\n", |
235 | __func__, __LINE__); | 235 | __func__, __LINE__); |
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 690ca7b0dcf6..6b7c7b132454 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -298,8 +298,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, | |||
298 | 298 | ||
299 | d_instantiate(dentry, inode); | 299 | d_instantiate(dentry, inode); |
300 | dget(dentry); | 300 | dget(dentry); |
301 | dir->i_nlink++; | 301 | inc_nlink(dir); |
302 | dentry->d_inode->i_nlink++; | 302 | inc_nlink(dentry->d_inode); |
303 | goto out; | 303 | goto out; |
304 | 304 | ||
305 | out_free_ctx: | 305 | out_free_ctx: |
@@ -496,6 +496,8 @@ spufs_create_context(struct inode *inode, struct dentry *dentry, | |||
496 | ret = spufs_context_open(dget(dentry), mntget(mnt)); | 496 | ret = spufs_context_open(dget(dentry), mntget(mnt)); |
497 | if (ret < 0) { | 497 | if (ret < 0) { |
498 | WARN_ON(spufs_rmdir(inode, dentry)); | 498 | WARN_ON(spufs_rmdir(inode, dentry)); |
499 | if (affinity) | ||
500 | mutex_unlock(&gang->aff_mutex); | ||
499 | mutex_unlock(&inode->i_mutex); | 501 | mutex_unlock(&inode->i_mutex); |
500 | spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); | 502 | spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); |
501 | goto out; | 503 | goto out; |
@@ -538,8 +540,8 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) | |||
538 | inode->i_fop = &simple_dir_operations; | 540 | inode->i_fop = &simple_dir_operations; |
539 | 541 | ||
540 | d_instantiate(dentry, inode); | 542 | d_instantiate(dentry, inode); |
541 | dir->i_nlink++; | 543 | inc_nlink(dir); |
542 | dentry->d_inode->i_nlink++; | 544 | inc_nlink(dentry->d_inode); |
543 | return ret; | 545 | return ret; |
544 | 546 | ||
545 | out_iput: | 547 | out_iput: |
@@ -755,6 +757,7 @@ spufs_create_root(struct super_block *sb, void *data) | |||
755 | inode->i_op = &simple_dir_inode_operations; | 757 | inode->i_op = &simple_dir_inode_operations; |
756 | inode->i_fop = &simple_dir_operations; | 758 | inode->i_fop = &simple_dir_operations; |
757 | SPUFS_I(inode)->i_ctx = NULL; | 759 | SPUFS_I(inode)->i_ctx = NULL; |
760 | inc_nlink(inode); | ||
758 | 761 | ||
759 | ret = -EINVAL; | 762 | ret = -EINVAL; |
760 | if (!spufs_parse_options(sb, data, inode)) | 763 | if (!spufs_parse_options(sb, data, inode)) |
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index a1a368dd2d99..140d02a5232a 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c | |||
@@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size) | |||
21 | struct zone *zone; | 21 | struct zone *zone; |
22 | int ret; | 22 | int ret; |
23 | 23 | ||
24 | start_pfn = base >> PFN_SECTION_SHIFT; | 24 | start_pfn = base >> PAGE_SHIFT; |
25 | zone = page_zone(pfn_to_page(start_pfn)); | 25 | zone = page_zone(pfn_to_page(start_pfn)); |
26 | 26 | ||
27 | /* | 27 | /* |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 9d8f8c84ab89..e00f96baa381 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <asm/paca.h> | 37 | #include <asm/paca.h> |
38 | #include <asm/time.h> | 38 | #include <asm/time.h> |
39 | #include <asm/machdep.h> | 39 | #include <asm/machdep.h> |
40 | #include "xics.h" | ||
41 | #include <asm/cputable.h> | 40 | #include <asm/cputable.h> |
42 | #include <asm/firmware.h> | 41 | #include <asm/firmware.h> |
43 | #include <asm/system.h> | 42 | #include <asm/system.h> |
@@ -49,6 +48,7 @@ | |||
49 | 48 | ||
50 | #include "plpar_wrappers.h" | 49 | #include "plpar_wrappers.h" |
51 | #include "pseries.h" | 50 | #include "pseries.h" |
51 | #include "xics.h" | ||
52 | 52 | ||
53 | 53 | ||
54 | /* | 54 | /* |
@@ -105,36 +105,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) | |||
105 | } | 105 | } |
106 | 106 | ||
107 | #ifdef CONFIG_XICS | 107 | #ifdef CONFIG_XICS |
108 | static inline void smp_xics_do_message(int cpu, int msg) | ||
109 | { | ||
110 | set_bit(msg, &xics_ipi_message[cpu].value); | ||
111 | mb(); | ||
112 | xics_cause_IPI(cpu); | ||
113 | } | ||
114 | |||
115 | static void smp_xics_message_pass(int target, int msg) | ||
116 | { | ||
117 | unsigned int i; | ||
118 | |||
119 | if (target < NR_CPUS) { | ||
120 | smp_xics_do_message(target, msg); | ||
121 | } else { | ||
122 | for_each_online_cpu(i) { | ||
123 | if (target == MSG_ALL_BUT_SELF | ||
124 | && i == smp_processor_id()) | ||
125 | continue; | ||
126 | smp_xics_do_message(i, msg); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static int __init smp_xics_probe(void) | ||
132 | { | ||
133 | xics_request_IPIs(); | ||
134 | |||
135 | return cpus_weight(cpu_possible_map); | ||
136 | } | ||
137 | |||
138 | static void __devinit smp_xics_setup_cpu(int cpu) | 108 | static void __devinit smp_xics_setup_cpu(int cpu) |
139 | { | 109 | { |
140 | if (cpu != boot_cpuid) | 110 | if (cpu != boot_cpuid) |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 6b1a005cc0cc..e1904774a70f 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -9,32 +9,30 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | |||
13 | #include <linux/types.h> | 12 | #include <linux/types.h> |
14 | #include <linux/threads.h> | 13 | #include <linux/threads.h> |
15 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
16 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
17 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
18 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
19 | #include <linux/signal.h> | ||
20 | #include <linux/init.h> | 18 | #include <linux/init.h> |
21 | #include <linux/gfp.h> | ||
22 | #include <linux/radix-tree.h> | 19 | #include <linux/radix-tree.h> |
23 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
21 | #include <linux/of.h> | ||
24 | 22 | ||
25 | #include <asm/firmware.h> | 23 | #include <asm/firmware.h> |
26 | #include <asm/prom.h> | ||
27 | #include <asm/io.h> | 24 | #include <asm/io.h> |
28 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
29 | #include <asm/smp.h> | 26 | #include <asm/smp.h> |
30 | #include <asm/rtas.h> | 27 | #include <asm/rtas.h> |
31 | #include <asm/hvcall.h> | 28 | #include <asm/hvcall.h> |
32 | #include <asm/machdep.h> | 29 | #include <asm/machdep.h> |
33 | #include <asm/i8259.h> | ||
34 | 30 | ||
35 | #include "xics.h" | 31 | #include "xics.h" |
36 | #include "plpar_wrappers.h" | 32 | #include "plpar_wrappers.h" |
37 | 33 | ||
34 | static struct irq_host *xics_host; | ||
35 | |||
38 | #define XICS_IPI 2 | 36 | #define XICS_IPI 2 |
39 | #define XICS_IRQ_SPURIOUS 0 | 37 | #define XICS_IRQ_SPURIOUS 0 |
40 | 38 | ||
@@ -47,6 +45,20 @@ | |||
47 | */ | 45 | */ |
48 | #define IPI_PRIORITY 4 | 46 | #define IPI_PRIORITY 4 |
49 | 47 | ||
48 | static unsigned int default_server = 0xFF; | ||
49 | static unsigned int default_distrib_server = 0; | ||
50 | static unsigned int interrupt_server_size = 8; | ||
51 | |||
52 | /* RTAS service tokens */ | ||
53 | static int ibm_get_xive; | ||
54 | static int ibm_set_xive; | ||
55 | static int ibm_int_on; | ||
56 | static int ibm_int_off; | ||
57 | |||
58 | |||
59 | /* Direct hardware low level accessors */ | ||
60 | |||
61 | /* The part of the interrupt presentation layer that we care about */ | ||
50 | struct xics_ipl { | 62 | struct xics_ipl { |
51 | union { | 63 | union { |
52 | u32 word; | 64 | u32 word; |
@@ -65,27 +77,6 @@ struct xics_ipl { | |||
65 | 77 | ||
66 | static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; | 78 | static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; |
67 | 79 | ||
68 | static unsigned int default_server = 0xFF; | ||
69 | static unsigned int default_distrib_server = 0; | ||
70 | static unsigned int interrupt_server_size = 8; | ||
71 | |||
72 | static struct irq_host *xics_host; | ||
73 | |||
74 | /* | ||
75 | * XICS only has a single IPI, so encode the messages per CPU | ||
76 | */ | ||
77 | struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | ||
78 | |||
79 | /* RTAS service tokens */ | ||
80 | static int ibm_get_xive; | ||
81 | static int ibm_set_xive; | ||
82 | static int ibm_int_on; | ||
83 | static int ibm_int_off; | ||
84 | |||
85 | |||
86 | /* Direct HW low level accessors */ | ||
87 | |||
88 | |||
89 | static inline unsigned int direct_xirr_info_get(void) | 80 | static inline unsigned int direct_xirr_info_get(void) |
90 | { | 81 | { |
91 | int cpu = smp_processor_id(); | 82 | int cpu = smp_processor_id(); |
@@ -93,7 +84,7 @@ static inline unsigned int direct_xirr_info_get(void) | |||
93 | return in_be32(&xics_per_cpu[cpu]->xirr.word); | 84 | return in_be32(&xics_per_cpu[cpu]->xirr.word); |
94 | } | 85 | } |
95 | 86 | ||
96 | static inline void direct_xirr_info_set(int value) | 87 | static inline void direct_xirr_info_set(unsigned int value) |
97 | { | 88 | { |
98 | int cpu = smp_processor_id(); | 89 | int cpu = smp_processor_id(); |
99 | 90 | ||
@@ -115,7 +106,6 @@ static inline void direct_qirr_info(int n_cpu, u8 value) | |||
115 | 106 | ||
116 | /* LPAR low level accessors */ | 107 | /* LPAR low level accessors */ |
117 | 108 | ||
118 | |||
119 | static inline unsigned int lpar_xirr_info_get(void) | 109 | static inline unsigned int lpar_xirr_info_get(void) |
120 | { | 110 | { |
121 | unsigned long lpar_rc; | 111 | unsigned long lpar_rc; |
@@ -127,15 +117,14 @@ static inline unsigned int lpar_xirr_info_get(void) | |||
127 | return (unsigned int)return_value; | 117 | return (unsigned int)return_value; |
128 | } | 118 | } |
129 | 119 | ||
130 | static inline void lpar_xirr_info_set(int value) | 120 | static inline void lpar_xirr_info_set(unsigned int value) |
131 | { | 121 | { |
132 | unsigned long lpar_rc; | 122 | unsigned long lpar_rc; |
133 | unsigned long val64 = value & 0xffffffff; | ||
134 | 123 | ||
135 | lpar_rc = plpar_eoi(val64); | 124 | lpar_rc = plpar_eoi(value); |
136 | if (lpar_rc != H_SUCCESS) | 125 | if (lpar_rc != H_SUCCESS) |
137 | panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, | 126 | panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc, |
138 | val64); | 127 | value); |
139 | } | 128 | } |
140 | 129 | ||
141 | static inline void lpar_cppr_info(u8 value) | 130 | static inline void lpar_cppr_info(u8 value) |
@@ -157,48 +146,7 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) | |||
157 | } | 146 | } |
158 | 147 | ||
159 | 148 | ||
160 | /* High level handlers and init code */ | 149 | /* Interface to generic irq subsystem */ |
161 | |||
162 | static void xics_update_irq_servers(void) | ||
163 | { | ||
164 | int i, j; | ||
165 | struct device_node *np; | ||
166 | u32 ilen; | ||
167 | const u32 *ireg, *isize; | ||
168 | u32 hcpuid; | ||
169 | |||
170 | /* Find the server numbers for the boot cpu. */ | ||
171 | np = of_get_cpu_node(boot_cpuid, NULL); | ||
172 | BUG_ON(!np); | ||
173 | |||
174 | ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); | ||
175 | if (!ireg) { | ||
176 | of_node_put(np); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | i = ilen / sizeof(int); | ||
181 | hcpuid = get_hard_smp_processor_id(boot_cpuid); | ||
182 | |||
183 | /* Global interrupt distribution server is specified in the last | ||
184 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last | ||
185 | * entry fom this property for current boot cpu id and use it as | ||
186 | * default distribution server | ||
187 | */ | ||
188 | for (j = 0; j < i; j += 2) { | ||
189 | if (ireg[j] == hcpuid) { | ||
190 | default_server = hcpuid; | ||
191 | default_distrib_server = ireg[j+1]; | ||
192 | |||
193 | isize = of_get_property(np, | ||
194 | "ibm,interrupt-server#-size", NULL); | ||
195 | if (isize) | ||
196 | interrupt_server_size = *isize; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | of_node_put(np); | ||
201 | } | ||
202 | 150 | ||
203 | #ifdef CONFIG_SMP | 151 | #ifdef CONFIG_SMP |
204 | static int get_irq_server(unsigned int virq, unsigned int strict_check) | 152 | static int get_irq_server(unsigned int virq, unsigned int strict_check) |
@@ -208,9 +156,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
208 | cpumask_t cpumask = irq_desc[virq].affinity; | 156 | cpumask_t cpumask = irq_desc[virq].affinity; |
209 | cpumask_t tmp = CPU_MASK_NONE; | 157 | cpumask_t tmp = CPU_MASK_NONE; |
210 | 158 | ||
211 | if (! cpu_isset(default_server, cpu_online_map)) | ||
212 | xics_update_irq_servers(); | ||
213 | |||
214 | if (!distribute_irqs) | 159 | if (!distribute_irqs) |
215 | return default_server; | 160 | return default_server; |
216 | 161 | ||
@@ -238,7 +183,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
238 | } | 183 | } |
239 | #endif | 184 | #endif |
240 | 185 | ||
241 | |||
242 | static void xics_unmask_irq(unsigned int virq) | 186 | static void xics_unmask_irq(unsigned int virq) |
243 | { | 187 | { |
244 | unsigned int irq; | 188 | unsigned int irq; |
@@ -257,21 +201,28 @@ static void xics_unmask_irq(unsigned int virq) | |||
257 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, | 201 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, |
258 | DEFAULT_PRIORITY); | 202 | DEFAULT_PRIORITY); |
259 | if (call_status != 0) { | 203 | if (call_status != 0) { |
260 | printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " | 204 | printk(KERN_ERR |
261 | "returned %d\n", irq, call_status); | 205 | "%s: ibm_set_xive irq %u server %x returned %d\n", |
262 | printk("set_xive %x, server %x\n", ibm_set_xive, server); | 206 | __func__, irq, server, call_status); |
263 | return; | 207 | return; |
264 | } | 208 | } |
265 | 209 | ||
266 | /* Now unmask the interrupt (often a no-op) */ | 210 | /* Now unmask the interrupt (often a no-op) */ |
267 | call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); | 211 | call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); |
268 | if (call_status != 0) { | 212 | if (call_status != 0) { |
269 | printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " | 213 | printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", |
270 | "returned %d\n", irq, call_status); | 214 | __func__, irq, call_status); |
271 | return; | 215 | return; |
272 | } | 216 | } |
273 | } | 217 | } |
274 | 218 | ||
219 | static unsigned int xics_startup(unsigned int virq) | ||
220 | { | ||
221 | /* unmask it */ | ||
222 | xics_unmask_irq(virq); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
275 | static void xics_mask_real_irq(unsigned int irq) | 226 | static void xics_mask_real_irq(unsigned int irq) |
276 | { | 227 | { |
277 | int call_status; | 228 | int call_status; |
@@ -281,8 +232,8 @@ static void xics_mask_real_irq(unsigned int irq) | |||
281 | 232 | ||
282 | call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); | 233 | call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); |
283 | if (call_status != 0) { | 234 | if (call_status != 0) { |
284 | printk(KERN_ERR "xics_disable_real_irq: irq=%u: " | 235 | printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", |
285 | "ibm_int_off returned %d\n", irq, call_status); | 236 | __func__, irq, call_status); |
286 | return; | 237 | return; |
287 | } | 238 | } |
288 | 239 | ||
@@ -290,8 +241,8 @@ static void xics_mask_real_irq(unsigned int irq) | |||
290 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, | 241 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, |
291 | default_server, 0xff); | 242 | default_server, 0xff); |
292 | if (call_status != 0) { | 243 | if (call_status != 0) { |
293 | printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" | 244 | printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", |
294 | " returned %d\n", irq, call_status); | 245 | __func__, irq, call_status); |
295 | return; | 246 | return; |
296 | } | 247 | } |
297 | } | 248 | } |
@@ -308,126 +259,77 @@ static void xics_mask_irq(unsigned int virq) | |||
308 | xics_mask_real_irq(irq); | 259 | xics_mask_real_irq(irq); |
309 | } | 260 | } |
310 | 261 | ||
311 | static unsigned int xics_startup(unsigned int virq) | 262 | static void xics_mask_unknown_vec(unsigned int vec) |
312 | { | 263 | { |
313 | /* unmask it */ | 264 | printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); |
314 | xics_unmask_irq(virq); | 265 | xics_mask_real_irq(vec); |
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static void xics_eoi_direct(unsigned int virq) | ||
319 | { | ||
320 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | ||
321 | |||
322 | iosync(); | ||
323 | direct_xirr_info_set((0xff << 24) | irq); | ||
324 | } | 266 | } |
325 | 267 | ||
326 | 268 | static inline unsigned int xics_xirr_vector(unsigned int xirr) | |
327 | static void xics_eoi_lpar(unsigned int virq) | ||
328 | { | 269 | { |
329 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 270 | /* |
330 | 271 | * The top byte is the old cppr, to be restored on EOI. | |
331 | iosync(); | 272 | * The remaining 24 bits are the vector. |
332 | lpar_xirr_info_set((0xff << 24) | irq); | 273 | */ |
274 | return xirr & 0x00ffffff; | ||
333 | } | 275 | } |
334 | 276 | ||
335 | static inline unsigned int xics_remap_irq(unsigned int vec) | 277 | static unsigned int xics_get_irq_direct(void) |
336 | { | 278 | { |
279 | unsigned int xirr = direct_xirr_info_get(); | ||
280 | unsigned int vec = xics_xirr_vector(xirr); | ||
337 | unsigned int irq; | 281 | unsigned int irq; |
338 | 282 | ||
339 | vec &= 0x00ffffff; | ||
340 | |||
341 | if (vec == XICS_IRQ_SPURIOUS) | 283 | if (vec == XICS_IRQ_SPURIOUS) |
342 | return NO_IRQ; | 284 | return NO_IRQ; |
285 | |||
343 | irq = irq_radix_revmap_lookup(xics_host, vec); | 286 | irq = irq_radix_revmap_lookup(xics_host, vec); |
344 | if (likely(irq != NO_IRQ)) | 287 | if (likely(irq != NO_IRQ)) |
345 | return irq; | 288 | return irq; |
346 | 289 | ||
347 | printk(KERN_ERR "Interrupt %u (real) is invalid," | 290 | /* We don't have a linux mapping, so have rtas mask it. */ |
348 | " disabling it.\n", vec); | 291 | xics_mask_unknown_vec(vec); |
349 | xics_mask_real_irq(vec); | ||
350 | return NO_IRQ; | ||
351 | } | ||
352 | 292 | ||
353 | static unsigned int xics_get_irq_direct(void) | 293 | /* We might learn about it later, so EOI it */ |
354 | { | 294 | direct_xirr_info_set(xirr); |
355 | return xics_remap_irq(direct_xirr_info_get()); | 295 | return NO_IRQ; |
356 | } | 296 | } |
357 | 297 | ||
358 | static unsigned int xics_get_irq_lpar(void) | 298 | static unsigned int xics_get_irq_lpar(void) |
359 | { | 299 | { |
360 | return xics_remap_irq(lpar_xirr_info_get()); | 300 | unsigned int xirr = lpar_xirr_info_get(); |
361 | } | 301 | unsigned int vec = xics_xirr_vector(xirr); |
362 | 302 | unsigned int irq; | |
363 | #ifdef CONFIG_SMP | ||
364 | |||
365 | static irqreturn_t xics_ipi_dispatch(int cpu) | ||
366 | { | ||
367 | WARN_ON(cpu_is_offline(cpu)); | ||
368 | 303 | ||
369 | while (xics_ipi_message[cpu].value) { | 304 | if (vec == XICS_IRQ_SPURIOUS) |
370 | if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, | 305 | return NO_IRQ; |
371 | &xics_ipi_message[cpu].value)) { | ||
372 | mb(); | ||
373 | smp_message_recv(PPC_MSG_CALL_FUNCTION); | ||
374 | } | ||
375 | if (test_and_clear_bit(PPC_MSG_RESCHEDULE, | ||
376 | &xics_ipi_message[cpu].value)) { | ||
377 | mb(); | ||
378 | smp_message_recv(PPC_MSG_RESCHEDULE); | ||
379 | } | ||
380 | if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, | ||
381 | &xics_ipi_message[cpu].value)) { | ||
382 | mb(); | ||
383 | smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); | ||
384 | } | ||
385 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | ||
386 | if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, | ||
387 | &xics_ipi_message[cpu].value)) { | ||
388 | mb(); | ||
389 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | ||
390 | } | ||
391 | #endif | ||
392 | } | ||
393 | return IRQ_HANDLED; | ||
394 | } | ||
395 | 306 | ||
396 | static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) | 307 | irq = irq_radix_revmap_lookup(xics_host, vec); |
397 | { | 308 | if (likely(irq != NO_IRQ)) |
398 | int cpu = smp_processor_id(); | 309 | return irq; |
399 | 310 | ||
400 | direct_qirr_info(cpu, 0xff); | 311 | /* We don't have a linux mapping, so have RTAS mask it. */ |
312 | xics_mask_unknown_vec(vec); | ||
401 | 313 | ||
402 | return xics_ipi_dispatch(cpu); | 314 | /* We might learn about it later, so EOI it */ |
315 | lpar_xirr_info_set(xirr); | ||
316 | return NO_IRQ; | ||
403 | } | 317 | } |
404 | 318 | ||
405 | static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) | 319 | static void xics_eoi_direct(unsigned int virq) |
406 | { | 320 | { |
407 | int cpu = smp_processor_id(); | 321 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
408 | |||
409 | lpar_qirr_info(cpu, 0xff); | ||
410 | 322 | ||
411 | return xics_ipi_dispatch(cpu); | 323 | iosync(); |
324 | direct_xirr_info_set((0xff << 24) | irq); | ||
412 | } | 325 | } |
413 | 326 | ||
414 | void xics_cause_IPI(int cpu) | 327 | static void xics_eoi_lpar(unsigned int virq) |
415 | { | 328 | { |
416 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 329 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
417 | lpar_qirr_info(cpu, IPI_PRIORITY); | ||
418 | else | ||
419 | direct_qirr_info(cpu, IPI_PRIORITY); | ||
420 | } | ||
421 | |||
422 | #endif /* CONFIG_SMP */ | ||
423 | 330 | ||
424 | static void xics_set_cpu_priority(unsigned char cppr) | ||
425 | { | ||
426 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
427 | lpar_cppr_info(cppr); | ||
428 | else | ||
429 | direct_cppr_info(cppr); | ||
430 | iosync(); | 331 | iosync(); |
332 | lpar_xirr_info_set((0xff << 24) | irq); | ||
431 | } | 333 | } |
432 | 334 | ||
433 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | 335 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) |
@@ -444,8 +346,8 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
444 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); | 346 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); |
445 | 347 | ||
446 | if (status) { | 348 | if (status) { |
447 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " | 349 | printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", |
448 | "returns %d\n", irq, status); | 350 | __func__, irq, status); |
449 | return; | 351 | return; |
450 | } | 352 | } |
451 | 353 | ||
@@ -457,8 +359,9 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
457 | if (irq_server == -1) { | 359 | if (irq_server == -1) { |
458 | char cpulist[128]; | 360 | char cpulist[128]; |
459 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); | 361 | cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); |
460 | printk(KERN_WARNING "xics_set_affinity: No online cpus in " | 362 | printk(KERN_WARNING |
461 | "the mask %s for irq %d\n", cpulist, virq); | 363 | "%s: No online cpus in the mask %s for irq %d\n", |
364 | __func__, cpulist, virq); | ||
462 | return; | 365 | return; |
463 | } | 366 | } |
464 | 367 | ||
@@ -466,28 +369,12 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
466 | irq, irq_server, xics_status[1]); | 369 | irq, irq_server, xics_status[1]); |
467 | 370 | ||
468 | if (status) { | 371 | if (status) { |
469 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " | 372 | printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", |
470 | "returns %d\n", irq, status); | 373 | __func__, irq, status); |
471 | return; | 374 | return; |
472 | } | 375 | } |
473 | } | 376 | } |
474 | 377 | ||
475 | void xics_setup_cpu(void) | ||
476 | { | ||
477 | xics_set_cpu_priority(0xff); | ||
478 | |||
479 | /* | ||
480 | * Put the calling processor into the GIQ. This is really only | ||
481 | * necessary from a secondary thread as the OF start-cpu interface | ||
482 | * performs this function for us on primary threads. | ||
483 | * | ||
484 | * XXX: undo of teardown on kexec needs this too, as may hotplug | ||
485 | */ | ||
486 | rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | ||
487 | (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); | ||
488 | } | ||
489 | |||
490 | |||
491 | static struct irq_chip xics_pic_direct = { | 378 | static struct irq_chip xics_pic_direct = { |
492 | .typename = " XICS ", | 379 | .typename = " XICS ", |
493 | .startup = xics_startup, | 380 | .startup = xics_startup, |
@@ -497,7 +384,6 @@ static struct irq_chip xics_pic_direct = { | |||
497 | .set_affinity = xics_set_affinity | 384 | .set_affinity = xics_set_affinity |
498 | }; | 385 | }; |
499 | 386 | ||
500 | |||
501 | static struct irq_chip xics_pic_lpar = { | 387 | static struct irq_chip xics_pic_lpar = { |
502 | .typename = " XICS ", | 388 | .typename = " XICS ", |
503 | .startup = xics_startup, | 389 | .startup = xics_startup, |
@@ -507,6 +393,9 @@ static struct irq_chip xics_pic_lpar = { | |||
507 | .set_affinity = xics_set_affinity | 393 | .set_affinity = xics_set_affinity |
508 | }; | 394 | }; |
509 | 395 | ||
396 | |||
397 | /* Interface to arch irq controller subsystem layer */ | ||
398 | |||
510 | /* Points to the irq_chip we're actually using */ | 399 | /* Points to the irq_chip we're actually using */ |
511 | static struct irq_chip *xics_irq_chip; | 400 | static struct irq_chip *xics_irq_chip; |
512 | 401 | ||
@@ -566,10 +455,169 @@ static void __init xics_init_host(void) | |||
566 | irq_set_default_host(xics_host); | 455 | irq_set_default_host(xics_host); |
567 | } | 456 | } |
568 | 457 | ||
458 | |||
459 | /* Inter-processor interrupt support */ | ||
460 | |||
461 | #ifdef CONFIG_SMP | ||
462 | /* | ||
463 | * XICS only has a single IPI, so encode the messages per CPU | ||
464 | */ | ||
465 | struct xics_ipi_struct { | ||
466 | unsigned long value; | ||
467 | } ____cacheline_aligned; | ||
468 | |||
469 | static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | ||
470 | |||
471 | static inline void smp_xics_do_message(int cpu, int msg) | ||
472 | { | ||
473 | set_bit(msg, &xics_ipi_message[cpu].value); | ||
474 | mb(); | ||
475 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
476 | lpar_qirr_info(cpu, IPI_PRIORITY); | ||
477 | else | ||
478 | direct_qirr_info(cpu, IPI_PRIORITY); | ||
479 | } | ||
480 | |||
481 | void smp_xics_message_pass(int target, int msg) | ||
482 | { | ||
483 | unsigned int i; | ||
484 | |||
485 | if (target < NR_CPUS) { | ||
486 | smp_xics_do_message(target, msg); | ||
487 | } else { | ||
488 | for_each_online_cpu(i) { | ||
489 | if (target == MSG_ALL_BUT_SELF | ||
490 | && i == smp_processor_id()) | ||
491 | continue; | ||
492 | smp_xics_do_message(i, msg); | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static irqreturn_t xics_ipi_dispatch(int cpu) | ||
498 | { | ||
499 | WARN_ON(cpu_is_offline(cpu)); | ||
500 | |||
501 | mb(); /* order mmio clearing qirr */ | ||
502 | while (xics_ipi_message[cpu].value) { | ||
503 | if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, | ||
504 | &xics_ipi_message[cpu].value)) { | ||
505 | smp_message_recv(PPC_MSG_CALL_FUNCTION); | ||
506 | } | ||
507 | if (test_and_clear_bit(PPC_MSG_RESCHEDULE, | ||
508 | &xics_ipi_message[cpu].value)) { | ||
509 | smp_message_recv(PPC_MSG_RESCHEDULE); | ||
510 | } | ||
511 | if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, | ||
512 | &xics_ipi_message[cpu].value)) { | ||
513 | smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); | ||
514 | } | ||
515 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | ||
516 | if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, | ||
517 | &xics_ipi_message[cpu].value)) { | ||
518 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | ||
519 | } | ||
520 | #endif | ||
521 | } | ||
522 | return IRQ_HANDLED; | ||
523 | } | ||
524 | |||
525 | static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) | ||
526 | { | ||
527 | int cpu = smp_processor_id(); | ||
528 | |||
529 | direct_qirr_info(cpu, 0xff); | ||
530 | |||
531 | return xics_ipi_dispatch(cpu); | ||
532 | } | ||
533 | |||
534 | static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) | ||
535 | { | ||
536 | int cpu = smp_processor_id(); | ||
537 | |||
538 | lpar_qirr_info(cpu, 0xff); | ||
539 | |||
540 | return xics_ipi_dispatch(cpu); | ||
541 | } | ||
542 | |||
543 | static void xics_request_ipi(void) | ||
544 | { | ||
545 | unsigned int ipi; | ||
546 | int rc; | ||
547 | |||
548 | ipi = irq_create_mapping(xics_host, XICS_IPI); | ||
549 | BUG_ON(ipi == NO_IRQ); | ||
550 | |||
551 | /* | ||
552 | * IPIs are marked IRQF_DISABLED as they must run with irqs | ||
553 | * disabled | ||
554 | */ | ||
555 | set_irq_handler(ipi, handle_percpu_irq); | ||
556 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
557 | rc = request_irq(ipi, xics_ipi_action_lpar, | ||
558 | IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); | ||
559 | else | ||
560 | rc = request_irq(ipi, xics_ipi_action_direct, | ||
561 | IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); | ||
562 | BUG_ON(rc); | ||
563 | } | ||
564 | |||
565 | int __init smp_xics_probe(void) | ||
566 | { | ||
567 | xics_request_ipi(); | ||
568 | |||
569 | return cpus_weight(cpu_possible_map); | ||
570 | } | ||
571 | |||
572 | #endif /* CONFIG_SMP */ | ||
573 | |||
574 | |||
575 | /* Initialization */ | ||
576 | |||
577 | static void xics_update_irq_servers(void) | ||
578 | { | ||
579 | int i, j; | ||
580 | struct device_node *np; | ||
581 | u32 ilen; | ||
582 | const u32 *ireg, *isize; | ||
583 | u32 hcpuid; | ||
584 | |||
585 | /* Find the server numbers for the boot cpu. */ | ||
586 | np = of_get_cpu_node(boot_cpuid, NULL); | ||
587 | BUG_ON(!np); | ||
588 | |||
589 | ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); | ||
590 | if (!ireg) { | ||
591 | of_node_put(np); | ||
592 | return; | ||
593 | } | ||
594 | |||
595 | i = ilen / sizeof(int); | ||
596 | hcpuid = get_hard_smp_processor_id(boot_cpuid); | ||
597 | |||
598 | /* Global interrupt distribution server is specified in the last | ||
599 | * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last | ||
600 | * entry fom this property for current boot cpu id and use it as | ||
601 | * default distribution server | ||
602 | */ | ||
603 | for (j = 0; j < i; j += 2) { | ||
604 | if (ireg[j] == hcpuid) { | ||
605 | default_server = hcpuid; | ||
606 | default_distrib_server = ireg[j+1]; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | /* get the bit size of server numbers */ | ||
611 | isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); | ||
612 | if (isize) | ||
613 | interrupt_server_size = *isize; | ||
614 | |||
615 | of_node_put(np); | ||
616 | } | ||
617 | |||
569 | static void __init xics_map_one_cpu(int hw_id, unsigned long addr, | 618 | static void __init xics_map_one_cpu(int hw_id, unsigned long addr, |
570 | unsigned long size) | 619 | unsigned long size) |
571 | { | 620 | { |
572 | #ifdef CONFIG_SMP | ||
573 | int i; | 621 | int i; |
574 | 622 | ||
575 | /* This may look gross but it's good enough for now, we don't quite | 623 | /* This may look gross but it's good enough for now, we don't quite |
@@ -583,11 +631,6 @@ static void __init xics_map_one_cpu(int hw_id, unsigned long addr, | |||
583 | return; | 631 | return; |
584 | } | 632 | } |
585 | } | 633 | } |
586 | #else | ||
587 | if (hw_id != 0) | ||
588 | return; | ||
589 | xics_per_cpu[0] = ioremap(addr, size); | ||
590 | #endif /* CONFIG_SMP */ | ||
591 | } | 634 | } |
592 | 635 | ||
593 | static void __init xics_init_one_node(struct device_node *np, | 636 | static void __init xics_init_one_node(struct device_node *np, |
@@ -649,15 +692,17 @@ void __init xics_init_IRQ(void) | |||
649 | 692 | ||
650 | for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") { | 693 | for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") { |
651 | found = 1; | 694 | found = 1; |
652 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 695 | if (firmware_has_feature(FW_FEATURE_LPAR)) { |
696 | of_node_put(np); | ||
653 | break; | 697 | break; |
698 | } | ||
654 | xics_init_one_node(np, &indx); | 699 | xics_init_one_node(np, &indx); |
655 | } | 700 | } |
656 | if (found == 0) | 701 | if (found == 0) |
657 | return; | 702 | return; |
658 | 703 | ||
659 | xics_init_host(); | ||
660 | xics_update_irq_servers(); | 704 | xics_update_irq_servers(); |
705 | xics_init_host(); | ||
661 | 706 | ||
662 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 707 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
663 | ppc_md.get_irq = xics_get_irq_lpar; | 708 | ppc_md.get_irq = xics_get_irq_lpar; |
@@ -669,30 +714,31 @@ void __init xics_init_IRQ(void) | |||
669 | ppc64_boot_msg(0x21, "XICS Done"); | 714 | ppc64_boot_msg(0x21, "XICS Done"); |
670 | } | 715 | } |
671 | 716 | ||
717 | /* Cpu startup, shutdown, and hotplug */ | ||
672 | 718 | ||
673 | #ifdef CONFIG_SMP | 719 | static void xics_set_cpu_priority(unsigned char cppr) |
674 | void xics_request_IPIs(void) | ||
675 | { | 720 | { |
676 | unsigned int ipi; | ||
677 | int rc; | ||
678 | |||
679 | ipi = irq_create_mapping(xics_host, XICS_IPI); | ||
680 | BUG_ON(ipi == NO_IRQ); | ||
681 | |||
682 | /* | ||
683 | * IPIs are marked IRQF_DISABLED as they must run with irqs | ||
684 | * disabled | ||
685 | */ | ||
686 | set_irq_handler(ipi, handle_percpu_irq); | ||
687 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 721 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
688 | rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, | 722 | lpar_cppr_info(cppr); |
689 | "IPI", NULL); | ||
690 | else | 723 | else |
691 | rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, | 724 | direct_cppr_info(cppr); |
692 | "IPI", NULL); | 725 | iosync(); |
693 | BUG_ON(rc); | 726 | } |
727 | |||
728 | /* Have the calling processor join or leave the specified global queue */ | ||
729 | static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) | ||
730 | { | ||
731 | int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | ||
732 | (1UL << interrupt_server_size) - 1 - gserver, join); | ||
733 | WARN_ON(status < 0); | ||
734 | } | ||
735 | |||
736 | void xics_setup_cpu(void) | ||
737 | { | ||
738 | xics_set_cpu_priority(0xff); | ||
739 | |||
740 | xics_set_cpu_giq(default_distrib_server, 1); | ||
694 | } | 741 | } |
695 | #endif /* CONFIG_SMP */ | ||
696 | 742 | ||
697 | void xics_teardown_cpu(void) | 743 | void xics_teardown_cpu(void) |
698 | { | 744 | { |
@@ -700,9 +746,7 @@ void xics_teardown_cpu(void) | |||
700 | 746 | ||
701 | xics_set_cpu_priority(0); | 747 | xics_set_cpu_priority(0); |
702 | 748 | ||
703 | /* | 749 | /* Clear any pending IPI request */ |
704 | * Clear IPI | ||
705 | */ | ||
706 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 750 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
707 | lpar_qirr_info(cpu, 0xff); | 751 | lpar_qirr_info(cpu, 0xff); |
708 | else | 752 | else |
@@ -711,34 +755,28 @@ void xics_teardown_cpu(void) | |||
711 | 755 | ||
712 | void xics_kexec_teardown_cpu(int secondary) | 756 | void xics_kexec_teardown_cpu(int secondary) |
713 | { | 757 | { |
714 | unsigned int ipi; | ||
715 | struct irq_desc *desc; | ||
716 | |||
717 | xics_teardown_cpu(); | 758 | xics_teardown_cpu(); |
718 | 759 | ||
719 | /* | 760 | /* |
720 | * we need to EOI the IPI | 761 | * we take the ipi irq but and never return so we |
762 | * need to EOI the IPI, but want to leave our priority 0 | ||
721 | * | 763 | * |
722 | * probably need to check all the other interrupts too | 764 | * should we check all the other interrupts too? |
723 | * should we be flagging idle loop instead? | 765 | * should we be flagging idle loop instead? |
724 | * or creating some task to be scheduled? | 766 | * or creating some task to be scheduled? |
725 | */ | 767 | */ |
726 | 768 | ||
727 | ipi = irq_find_mapping(xics_host, XICS_IPI); | 769 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
728 | if (ipi == XICS_IRQ_SPURIOUS) | 770 | lpar_xirr_info_set((0x00 << 24) | XICS_IPI); |
729 | return; | 771 | else |
730 | desc = get_irq_desc(ipi); | 772 | direct_xirr_info_set((0x00 << 24) | XICS_IPI); |
731 | if (desc->chip && desc->chip->eoi) | ||
732 | desc->chip->eoi(ipi); | ||
733 | 773 | ||
734 | /* | 774 | /* |
735 | * Some machines need to have at least one cpu in the GIQ, | 775 | * Some machines need to have at least one cpu in the GIQ, |
736 | * so leave the master cpu in the group. | 776 | * so leave the master cpu in the group. |
737 | */ | 777 | */ |
738 | if (secondary) | 778 | if (secondary) |
739 | rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | 779 | xics_set_cpu_giq(default_distrib_server, 0); |
740 | (1UL << interrupt_server_size) - 1 - | ||
741 | default_distrib_server, 0); | ||
742 | } | 780 | } |
743 | 781 | ||
744 | #ifdef CONFIG_HOTPLUG_CPU | 782 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -746,17 +784,18 @@ void xics_kexec_teardown_cpu(int secondary) | |||
746 | /* Interrupts are disabled. */ | 784 | /* Interrupts are disabled. */ |
747 | void xics_migrate_irqs_away(void) | 785 | void xics_migrate_irqs_away(void) |
748 | { | 786 | { |
749 | int status; | ||
750 | int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); | 787 | int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); |
751 | unsigned int irq, virq; | 788 | unsigned int irq, virq; |
752 | 789 | ||
790 | /* If we used to be the default server, move to the new "boot_cpuid" */ | ||
791 | if (hw_cpu == default_server) | ||
792 | xics_update_irq_servers(); | ||
793 | |||
753 | /* Reject any interrupt that was queued to us... */ | 794 | /* Reject any interrupt that was queued to us... */ |
754 | xics_set_cpu_priority(0); | 795 | xics_set_cpu_priority(0); |
755 | 796 | ||
756 | /* remove ourselves from the global interrupt queue */ | 797 | /* Remove ourselves from the global interrupt queue */ |
757 | status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | 798 | xics_set_cpu_giq(default_distrib_server, 0); |
758 | (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); | ||
759 | WARN_ON(status < 0); | ||
760 | 799 | ||
761 | /* Allow IPIs again... */ | 800 | /* Allow IPIs again... */ |
762 | xics_set_cpu_priority(DEFAULT_PRIORITY); | 801 | xics_set_cpu_priority(DEFAULT_PRIORITY); |
@@ -764,6 +803,7 @@ void xics_migrate_irqs_away(void) | |||
764 | for_each_irq(virq) { | 803 | for_each_irq(virq) { |
765 | struct irq_desc *desc; | 804 | struct irq_desc *desc; |
766 | int xics_status[2]; | 805 | int xics_status[2]; |
806 | int status; | ||
767 | unsigned long flags; | 807 | unsigned long flags; |
768 | 808 | ||
769 | /* We cant set affinity on ISA interrupts */ | 809 | /* We cant set affinity on ISA interrupts */ |
@@ -787,9 +827,8 @@ void xics_migrate_irqs_away(void) | |||
787 | 827 | ||
788 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); | 828 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); |
789 | if (status) { | 829 | if (status) { |
790 | printk(KERN_ERR "migrate_irqs_away: irq=%u " | 830 | printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", |
791 | "ibm,get-xive returns %d\n", | 831 | __func__, irq, status); |
792 | virq, status); | ||
793 | goto unlock; | 832 | goto unlock; |
794 | } | 833 | } |
795 | 834 | ||
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index 1c5321ae8f2f..d1d5a83039ae 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h | |||
@@ -12,20 +12,12 @@ | |||
12 | #ifndef _POWERPC_KERNEL_XICS_H | 12 | #ifndef _POWERPC_KERNEL_XICS_H |
13 | #define _POWERPC_KERNEL_XICS_H | 13 | #define _POWERPC_KERNEL_XICS_H |
14 | 14 | ||
15 | #include <linux/cache.h> | ||
16 | |||
17 | extern void xics_init_IRQ(void); | 15 | extern void xics_init_IRQ(void); |
18 | extern void xics_setup_cpu(void); | 16 | extern void xics_setup_cpu(void); |
19 | extern void xics_teardown_cpu(void); | 17 | extern void xics_teardown_cpu(void); |
20 | extern void xics_kexec_teardown_cpu(int secondary); | 18 | extern void xics_kexec_teardown_cpu(int secondary); |
21 | extern void xics_cause_IPI(int cpu); | ||
22 | extern void xics_request_IPIs(void); | ||
23 | extern void xics_migrate_irqs_away(void); | 19 | extern void xics_migrate_irqs_away(void); |
24 | 20 | extern int smp_xics_probe(void); | |
25 | struct xics_ipi_struct { | 21 | extern void smp_xics_message_pass(int target, int msg); |
26 | volatile unsigned long value; | ||
27 | } ____cacheline_aligned; | ||
28 | |||
29 | extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | ||
30 | 22 | ||
31 | #endif /* _POWERPC_KERNEL_XICS_H */ | 23 | #endif /* _POWERPC_KERNEL_XICS_H */ |
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 55618ba9eff0..a44709a94f97 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -38,15 +38,12 @@ ifeq ($(CONFIG_PCI),y) | |||
38 | obj-$(CONFIG_4xx) += ppc4xx_pci.o | 38 | obj-$(CONFIG_4xx) += ppc4xx_pci.o |
39 | endif | 39 | endif |
40 | 40 | ||
41 | # Temporary hack until we have migrated to asm-powerpc | ||
42 | ifeq ($(ARCH),powerpc) | ||
43 | obj-$(CONFIG_CPM) += cpm_common.o | 41 | obj-$(CONFIG_CPM) += cpm_common.o |
44 | obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o | 42 | obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o |
45 | obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o | 43 | obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o |
46 | obj-$(CONFIG_PPC_DCR) += dcr.o | 44 | obj-$(CONFIG_PPC_DCR) += dcr.o |
47 | obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o | 45 | obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o |
48 | obj-$(CONFIG_UCODE_PATCH) += micropatch.o | 46 | obj-$(CONFIG_UCODE_PATCH) += micropatch.o |
49 | endif | ||
50 | 47 | ||
51 | ifeq ($(CONFIG_SUSPEND),y) | 48 | ifeq ($(CONFIG_SUSPEND),y) |
52 | obj-$(CONFIG_6xx) += 6xx-suspend.o | 49 | obj-$(CONFIG_6xx) += 6xx-suspend.o |
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 408da30594c4..1f18ad9e4fe1 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c | |||
@@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev, | |||
52 | 52 | ||
53 | ret = of_irq_to_resource(dn, 0, &irq_res); | 53 | ret = of_irq_to_resource(dn, 0, &irq_res); |
54 | if (ret == NO_IRQ) | 54 | if (ret == NO_IRQ) |
55 | irq_res.start = irq_res.end = -1; | 55 | irq_res.start = irq_res.end = 0; |
56 | else | 56 | else |
57 | irq_res.flags = 0; | 57 | irq_res.flags = 0; |
58 | 58 | ||
diff --git a/drivers/of/base.c b/drivers/of/base.c index a7264644003f..7c79e94a35ea 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -420,13 +420,12 @@ static struct of_modalias_table of_modalias_table[] = { | |||
420 | * @len: Length of modalias value | 420 | * @len: Length of modalias value |
421 | * | 421 | * |
422 | * Based on the value of the compatible property, this routine will determine | 422 | * Based on the value of the compatible property, this routine will determine |
423 | * an appropriate modalias value for a particular device tree node. Three | 423 | * an appropriate modalias value for a particular device tree node. Two |
424 | * separate methods are used to derive a modalias value. | 424 | * separate methods are attempted to derive a modalias value. |
425 | * | 425 | * |
426 | * First method is to lookup the compatible value in of_modalias_table. | 426 | * First method is to lookup the compatible value in of_modalias_table. |
427 | * Second is to look for a "linux,<modalias>" entry in the compatible list | 427 | * Second is to strip off the manufacturer prefix from the first |
428 | * and used that for modalias. Third is to strip off the manufacturer | 428 | * compatible entry and use the remainder as modalias |
429 | * prefix from the first compatible entry and use the remainder as modalias | ||
430 | * | 429 | * |
431 | * This routine returns 0 on success | 430 | * This routine returns 0 on success |
432 | */ | 431 | */ |
@@ -449,21 +448,7 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) | |||
449 | if (!compatible) | 448 | if (!compatible) |
450 | return -ENODEV; | 449 | return -ENODEV; |
451 | 450 | ||
452 | /* 2. search for linux,<modalias> entry */ | 451 | /* 2. take first compatible entry and strip manufacturer */ |
453 | p = compatible; | ||
454 | while (cplen > 0) { | ||
455 | if (!strncmp(p, "linux,", 6)) { | ||
456 | p += 6; | ||
457 | strlcpy(modalias, p, len); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | i = strlen(p) + 1; | ||
462 | p += i; | ||
463 | cplen -= i; | ||
464 | } | ||
465 | |||
466 | /* 3. take first compatible entry and strip manufacturer */ | ||
467 | p = strchr(compatible, ','); | 452 | p = strchr(compatible, ','); |
468 | if (!p) | 453 | if (!p) |
469 | return -ENODEV; | 454 | return -ENODEV; |
@@ -473,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) | |||
473 | } | 458 | } |
474 | EXPORT_SYMBOL_GPL(of_modalias_node); | 459 | EXPORT_SYMBOL_GPL(of_modalias_node); |
475 | 460 | ||
461 | /** | ||
462 | * of_parse_phandles_with_args - Find a node pointed by phandle in a list | ||
463 | * @np: pointer to a device tree node containing a list | ||
464 | * @list_name: property name that contains a list | ||
465 | * @cells_name: property name that specifies phandles' arguments count | ||
466 | * @index: index of a phandle to parse out | ||
467 | * @out_node: pointer to device_node struct pointer (will be filled) | ||
468 | * @out_args: pointer to arguments pointer (will be filled) | ||
469 | * | ||
470 | * This function is useful to parse lists of phandles and their arguments. | ||
471 | * Returns 0 on success and fills out_node and out_args, on error returns | ||
472 | * appropriate errno value. | ||
473 | * | ||
474 | * Example: | ||
475 | * | ||
476 | * phandle1: node1 { | ||
477 | * #list-cells = <2>; | ||
478 | * } | ||
479 | * | ||
480 | * phandle2: node2 { | ||
481 | * #list-cells = <1>; | ||
482 | * } | ||
483 | * | ||
484 | * node3 { | ||
485 | * list = <&phandle1 1 2 &phandle2 3>; | ||
486 | * } | ||
487 | * | ||
488 | * To get a device_node of the `node2' node you may call this: | ||
489 | * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); | ||
490 | */ | ||
491 | int of_parse_phandles_with_args(struct device_node *np, const char *list_name, | ||
492 | const char *cells_name, int index, | ||
493 | struct device_node **out_node, | ||
494 | const void **out_args) | ||
495 | { | ||
496 | int ret = -EINVAL; | ||
497 | const u32 *list; | ||
498 | const u32 *list_end; | ||
499 | int size; | ||
500 | int cur_index = 0; | ||
501 | struct device_node *node = NULL; | ||
502 | const void *args; | ||
503 | |||
504 | list = of_get_property(np, list_name, &size); | ||
505 | if (!list) { | ||
506 | ret = -ENOENT; | ||
507 | goto err0; | ||
508 | } | ||
509 | list_end = list + size / sizeof(*list); | ||
510 | |||
511 | while (list < list_end) { | ||
512 | const u32 *cells; | ||
513 | const phandle *phandle; | ||
514 | |||
515 | phandle = list; | ||
516 | args = list + 1; | ||
517 | |||
518 | /* one cell hole in the list = <>; */ | ||
519 | if (!*phandle) { | ||
520 | list++; | ||
521 | goto next; | ||
522 | } | ||
523 | |||
524 | node = of_find_node_by_phandle(*phandle); | ||
525 | if (!node) { | ||
526 | pr_debug("%s: could not find phandle\n", | ||
527 | np->full_name); | ||
528 | goto err0; | ||
529 | } | ||
530 | |||
531 | cells = of_get_property(node, cells_name, &size); | ||
532 | if (!cells || size != sizeof(*cells)) { | ||
533 | pr_debug("%s: could not get %s for %s\n", | ||
534 | np->full_name, cells_name, node->full_name); | ||
535 | goto err1; | ||
536 | } | ||
537 | |||
538 | /* Next phandle is at offset of one phandle cell + #cells */ | ||
539 | list += 1 + *cells; | ||
540 | if (list > list_end) { | ||
541 | pr_debug("%s: insufficient arguments length\n", | ||
542 | np->full_name); | ||
543 | goto err1; | ||
544 | } | ||
545 | next: | ||
546 | if (cur_index == index) | ||
547 | break; | ||
548 | |||
549 | of_node_put(node); | ||
550 | node = NULL; | ||
551 | cur_index++; | ||
552 | } | ||
553 | |||
554 | if (!node) { | ||
555 | ret = -ENOENT; | ||
556 | goto err0; | ||
557 | } | ||
558 | |||
559 | *out_node = node; | ||
560 | *out_args = args; | ||
561 | |||
562 | return 0; | ||
563 | err1: | ||
564 | of_node_put(node); | ||
565 | err0: | ||
566 | pr_debug("%s failed with status %d\n", __func__, ret); | ||
567 | return ret; | ||
568 | } | ||
569 | EXPORT_SYMBOL(of_parse_phandles_with_args); | ||
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 1c9cab844f10..7cd7301b5839 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c | |||
@@ -28,78 +28,35 @@ | |||
28 | */ | 28 | */ |
29 | int of_get_gpio(struct device_node *np, int index) | 29 | int of_get_gpio(struct device_node *np, int index) |
30 | { | 30 | { |
31 | int ret = -EINVAL; | 31 | int ret; |
32 | struct device_node *gc; | 32 | struct device_node *gc; |
33 | struct of_gpio_chip *of_gc = NULL; | 33 | struct of_gpio_chip *of_gc = NULL; |
34 | int size; | 34 | int size; |
35 | const u32 *gpios; | ||
36 | u32 nr_cells; | ||
37 | int i; | ||
38 | const void *gpio_spec; | 35 | const void *gpio_spec; |
39 | const u32 *gpio_cells; | 36 | const u32 *gpio_cells; |
40 | int gpio_index = 0; | ||
41 | 37 | ||
42 | gpios = of_get_property(np, "gpios", &size); | 38 | ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, |
43 | if (!gpios) { | 39 | &gc, &gpio_spec); |
44 | ret = -ENOENT; | 40 | if (ret) { |
41 | pr_debug("%s: can't parse gpios property\n", __func__); | ||
45 | goto err0; | 42 | goto err0; |
46 | } | 43 | } |
47 | nr_cells = size / sizeof(u32); | ||
48 | |||
49 | for (i = 0; i < nr_cells; gpio_index++) { | ||
50 | const phandle *gpio_phandle; | ||
51 | |||
52 | gpio_phandle = gpios + i; | ||
53 | gpio_spec = gpio_phandle + 1; | ||
54 | |||
55 | /* one cell hole in the gpios = <>; */ | ||
56 | if (!*gpio_phandle) { | ||
57 | if (gpio_index == index) | ||
58 | return -ENOENT; | ||
59 | i++; | ||
60 | continue; | ||
61 | } | ||
62 | |||
63 | gc = of_find_node_by_phandle(*gpio_phandle); | ||
64 | if (!gc) { | ||
65 | pr_debug("%s: could not find phandle for gpios\n", | ||
66 | np->full_name); | ||
67 | goto err0; | ||
68 | } | ||
69 | |||
70 | of_gc = gc->data; | ||
71 | if (!of_gc) { | ||
72 | pr_debug("%s: gpio controller %s isn't registered\n", | ||
73 | np->full_name, gc->full_name); | ||
74 | goto err1; | ||
75 | } | ||
76 | |||
77 | gpio_cells = of_get_property(gc, "#gpio-cells", &size); | ||
78 | if (!gpio_cells || size != sizeof(*gpio_cells) || | ||
79 | *gpio_cells != of_gc->gpio_cells) { | ||
80 | pr_debug("%s: wrong #gpio-cells for %s\n", | ||
81 | np->full_name, gc->full_name); | ||
82 | goto err1; | ||
83 | } | ||
84 | |||
85 | /* Next phandle is at phandle cells + #gpio-cells */ | ||
86 | i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells; | ||
87 | if (i >= nr_cells + 1) { | ||
88 | pr_debug("%s: insufficient gpio-spec length\n", | ||
89 | np->full_name); | ||
90 | goto err1; | ||
91 | } | ||
92 | |||
93 | if (gpio_index == index) | ||
94 | break; | ||
95 | |||
96 | of_gc = NULL; | ||
97 | of_node_put(gc); | ||
98 | } | ||
99 | 44 | ||
45 | of_gc = gc->data; | ||
100 | if (!of_gc) { | 46 | if (!of_gc) { |
101 | ret = -ENOENT; | 47 | pr_debug("%s: gpio controller %s isn't registered\n", |
102 | goto err0; | 48 | np->full_name, gc->full_name); |
49 | ret = -ENODEV; | ||
50 | goto err1; | ||
51 | } | ||
52 | |||
53 | gpio_cells = of_get_property(gc, "#gpio-cells", &size); | ||
54 | if (!gpio_cells || size != sizeof(*gpio_cells) || | ||
55 | *gpio_cells != of_gc->gpio_cells) { | ||
56 | pr_debug("%s: wrong #gpio-cells for %s\n", | ||
57 | np->full_name, gc->full_name); | ||
58 | ret = -EINVAL; | ||
59 | goto err1; | ||
103 | } | 60 | } |
104 | 61 | ||
105 | ret = of_gc->xlate(of_gc, np, gpio_spec); | 62 | ret = of_gc->xlate(of_gc, np, gpio_spec); |
diff --git a/include/linux/of.h b/include/linux/of.h index 79886ade070f..e2488f5e7cb2 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -71,5 +71,8 @@ extern int of_n_size_cells(struct device_node *np); | |||
71 | extern const struct of_device_id *of_match_node( | 71 | extern const struct of_device_id *of_match_node( |
72 | const struct of_device_id *matches, const struct device_node *node); | 72 | const struct of_device_id *matches, const struct device_node *node); |
73 | extern int of_modalias_node(struct device_node *node, char *modalias, int len); | 73 | extern int of_modalias_node(struct device_node *node, char *modalias, int len); |
74 | extern int of_parse_phandles_with_args(struct device_node *np, | ||
75 | const char *list_name, const char *cells_name, int index, | ||
76 | struct device_node **out_node, const void **out_args); | ||
74 | 77 | ||
75 | #endif /* _LINUX_OF_H */ | 78 | #endif /* _LINUX_OF_H */ |