aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/boot/addnote.c144
-rwxr-xr-xarch/powerpc/boot/wrapper4
-rw-r--r--arch/powerpc/include/asm/smp.h3
-rw-r--r--arch/powerpc/kernel/misc_32.S8
-rw-r--r--arch/powerpc/kernel/misc_64.S8
-rw-r--r--arch/powerpc/kernel/prom_init.c10
-rw-r--r--arch/powerpc/kernel/smp.c3
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S3
-rw-r--r--arch/powerpc/mm/numa.c108
-rw-r--r--arch/powerpc/oprofile/cell/vma_map.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c11
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c2
-rw-r--r--arch/powerpc/platforms/pseries/smp.c32
-rw-r--r--arch/powerpc/platforms/pseries/xics.c539
-rw-r--r--arch/powerpc/platforms/pseries/xics.h12
-rw-r--r--arch/powerpc/sysdev/Makefile3
-rw-r--r--drivers/ata/pata_of_platform.c2
-rw-r--r--drivers/of/base.c134
-rw-r--r--drivers/of/gpio.c81
-rw-r--r--include/linux/of.h3
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
45unsigned int rpanote[N_RPA_DESCR] = { 50unsigned 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
58unsigned char buf[512]; 63unsigned char buf[512];
64unsigned 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
89unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; 96unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
90 97
98unsigned 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(&notebuf[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 *)&notebuf[note + 12], rpaname) != 0)
140 continue;
141 /* looks like an RPA note, return it */
142 *nnp = notesize;
143 return &notebuf[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
91int 153int
92main(int ac, char **av) 154main(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
308case "$platform" in 308case "$platform" in
309pseries|chrp) 309pseries|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 ;;
312coff) 314coff)
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
123static inline void set_hard_smp_processor_id(int cpu, int phys) 123static 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 */
9051: 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
9141: lwz r30,8(r1) 9162: 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 */
4311: 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
4411: addi r1,r1,STACK_FRAME_OVERHEAD 4432: 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 */
102static 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 */
122static 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
92static void __cpuinit map_cpu_to_node(int cpu, int node) 132static 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
919void __init paging_init(void) 971void __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
305out_free_ctx: 305out_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
545out_iput: 547out_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
108static 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
115static 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
131static int __init smp_xics_probe(void)
132{
133 xics_request_IPIs();
134
135 return cpus_weight(cpu_possible_map);
136}
137
138static void __devinit smp_xics_setup_cpu(int cpu) 108static 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
34static 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
48static unsigned int default_server = 0xFF;
49static unsigned int default_distrib_server = 0;
50static unsigned int interrupt_server_size = 8;
51
52/* RTAS service tokens */
53static int ibm_get_xive;
54static int ibm_set_xive;
55static int ibm_int_on;
56static 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 */
50struct xics_ipl { 62struct xics_ipl {
51 union { 63 union {
52 u32 word; 64 u32 word;
@@ -65,27 +77,6 @@ struct xics_ipl {
65 77
66static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; 78static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
67 79
68static unsigned int default_server = 0xFF;
69static unsigned int default_distrib_server = 0;
70static unsigned int interrupt_server_size = 8;
71
72static struct irq_host *xics_host;
73
74/*
75 * XICS only has a single IPI, so encode the messages per CPU
76 */
77struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
78
79/* RTAS service tokens */
80static int ibm_get_xive;
81static int ibm_set_xive;
82static int ibm_int_on;
83static int ibm_int_off;
84
85
86/* Direct HW low level accessors */
87
88
89static inline unsigned int direct_xirr_info_get(void) 80static 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
96static inline void direct_xirr_info_set(int value) 87static 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
119static inline unsigned int lpar_xirr_info_get(void) 109static 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
130static inline void lpar_xirr_info_set(int value) 120static 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
141static inline void lpar_cppr_info(u8 value) 130static 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
162static 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
204static int get_irq_server(unsigned int virq, unsigned int strict_check) 152static 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
242static void xics_unmask_irq(unsigned int virq) 186static 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
219static unsigned int xics_startup(unsigned int virq)
220{
221 /* unmask it */
222 xics_unmask_irq(virq);
223 return 0;
224}
225
275static void xics_mask_real_irq(unsigned int irq) 226static 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
311static unsigned int xics_startup(unsigned int virq) 262static 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
318static 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 268static inline unsigned int xics_xirr_vector(unsigned int xirr)
327static 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
335static inline unsigned int xics_remap_irq(unsigned int vec) 277static 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
353static 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
358static unsigned int xics_get_irq_lpar(void) 298static 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
365static 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
396static 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
405static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) 319static 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
414void xics_cause_IPI(int cpu) 327static 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
424static 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
433static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) 335static 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
475void 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
491static struct irq_chip xics_pic_direct = { 378static 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
501static struct irq_chip xics_pic_lpar = { 387static 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 */
511static struct irq_chip *xics_irq_chip; 400static 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 */
465struct xics_ipi_struct {
466 unsigned long value;
467 } ____cacheline_aligned;
468
469static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
470
471static 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
481void 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
497static 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
525static 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
534static 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
543static 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
565int __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
577static 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
569static void __init xics_map_one_cpu(int hw_id, unsigned long addr, 618static 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
593static void __init xics_init_one_node(struct device_node *np, 636static 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 719static void xics_set_cpu_priority(unsigned char cppr)
674void 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 */
729static 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
736void 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
697void xics_teardown_cpu(void) 743void 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
712void xics_kexec_teardown_cpu(int secondary) 756void 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. */
747void xics_migrate_irqs_away(void) 785void 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
17extern void xics_init_IRQ(void); 15extern void xics_init_IRQ(void);
18extern void xics_setup_cpu(void); 16extern void xics_setup_cpu(void);
19extern void xics_teardown_cpu(void); 17extern void xics_teardown_cpu(void);
20extern void xics_kexec_teardown_cpu(int secondary); 18extern void xics_kexec_teardown_cpu(int secondary);
21extern void xics_cause_IPI(int cpu);
22extern void xics_request_IPIs(void);
23extern void xics_migrate_irqs_away(void); 19extern void xics_migrate_irqs_away(void);
24 20extern int smp_xics_probe(void);
25struct xics_ipi_struct { 21extern void smp_xics_message_pass(int target, int msg);
26 volatile unsigned long value;
27} ____cacheline_aligned;
28
29extern 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)
38obj-$(CONFIG_4xx) += ppc4xx_pci.o 38obj-$(CONFIG_4xx) += ppc4xx_pci.o
39endif 39endif
40 40
41# Temporary hack until we have migrated to asm-powerpc
42ifeq ($(ARCH),powerpc)
43obj-$(CONFIG_CPM) += cpm_common.o 41obj-$(CONFIG_CPM) += cpm_common.o
44obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o 42obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o
45obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o 43obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o
46obj-$(CONFIG_PPC_DCR) += dcr.o 44obj-$(CONFIG_PPC_DCR) += dcr.o
47obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o 45obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o
48obj-$(CONFIG_UCODE_PATCH) += micropatch.o 46obj-$(CONFIG_UCODE_PATCH) += micropatch.o
49endif
50 47
51ifeq ($(CONFIG_SUSPEND),y) 48ifeq ($(CONFIG_SUSPEND),y)
52obj-$(CONFIG_6xx) += 6xx-suspend.o 49obj-$(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}
474EXPORT_SYMBOL_GPL(of_modalias_node); 459EXPORT_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 */
491int 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 }
545next:
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;
563err1:
564 of_node_put(node);
565err0:
566 pr_debug("%s failed with status %d\n", __func__, ret);
567 return ret;
568}
569EXPORT_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 */
29int of_get_gpio(struct device_node *np, int index) 29int 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);
71extern const struct of_device_id *of_match_node( 71extern 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);
73extern int of_modalias_node(struct device_node *node, char *modalias, int len); 73extern int of_modalias_node(struct device_node *node, char *modalias, int len);
74extern 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 */