diff --git a/[refs] b/[refs] index b629f8c74373..52359b968d40 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 22d660ffd0db8d136b122751287d186e869ca474 +refs/heads/master: a897ea13f7a801e6baba8d4985f459042712244c diff --git a/trunk/arch/powerpc/boot/addnote.c b/trunk/arch/powerpc/boot/addnote.c index dcc9ab2ca823..b1e5611b2ab1 100644 --- a/trunk/arch/powerpc/boot/addnote.c +++ b/trunk/arch/powerpc/boot/addnote.c @@ -11,12 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Usage: addnote zImage [note.elf] - * - * If note.elf is supplied, it is the name of an ELF file that contains - * an RPA note to use instead of the built-in one. Alternatively, the - * note.elf file may be empty, in which case the built-in RPA note is - * used (this is to simplify how this is invoked from the wrapper script). + * Usage: addnote zImage */ #include #include @@ -48,29 +43,27 @@ char rpaname[] = "IBM,RPA-Client-Config"; */ #define N_RPA_DESCR 8 unsigned int rpanote[N_RPA_DESCR] = { - 1, /* lparaffinity */ - 128, /* min_rmo_size */ + 0, /* lparaffinity */ + 64, /* min_rmo_size */ 0, /* min_rmo_percent */ - 46, /* max_pft_size */ + 40, /* max_pft_size */ 1, /* splpar */ -1, /* min_load */ - 1, /* new_mem_def */ - 0, /* ignore_my_client_config */ + 0, /* new_mem_def */ + 1, /* ignore_my_client_config */ }; #define ROUNDUP(len) (((len) + 3) & ~3) unsigned char buf[512]; -unsigned char notebuf[512]; -#define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1])) -#define GET_32BE(b, off) ((GET_16BE((b), (off)) << 16) + \ - GET_16BE((b), (off)+2)) +#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) +#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) -#define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \ - (b)[(off) + 1] = (v) & 0xff) -#define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \ - PUT_16BE((b), (off) + 2, (v))) +#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ + buf[(off) + 1] = (v) & 0xff) +#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ + PUT_16BE((off) + 2, (v))) /* Structure of an ELF file */ #define E_IDENT 0 /* ELF header */ @@ -95,71 +88,15 @@ unsigned char notebuf[512]; unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; -unsigned char *read_rpanote(const char *fname, int *nnp) -{ - int notefd, nr, i; - int ph, ps, np; - int note, notesize; - - notefd = open(fname, O_RDONLY); - if (notefd < 0) { - perror(fname); - exit(1); - } - nr = read(notefd, notebuf, sizeof(notebuf)); - if (nr < 0) { - perror("read note"); - exit(1); - } - if (nr == 0) /* empty file */ - return NULL; - if (nr < E_HSIZE || - memcmp(¬ebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 || - notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 || - notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB) - goto notelf; - close(notefd); - - /* now look for the RPA-note */ - ph = GET_32BE(notebuf, E_PHOFF); - ps = GET_16BE(notebuf, E_PHENTSIZE); - np = GET_16BE(notebuf, E_PHNUM); - if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) - goto notelf; - - for (i = 0; i < np; ++i, ph += ps) { - if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE) - continue; - note = GET_32BE(notebuf, ph + PH_OFFSET); - notesize = GET_32BE(notebuf, ph + PH_FILESZ); - if (notesize < 34 || note + notesize > nr) - continue; - if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 || - GET_32BE(notebuf, note + 8) != 0x12759999 || - strcmp((char *)¬ebuf[note + 12], rpaname) != 0) - continue; - /* looks like an RPA note, return it */ - *nnp = notesize; - return ¬ebuf[note]; - } - /* no RPA note found */ - return NULL; - - notelf: - fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname); - exit(1); -} - int main(int ac, char **av) { int fd, n, i; int ph, ps, np; int nnote, nnote2, ns; - unsigned char *rpap; - if (ac != 2 && ac != 3) { - fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]); + if (ac != 2) { + fprintf(stderr, "Usage: %s elf-file\n", av[0]); exit(1); } fd = open(av[1], O_RDWR); @@ -170,7 +107,6 @@ main(int ac, char **av) nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); - rpap = NULL; n = read(fd, buf, sizeof(buf)); if (n < 0) { @@ -188,19 +124,16 @@ main(int ac, char **av) exit(1); } - if (ac == 3) - rpap = read_rpanote(av[2], &nnote2); - - ph = GET_32BE(buf, E_PHOFF); - ps = GET_16BE(buf, E_PHENTSIZE); - np = GET_16BE(buf, E_PHNUM); + ph = GET_32BE(E_PHOFF); + ps = GET_16BE(E_PHENTSIZE); + np = GET_16BE(E_PHNUM); if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) goto notelf; if (ph + (np + 2) * ps + nnote + nnote2 > n) goto nospace; for (i = 0; i < np; ++i) { - if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) { + if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { fprintf(stderr, "%s already has a note entry\n", av[1]); exit(0); @@ -215,42 +148,37 @@ main(int ac, char **av) /* fill in the program header entry */ ns = ph + 2 * ps; - PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); - PUT_32BE(buf, ph + PH_OFFSET, ns); - PUT_32BE(buf, ph + PH_FILESZ, nnote); + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote); /* fill in the note area we point to */ /* XXX we should probably make this a proper section */ - PUT_32BE(buf, ns, strlen(arch) + 1); - PUT_32BE(buf, ns + 4, N_DESCR * 4); - PUT_32BE(buf, ns + 8, 0x1275); + PUT_32BE(ns, strlen(arch) + 1); + PUT_32BE(ns + 4, N_DESCR * 4); + PUT_32BE(ns + 8, 0x1275); strcpy((char *) &buf[ns + 12], arch); ns += 12 + strlen(arch) + 1; for (i = 0; i < N_DESCR; ++i, ns += 4) - PUT_32BE(buf, ns, descr[i]); + PUT_32BE(ns, descr[i]); /* fill in the second program header entry and the RPA note area */ ph += ps; - PUT_32BE(buf, ph + PH_TYPE, PT_NOTE); - PUT_32BE(buf, ph + PH_OFFSET, ns); - PUT_32BE(buf, ph + PH_FILESZ, nnote2); + PUT_32BE(ph + PH_TYPE, PT_NOTE); + PUT_32BE(ph + PH_OFFSET, ns); + PUT_32BE(ph + PH_FILESZ, nnote2); /* fill in the note area we point to */ - if (rpap) { - /* RPA note supplied in file, just copy the whole thing over */ - memcpy(buf + ns, rpap, nnote2); - } else { - PUT_32BE(buf, ns, strlen(rpaname) + 1); - PUT_32BE(buf, ns + 4, sizeof(rpanote)); - PUT_32BE(buf, ns + 8, 0x12759999); - strcpy((char *) &buf[ns + 12], rpaname); - ns += 12 + ROUNDUP(strlen(rpaname) + 1); - for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) - PUT_32BE(buf, ns, rpanote[i]); - } + PUT_32BE(ns, strlen(rpaname) + 1); + PUT_32BE(ns + 4, sizeof(rpanote)); + PUT_32BE(ns + 8, 0x12759999); + strcpy((char *) &buf[ns + 12], rpaname); + ns += 12 + ROUNDUP(strlen(rpaname) + 1); + for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) + PUT_32BE(ns, rpanote[i]); /* Update the number of program headers */ - PUT_16BE(buf, E_PHNUM, np + 2); + PUT_16BE(E_PHNUM, np + 2); /* write back */ lseek(fd, (long) 0, SEEK_SET); diff --git a/trunk/arch/powerpc/boot/wrapper b/trunk/arch/powerpc/boot/wrapper index ee0dc41d7c56..965c237c122d 100755 --- a/trunk/arch/powerpc/boot/wrapper +++ b/trunk/arch/powerpc/boot/wrapper @@ -307,9 +307,7 @@ fi # post-processing needed for some platforms case "$platform" in pseries|chrp) - ${CROSS}objcopy -O binary -j .fakeelf "$kernel" "$ofile".rpanote - $objbin/addnote "$ofile" "$ofile".rpanote - rm -r "$ofile".rpanote + $objbin/addnote "$ofile" ;; coff) ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" diff --git a/trunk/arch/powerpc/include/asm/smp.h b/trunk/arch/powerpc/include/asm/smp.h index 1866cec4f967..c092f84302fd 100644 --- a/trunk/arch/powerpc/include/asm/smp.h +++ b/trunk/arch/powerpc/include/asm/smp.h @@ -93,7 +93,7 @@ extern void __cpu_die(unsigned int cpu); #else /* for UP */ -#define hard_smp_processor_id() get_hard_smp_processor_id(0) +#define hard_smp_processor_id() 0 #define smp_setup_cpu_maps() #endif /* CONFIG_SMP */ @@ -122,7 +122,6 @@ static inline int get_hard_smp_processor_id(int cpu) static inline void set_hard_smp_processor_id(int cpu, int phys) { - boot_cpuid_phys = phys; } #endif /* !CONFIG_SMP */ #endif /* !CONFIG_PPC64 */ diff --git a/trunk/arch/powerpc/kernel/misc_32.S b/trunk/arch/powerpc/kernel/misc_32.S index 6a9b4bf0d173..e9c8ab6eabfe 100644 --- a/trunk/arch/powerpc/kernel/misc_32.S +++ b/trunk/arch/powerpc/kernel/misc_32.S @@ -900,10 +900,8 @@ _GLOBAL(kernel_thread) li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - bns+ 1f /* did system call indicate error? */ - neg r3,r3 /* if so, make return code negative */ -1: cmpwi 0,r3,0 /* parent or child? */ - bne 2f /* return if parent */ + cmpwi 0,r3,0 /* parent or child? */ + bne 1f /* return if parent */ li r0,0 /* make top-level stack frame */ stwu r0,-16(r1) mtlr r30 /* fn addr in lr */ @@ -913,7 +911,7 @@ _GLOBAL(kernel_thread) li r0,__NR_exit /* exit if function returns */ li r3,0 sc -2: lwz r30,8(r1) +1: lwz r30,8(r1) lwz r31,12(r1) addi r1,r1,16 blr diff --git a/trunk/arch/powerpc/kernel/misc_64.S b/trunk/arch/powerpc/kernel/misc_64.S index 3053fe5c62f2..4dd70cf7bb4e 100644 --- a/trunk/arch/powerpc/kernel/misc_64.S +++ b/trunk/arch/powerpc/kernel/misc_64.S @@ -426,10 +426,8 @@ _GLOBAL(kernel_thread) li r4,0 /* new sp (unused) */ li r0,__NR_clone sc - bns+ 1f /* did system call indicate error? */ - neg r3,r3 /* if so, make return code negative */ -1: cmpdi 0,r3,0 /* parent or child? */ - bne 2f /* return if parent */ + cmpdi 0,r3,0 /* parent or child? */ + bne 1f /* return if parent */ li r0,0 stdu r0,-STACK_FRAME_OVERHEAD(r1) ld r2,8(r29) @@ -440,7 +438,7 @@ _GLOBAL(kernel_thread) li r0,__NR_exit /* exit after child exits */ li r3,0 sc -2: addi r1,r1,STACK_FRAME_OVERHEAD +1: addi r1,r1,STACK_FRAME_OVERHEAD ld r29,-24(r1) ld r30,-16(r1) blr diff --git a/trunk/arch/powerpc/kernel/prom_init.c b/trunk/arch/powerpc/kernel/prom_init.c index 2fdbc18ae94a..7cf274a2b334 100644 --- a/trunk/arch/powerpc/kernel/prom_init.c +++ b/trunk/arch/powerpc/kernel/prom_init.c @@ -732,7 +732,7 @@ static struct fake_elf { u32 ignore_me; } rpadesc; } rpanote; -} fake_elf __section(.fakeelf) = { +} fake_elf = { .elfhdr = { .e_ident = { 0x7f, 'E', 'L', 'F', ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, @@ -774,13 +774,13 @@ static struct fake_elf { .type = 0x12759999, .name = "IBM,RPA-Client-Config", .rpadesc = { - .lpar_affinity = 1, - .min_rmo_size = 128, /* in megabytes */ + .lpar_affinity = 0, + .min_rmo_size = 64, /* in megabytes */ .min_rmo_percent = 0, - .max_pft_size = 46, /* 2^46 bytes max PFT size */ + .max_pft_size = 48, /* 2^48 bytes max PFT size */ .splpar = 1, .min_load = ~0U, - .new_mem_def = 1 + .new_mem_def = 0 } } }; diff --git a/trunk/arch/powerpc/kernel/smp.c b/trunk/arch/powerpc/kernel/smp.c index 3ee736fa8b1d..5337ca7bb649 100644 --- a/trunk/arch/powerpc/kernel/smp.c +++ b/trunk/arch/powerpc/kernel/smp.c @@ -101,7 +101,8 @@ void smp_message_recv(int msg) generic_smp_call_function_interrupt(); break; case PPC_MSG_RESCHEDULE: - /* we notice need_resched on exit */ + /* XXX Do we have to do this? */ + set_need_resched(); break; case PPC_MSG_CALL_FUNC_SINGLE: generic_smp_call_function_single_interrupt(); diff --git a/trunk/arch/powerpc/kernel/vmlinux.lds.S b/trunk/arch/powerpc/kernel/vmlinux.lds.S index b39c27ed7919..e6927fb2e655 100644 --- a/trunk/arch/powerpc/kernel/vmlinux.lds.S +++ b/trunk/arch/powerpc/kernel/vmlinux.lds.S @@ -203,9 +203,6 @@ SECTIONS *(.rela*) } - /* Fake ELF header containing RPA note; for addnote */ - .fakeelf : AT(ADDR(.fakeelf) - LOAD_OFFSET) { *(.fakeelf) } - /* freed after init ends here */ . = ALIGN(PAGE_SIZE); __init_end = .; diff --git a/trunk/arch/powerpc/mm/numa.c b/trunk/arch/powerpc/mm/numa.c index 6cf5c71c431f..be05457631d4 100644 --- a/trunk/arch/powerpc/mm/numa.c +++ b/trunk/arch/powerpc/mm/numa.c @@ -89,46 +89,6 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn, return 0; } -/* - * get_active_region_work_fn - A helper function for get_node_active_region - * Returns datax set to the start_pfn and end_pfn if they contain - * the initial value of datax->start_pfn between them - * @start_pfn: start page(inclusive) of region to check - * @end_pfn: end page(exclusive) of region to check - * @datax: comes in with ->start_pfn set to value to search for and - * goes out with active range if it contains it - * Returns 1 if search value is in range else 0 - */ -static int __init get_active_region_work_fn(unsigned long start_pfn, - unsigned long end_pfn, void *datax) -{ - struct node_active_region *data; - data = (struct node_active_region *)datax; - - if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) { - data->start_pfn = start_pfn; - data->end_pfn = end_pfn; - return 1; - } - return 0; - -} - -/* - * get_node_active_region - Return active region containing start_pfn - * @start_pfn: The page to return the region for. - * @node_ar: Returned set to the active region containing start_pfn - */ -static void __init get_node_active_region(unsigned long start_pfn, - struct node_active_region *node_ar) -{ - int nid = early_pfn_to_nid(start_pfn); - - node_ar->nid = nid; - node_ar->start_pfn = start_pfn; - work_with_active_regions(nid, get_active_region_work_fn, node_ar); -} - static void __cpuinit map_cpu_to_node(int cpu, int node) { numa_cpu_lookup_table[cpu] = node; @@ -922,50 +882,38 @@ void __init do_init_bootmem(void) start_pfn, end_pfn); free_bootmem_with_active_regions(nid, end_pfn); - } - /* Mark reserved regions */ - for (i = 0; i < lmb.reserved.cnt; i++) { - unsigned long physbase = lmb.reserved.region[i].base; - unsigned long size = lmb.reserved.region[i].size; - unsigned long start_pfn = physbase >> PAGE_SHIFT; - unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT); - struct node_active_region node_ar; - - get_node_active_region(start_pfn, &node_ar); - while (start_pfn < end_pfn) { - /* - * if reserved region extends past active region - * then trim size to active region - */ - if (end_pfn > node_ar.end_pfn) - size = (node_ar.end_pfn << PAGE_SHIFT) - - (start_pfn << PAGE_SHIFT); - dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, size, - node_ar.nid); - reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase, - size, BOOTMEM_DEFAULT); - /* - * if reserved region is contained in the active region - * then done. - */ - if (end_pfn <= node_ar.end_pfn) - break; - - /* - * reserved region extends past the active region - * get next active region that contains this - * reserved region - */ - start_pfn = node_ar.end_pfn; - physbase = start_pfn << PAGE_SHIFT; - get_node_active_region(start_pfn, &node_ar); - } + /* Mark reserved regions on this node */ + for (i = 0; i < lmb.reserved.cnt; i++) { + unsigned long physbase = lmb.reserved.region[i].base; + unsigned long size = lmb.reserved.region[i].size; + unsigned long start_paddr = start_pfn << PAGE_SHIFT; + unsigned long end_paddr = end_pfn << PAGE_SHIFT; - } + if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid && + early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid) + continue; + + if (physbase < end_paddr && + (physbase+size) > start_paddr) { + /* overlaps */ + if (physbase < start_paddr) { + size -= start_paddr - physbase; + physbase = start_paddr; + } + + if (size > end_paddr - physbase) + size = end_paddr - physbase; + + dbg("reserve_bootmem %lx %lx\n", physbase, + size); + reserve_bootmem_node(NODE_DATA(nid), physbase, + size, BOOTMEM_DEFAULT); + } + } - for_each_online_node(nid) sparse_memory_present_with_active_regions(nid); + } } void __init paging_init(void) diff --git a/trunk/arch/powerpc/oprofile/cell/vma_map.c b/trunk/arch/powerpc/oprofile/cell/vma_map.c index 258fa4411e9e..fff66662d021 100644 --- a/trunk/arch/powerpc/oprofile/cell/vma_map.c +++ b/trunk/arch/powerpc/oprofile/cell/vma_map.c @@ -229,7 +229,7 @@ struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu, */ overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym, aSpu, &grd_val); - if (overlay_tbl_offset > 0x10000000) { + if (overlay_tbl_offset < 0) { printk(KERN_ERR "SPU_PROF: " "%s, line %d: Error finding SPU overlay table\n", __func__, __LINE__); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index 6b7c7b132454..690ca7b0dcf6 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -298,8 +298,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, d_instantiate(dentry, inode); dget(dentry); - inc_nlink(dir); - inc_nlink(dentry->d_inode); + dir->i_nlink++; + dentry->d_inode->i_nlink++; goto out; out_free_ctx: @@ -496,8 +496,6 @@ spufs_create_context(struct inode *inode, struct dentry *dentry, ret = spufs_context_open(dget(dentry), mntget(mnt)); if (ret < 0) { WARN_ON(spufs_rmdir(inode, dentry)); - if (affinity) - mutex_unlock(&gang->aff_mutex); mutex_unlock(&inode->i_mutex); spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); goto out; @@ -540,8 +538,8 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) inode->i_fop = &simple_dir_operations; d_instantiate(dentry, inode); - inc_nlink(dir); - inc_nlink(dentry->d_inode); + dir->i_nlink++; + dentry->d_inode->i_nlink++; return ret; out_iput: @@ -757,7 +755,6 @@ spufs_create_root(struct super_block *sb, void *data) inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; SPUFS_I(inode)->i_ctx = NULL; - inc_nlink(inode); ret = -EINVAL; if (!spufs_parse_options(sb, data, inode)) diff --git a/trunk/arch/powerpc/platforms/pseries/hotplug-memory.c b/trunk/arch/powerpc/platforms/pseries/hotplug-memory.c index 140d02a5232a..a1a368dd2d99 100644 --- a/trunk/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/trunk/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size) struct zone *zone; int ret; - start_pfn = base >> PAGE_SHIFT; + start_pfn = base >> PFN_SECTION_SHIFT; zone = page_zone(pfn_to_page(start_pfn)); /* diff --git a/trunk/arch/powerpc/platforms/pseries/smp.c b/trunk/arch/powerpc/platforms/pseries/smp.c index e00f96baa381..9d8f8c84ab89 100644 --- a/trunk/arch/powerpc/platforms/pseries/smp.c +++ b/trunk/arch/powerpc/platforms/pseries/smp.c @@ -37,6 +37,7 @@ #include #include #include +#include "xics.h" #include #include #include @@ -48,7 +49,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#include "xics.h" /* @@ -105,6 +105,36 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) } #ifdef CONFIG_XICS +static inline void smp_xics_do_message(int cpu, int msg) +{ + set_bit(msg, &xics_ipi_message[cpu].value); + mb(); + xics_cause_IPI(cpu); +} + +static void smp_xics_message_pass(int target, int msg) +{ + unsigned int i; + + if (target < NR_CPUS) { + smp_xics_do_message(target, msg); + } else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + smp_xics_do_message(i, msg); + } + } +} + +static int __init smp_xics_probe(void) +{ + xics_request_IPIs(); + + return cpus_weight(cpu_possible_map); +} + static void __devinit smp_xics_setup_cpu(int cpu) { if (cpu != boot_cpuid) diff --git a/trunk/arch/powerpc/platforms/pseries/xics.c b/trunk/arch/powerpc/platforms/pseries/xics.c index e1904774a70f..6b1a005cc0cc 100644 --- a/trunk/arch/powerpc/platforms/pseries/xics.c +++ b/trunk/arch/powerpc/platforms/pseries/xics.c @@ -9,30 +9,32 @@ * 2 of the License, or (at your option) any later version. */ + #include #include #include #include #include #include +#include #include +#include #include #include -#include #include +#include #include #include #include #include #include #include +#include #include "xics.h" #include "plpar_wrappers.h" -static struct irq_host *xics_host; - #define XICS_IPI 2 #define XICS_IRQ_SPURIOUS 0 @@ -45,20 +47,6 @@ static struct irq_host *xics_host; */ #define IPI_PRIORITY 4 -static unsigned int default_server = 0xFF; -static unsigned int default_distrib_server = 0; -static unsigned int interrupt_server_size = 8; - -/* RTAS service tokens */ -static int ibm_get_xive; -static int ibm_set_xive; -static int ibm_int_on; -static int ibm_int_off; - - -/* Direct hardware low level accessors */ - -/* The part of the interrupt presentation layer that we care about */ struct xics_ipl { union { u32 word; @@ -77,6 +65,27 @@ struct xics_ipl { static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; +static unsigned int default_server = 0xFF; +static unsigned int default_distrib_server = 0; +static unsigned int interrupt_server_size = 8; + +static struct irq_host *xics_host; + +/* + * XICS only has a single IPI, so encode the messages per CPU + */ +struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; + +/* RTAS service tokens */ +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; + + +/* Direct HW low level accessors */ + + static inline unsigned int direct_xirr_info_get(void) { int cpu = smp_processor_id(); @@ -84,7 +93,7 @@ static inline unsigned int direct_xirr_info_get(void) return in_be32(&xics_per_cpu[cpu]->xirr.word); } -static inline void direct_xirr_info_set(unsigned int value) +static inline void direct_xirr_info_set(int value) { int cpu = smp_processor_id(); @@ -106,6 +115,7 @@ static inline void direct_qirr_info(int n_cpu, u8 value) /* LPAR low level accessors */ + static inline unsigned int lpar_xirr_info_get(void) { unsigned long lpar_rc; @@ -117,14 +127,15 @@ static inline unsigned int lpar_xirr_info_get(void) return (unsigned int)return_value; } -static inline void lpar_xirr_info_set(unsigned int value) +static inline void lpar_xirr_info_set(int value) { unsigned long lpar_rc; + unsigned long val64 = value & 0xffffffff; - lpar_rc = plpar_eoi(value); + lpar_rc = plpar_eoi(val64); if (lpar_rc != H_SUCCESS) - panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc, - value); + panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, + val64); } static inline void lpar_cppr_info(u8 value) @@ -146,7 +157,48 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) } -/* Interface to generic irq subsystem */ +/* High level handlers and init code */ + +static void xics_update_irq_servers(void) +{ + int i, j; + struct device_node *np; + u32 ilen; + const u32 *ireg, *isize; + u32 hcpuid; + + /* Find the server numbers for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + if (!ireg) { + of_node_put(np); + return; + } + + i = ilen / sizeof(int); + hcpuid = get_hard_smp_processor_id(boot_cpuid); + + /* Global interrupt distribution server is specified in the last + * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last + * entry fom this property for current boot cpu id and use it as + * default distribution server + */ + for (j = 0; j < i; j += 2) { + if (ireg[j] == hcpuid) { + default_server = hcpuid; + default_distrib_server = ireg[j+1]; + + isize = of_get_property(np, + "ibm,interrupt-server#-size", NULL); + if (isize) + interrupt_server_size = *isize; + } + } + + of_node_put(np); +} #ifdef CONFIG_SMP static int get_irq_server(unsigned int virq, unsigned int strict_check) @@ -156,6 +208,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) cpumask_t cpumask = irq_desc[virq].affinity; cpumask_t tmp = CPU_MASK_NONE; + if (! cpu_isset(default_server, cpu_online_map)) + xics_update_irq_servers(); + if (!distribute_irqs) return default_server; @@ -183,6 +238,7 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) } #endif + static void xics_unmask_irq(unsigned int virq) { unsigned int irq; @@ -201,28 +257,21 @@ static void xics_unmask_irq(unsigned int virq) call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); if (call_status != 0) { - printk(KERN_ERR - "%s: ibm_set_xive irq %u server %x returned %d\n", - __func__, irq, server, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " + "returned %d\n", irq, call_status); + printk("set_xive %x, server %x\n", ibm_set_xive, server); return; } /* Now unmask the interrupt (often a no-op) */ call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", - __func__, irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " + "returned %d\n", irq, call_status); return; } } -static unsigned int xics_startup(unsigned int virq) -{ - /* unmask it */ - xics_unmask_irq(virq); - return 0; -} - static void xics_mask_real_irq(unsigned int irq) { int call_status; @@ -232,8 +281,8 @@ static void xics_mask_real_irq(unsigned int irq) call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", - __func__, irq, call_status); + printk(KERN_ERR "xics_disable_real_irq: irq=%u: " + "ibm_int_off returned %d\n", irq, call_status); return; } @@ -241,8 +290,8 @@ static void xics_mask_real_irq(unsigned int irq) call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, default_server, 0xff); if (call_status != 0) { - printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", - __func__, irq, call_status); + printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" + " returned %d\n", irq, call_status); return; } } @@ -259,77 +308,126 @@ static void xics_mask_irq(unsigned int virq) xics_mask_real_irq(irq); } -static void xics_mask_unknown_vec(unsigned int vec) +static unsigned int xics_startup(unsigned int virq) { - printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); - xics_mask_real_irq(vec); + /* unmask it */ + xics_unmask_irq(virq); + return 0; } -static inline unsigned int xics_xirr_vector(unsigned int xirr) +static void xics_eoi_direct(unsigned int virq) { - /* - * The top byte is the old cppr, to be restored on EOI. - * The remaining 24 bits are the vector. - */ - return xirr & 0x00ffffff; + unsigned int irq = (unsigned int)irq_map[virq].hwirq; + + iosync(); + direct_xirr_info_set((0xff << 24) | irq); } -static unsigned int xics_get_irq_direct(void) + +static void xics_eoi_lpar(unsigned int virq) +{ + unsigned int irq = (unsigned int)irq_map[virq].hwirq; + + iosync(); + lpar_xirr_info_set((0xff << 24) | irq); +} + +static inline unsigned int xics_remap_irq(unsigned int vec) { - unsigned int xirr = direct_xirr_info_get(); - unsigned int vec = xics_xirr_vector(xirr); unsigned int irq; + vec &= 0x00ffffff; + if (vec == XICS_IRQ_SPURIOUS) return NO_IRQ; - irq = irq_radix_revmap_lookup(xics_host, vec); if (likely(irq != NO_IRQ)) return irq; - /* We don't have a linux mapping, so have rtas mask it. */ - xics_mask_unknown_vec(vec); - - /* We might learn about it later, so EOI it */ - direct_xirr_info_set(xirr); + printk(KERN_ERR "Interrupt %u (real) is invalid," + " disabling it.\n", vec); + xics_mask_real_irq(vec); return NO_IRQ; } +static unsigned int xics_get_irq_direct(void) +{ + return xics_remap_irq(direct_xirr_info_get()); +} + static unsigned int xics_get_irq_lpar(void) { - unsigned int xirr = lpar_xirr_info_get(); - unsigned int vec = xics_xirr_vector(xirr); - unsigned int irq; + return xics_remap_irq(lpar_xirr_info_get()); +} - if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; +#ifdef CONFIG_SMP - irq = irq_radix_revmap_lookup(xics_host, vec); - if (likely(irq != NO_IRQ)) - return irq; +static irqreturn_t xics_ipi_dispatch(int cpu) +{ + WARN_ON(cpu_is_offline(cpu)); - /* We don't have a linux mapping, so have RTAS mask it. */ - xics_mask_unknown_vec(vec); + while (xics_ipi_message[cpu].value) { + if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, + &xics_ipi_message[cpu].value)) { + mb(); + smp_message_recv(PPC_MSG_CALL_FUNCTION); + } + if (test_and_clear_bit(PPC_MSG_RESCHEDULE, + &xics_ipi_message[cpu].value)) { + mb(); + smp_message_recv(PPC_MSG_RESCHEDULE); + } + if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, + &xics_ipi_message[cpu].value)) { + mb(); + smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); + } +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) + if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, + &xics_ipi_message[cpu].value)) { + mb(); + smp_message_recv(PPC_MSG_DEBUGGER_BREAK); + } +#endif + } + return IRQ_HANDLED; +} - /* We might learn about it later, so EOI it */ - lpar_xirr_info_set(xirr); - return NO_IRQ; +static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) +{ + int cpu = smp_processor_id(); + + direct_qirr_info(cpu, 0xff); + + return xics_ipi_dispatch(cpu); } -static void xics_eoi_direct(unsigned int virq) +static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) { - unsigned int irq = (unsigned int)irq_map[virq].hwirq; + int cpu = smp_processor_id(); - iosync(); - direct_xirr_info_set((0xff << 24) | irq); + lpar_qirr_info(cpu, 0xff); + + return xics_ipi_dispatch(cpu); } -static void xics_eoi_lpar(unsigned int virq) +void xics_cause_IPI(int cpu) { - unsigned int irq = (unsigned int)irq_map[virq].hwirq; + if (firmware_has_feature(FW_FEATURE_LPAR)) + lpar_qirr_info(cpu, IPI_PRIORITY); + else + direct_qirr_info(cpu, IPI_PRIORITY); +} + +#endif /* CONFIG_SMP */ +static void xics_set_cpu_priority(unsigned char cppr) +{ + if (firmware_has_feature(FW_FEATURE_LPAR)) + lpar_cppr_info(cppr); + else + direct_cppr_info(cppr); iosync(); - lpar_xirr_info_set((0xff << 24) | irq); } static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) @@ -346,8 +444,8 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, irq, status); + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " + "returns %d\n", irq, status); return; } @@ -359,9 +457,8 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) if (irq_server == -1) { char cpulist[128]; cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); - printk(KERN_WARNING - "%s: No online cpus in the mask %s for irq %d\n", - __func__, cpulist, virq); + printk(KERN_WARNING "xics_set_affinity: No online cpus in " + "the mask %s for irq %d\n", cpulist, virq); return; } @@ -369,12 +466,28 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) irq, irq_server, xics_status[1]); if (status) { - printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", - __func__, irq, status); + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " + "returns %d\n", irq, status); return; } } +void xics_setup_cpu(void) +{ + xics_set_cpu_priority(0xff); + + /* + * Put the calling processor into the GIQ. This is really only + * necessary from a secondary thread as the OF start-cpu interface + * performs this function for us on primary threads. + * + * XXX: undo of teardown on kexec needs this too, as may hotplug + */ + rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); +} + + static struct irq_chip xics_pic_direct = { .typename = " XICS ", .startup = xics_startup, @@ -384,6 +497,7 @@ static struct irq_chip xics_pic_direct = { .set_affinity = xics_set_affinity }; + static struct irq_chip xics_pic_lpar = { .typename = " XICS ", .startup = xics_startup, @@ -393,9 +507,6 @@ static struct irq_chip xics_pic_lpar = { .set_affinity = xics_set_affinity }; - -/* Interface to arch irq controller subsystem layer */ - /* Points to the irq_chip we're actually using */ static struct irq_chip *xics_irq_chip; @@ -455,169 +566,10 @@ static void __init xics_init_host(void) irq_set_default_host(xics_host); } - -/* Inter-processor interrupt support */ - -#ifdef CONFIG_SMP -/* - * XICS only has a single IPI, so encode the messages per CPU - */ -struct xics_ipi_struct { - unsigned long value; - } ____cacheline_aligned; - -static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; - -static inline void smp_xics_do_message(int cpu, int msg) -{ - set_bit(msg, &xics_ipi_message[cpu].value); - mb(); - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_qirr_info(cpu, IPI_PRIORITY); - else - direct_qirr_info(cpu, IPI_PRIORITY); -} - -void smp_xics_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - smp_xics_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - smp_xics_do_message(i, msg); - } - } -} - -static irqreturn_t xics_ipi_dispatch(int cpu) -{ - WARN_ON(cpu_is_offline(cpu)); - - mb(); /* order mmio clearing qirr */ - while (xics_ipi_message[cpu].value) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, - &xics_ipi_message[cpu].value)) { - smp_message_recv(PPC_MSG_CALL_FUNCTION); - } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, - &xics_ipi_message[cpu].value)) { - smp_message_recv(PPC_MSG_RESCHEDULE); - } - if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, - &xics_ipi_message[cpu].value)) { - smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); - } -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, - &xics_ipi_message[cpu].value)) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); - } -#endif - } - return IRQ_HANDLED; -} - -static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - direct_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - lpar_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static void xics_request_ipi(void) -{ - unsigned int ipi; - int rc; - - ipi = irq_create_mapping(xics_host, XICS_IPI); - BUG_ON(ipi == NO_IRQ); - - /* - * IPIs are marked IRQF_DISABLED as they must run with irqs - * disabled - */ - set_irq_handler(ipi, handle_percpu_irq); - if (firmware_has_feature(FW_FEATURE_LPAR)) - rc = request_irq(ipi, xics_ipi_action_lpar, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - else - rc = request_irq(ipi, xics_ipi_action_direct, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - BUG_ON(rc); -} - -int __init smp_xics_probe(void) -{ - xics_request_ipi(); - - return cpus_weight(cpu_possible_map); -} - -#endif /* CONFIG_SMP */ - - -/* Initialization */ - -static void xics_update_irq_servers(void) -{ - int i, j; - struct device_node *np; - u32 ilen; - const u32 *ireg, *isize; - u32 hcpuid; - - /* Find the server numbers for the boot cpu. */ - np = of_get_cpu_node(boot_cpuid, NULL); - BUG_ON(!np); - - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); - if (!ireg) { - of_node_put(np); - return; - } - - i = ilen / sizeof(int); - hcpuid = get_hard_smp_processor_id(boot_cpuid); - - /* Global interrupt distribution server is specified in the last - * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last - * entry fom this property for current boot cpu id and use it as - * default distribution server - */ - for (j = 0; j < i; j += 2) { - if (ireg[j] == hcpuid) { - default_server = hcpuid; - default_distrib_server = ireg[j+1]; - } - } - - /* get the bit size of server numbers */ - isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); - if (isize) - interrupt_server_size = *isize; - - of_node_put(np); -} - static void __init xics_map_one_cpu(int hw_id, unsigned long addr, unsigned long size) { +#ifdef CONFIG_SMP int i; /* This may look gross but it's good enough for now, we don't quite @@ -631,6 +583,11 @@ static void __init xics_map_one_cpu(int hw_id, unsigned long addr, return; } } +#else + if (hw_id != 0) + return; + xics_per_cpu[0] = ioremap(addr, size); +#endif /* CONFIG_SMP */ } static void __init xics_init_one_node(struct device_node *np, @@ -692,17 +649,15 @@ void __init xics_init_IRQ(void) for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") { found = 1; - if (firmware_has_feature(FW_FEATURE_LPAR)) { - of_node_put(np); + if (firmware_has_feature(FW_FEATURE_LPAR)) break; - } xics_init_one_node(np, &indx); } if (found == 0) return; - xics_update_irq_servers(); xics_init_host(); + xics_update_irq_servers(); if (firmware_has_feature(FW_FEATURE_LPAR)) ppc_md.get_irq = xics_get_irq_lpar; @@ -714,31 +669,30 @@ void __init xics_init_IRQ(void) ppc64_boot_msg(0x21, "XICS Done"); } -/* Cpu startup, shutdown, and hotplug */ -static void xics_set_cpu_priority(unsigned char cppr) -{ - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_cppr_info(cppr); - else - direct_cppr_info(cppr); - iosync(); -} - -/* Have the calling processor join or leave the specified global queue */ -static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) +#ifdef CONFIG_SMP +void xics_request_IPIs(void) { - int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - gserver, join); - WARN_ON(status < 0); -} + unsigned int ipi; + int rc; -void xics_setup_cpu(void) -{ - xics_set_cpu_priority(0xff); + ipi = irq_create_mapping(xics_host, XICS_IPI); + BUG_ON(ipi == NO_IRQ); - xics_set_cpu_giq(default_distrib_server, 1); + /* + * IPIs are marked IRQF_DISABLED as they must run with irqs + * disabled + */ + set_irq_handler(ipi, handle_percpu_irq); + if (firmware_has_feature(FW_FEATURE_LPAR)) + rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, + "IPI", NULL); + else + rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, + "IPI", NULL); + BUG_ON(rc); } +#endif /* CONFIG_SMP */ void xics_teardown_cpu(void) { @@ -746,7 +700,9 @@ void xics_teardown_cpu(void) xics_set_cpu_priority(0); - /* Clear any pending IPI request */ + /* + * Clear IPI + */ if (firmware_has_feature(FW_FEATURE_LPAR)) lpar_qirr_info(cpu, 0xff); else @@ -755,28 +711,34 @@ void xics_teardown_cpu(void) void xics_kexec_teardown_cpu(int secondary) { + unsigned int ipi; + struct irq_desc *desc; + xics_teardown_cpu(); /* - * we take the ipi irq but and never return so we - * need to EOI the IPI, but want to leave our priority 0 + * we need to EOI the IPI * - * should we check all the other interrupts too? + * probably need to check all the other interrupts too * should we be flagging idle loop instead? * or creating some task to be scheduled? */ - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_xirr_info_set((0x00 << 24) | XICS_IPI); - else - direct_xirr_info_set((0x00 << 24) | XICS_IPI); + ipi = irq_find_mapping(xics_host, XICS_IPI); + if (ipi == XICS_IRQ_SPURIOUS) + return; + desc = get_irq_desc(ipi); + if (desc->chip && desc->chip->eoi) + desc->chip->eoi(ipi); /* * Some machines need to have at least one cpu in the GIQ, * so leave the master cpu in the group. */ if (secondary) - xics_set_cpu_giq(default_distrib_server, 0); + rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - + default_distrib_server, 0); } #ifdef CONFIG_HOTPLUG_CPU @@ -784,18 +746,17 @@ void xics_kexec_teardown_cpu(int secondary) /* Interrupts are disabled. */ void xics_migrate_irqs_away(void) { + int status; int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); unsigned int irq, virq; - /* If we used to be the default server, move to the new "boot_cpuid" */ - if (hw_cpu == default_server) - xics_update_irq_servers(); - /* Reject any interrupt that was queued to us... */ xics_set_cpu_priority(0); - /* Remove ourselves from the global interrupt queue */ - xics_set_cpu_giq(default_distrib_server, 0); + /* remove ourselves from the global interrupt queue */ + status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); + WARN_ON(status < 0); /* Allow IPIs again... */ xics_set_cpu_priority(DEFAULT_PRIORITY); @@ -803,7 +764,6 @@ void xics_migrate_irqs_away(void) for_each_irq(virq) { struct irq_desc *desc; int xics_status[2]; - int status; unsigned long flags; /* We cant set affinity on ISA interrupts */ @@ -827,8 +787,9 @@ void xics_migrate_irqs_away(void) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, irq, status); + printk(KERN_ERR "migrate_irqs_away: irq=%u " + "ibm,get-xive returns %d\n", + virq, status); goto unlock; } diff --git a/trunk/arch/powerpc/platforms/pseries/xics.h b/trunk/arch/powerpc/platforms/pseries/xics.h index d1d5a83039ae..1c5321ae8f2f 100644 --- a/trunk/arch/powerpc/platforms/pseries/xics.h +++ b/trunk/arch/powerpc/platforms/pseries/xics.h @@ -12,12 +12,20 @@ #ifndef _POWERPC_KERNEL_XICS_H #define _POWERPC_KERNEL_XICS_H +#include + extern void xics_init_IRQ(void); extern void xics_setup_cpu(void); extern void xics_teardown_cpu(void); extern void xics_kexec_teardown_cpu(int secondary); +extern void xics_cause_IPI(int cpu); +extern void xics_request_IPIs(void); extern void xics_migrate_irqs_away(void); -extern int smp_xics_probe(void); -extern void smp_xics_message_pass(int target, int msg); + +struct xics_ipi_struct { + volatile unsigned long value; +} ____cacheline_aligned; + +extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; #endif /* _POWERPC_KERNEL_XICS_H */ diff --git a/trunk/arch/powerpc/sysdev/Makefile b/trunk/arch/powerpc/sysdev/Makefile index a44709a94f97..55618ba9eff0 100644 --- a/trunk/arch/powerpc/sysdev/Makefile +++ b/trunk/arch/powerpc/sysdev/Makefile @@ -38,12 +38,15 @@ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_4xx) += ppc4xx_pci.o endif +# Temporary hack until we have migrated to asm-powerpc +ifeq ($(ARCH),powerpc) obj-$(CONFIG_CPM) += cpm_common.o obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o +endif ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o diff --git a/trunk/drivers/ata/pata_of_platform.c b/trunk/drivers/ata/pata_of_platform.c index 1f18ad9e4fe1..408da30594c4 100644 --- a/trunk/drivers/ata/pata_of_platform.c +++ b/trunk/drivers/ata/pata_of_platform.c @@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev, ret = of_irq_to_resource(dn, 0, &irq_res); if (ret == NO_IRQ) - irq_res.start = irq_res.end = 0; + irq_res.start = irq_res.end = -1; else irq_res.flags = 0; diff --git a/trunk/drivers/of/base.c b/trunk/drivers/of/base.c index 4270eb4a26a1..ad8ac1a8af28 100644 --- a/trunk/drivers/of/base.c +++ b/trunk/drivers/of/base.c @@ -420,12 +420,13 @@ static struct of_modalias_table of_modalias_table[] = { * @len: Length of modalias value * * Based on the value of the compatible property, this routine will determine - * an appropriate modalias value for a particular device tree node. Two - * separate methods are attempted to derive a modalias value. + * an appropriate modalias value for a particular device tree node. Three + * separate methods are used to derive a modalias value. * * First method is to lookup the compatible value in of_modalias_table. - * Second is to strip off the manufacturer prefix from the first - * compatible entry and use the remainder as modalias + * Second is to look for a "linux," entry in the compatible list + * and used that for modalias. Third is to strip off the manufacturer + * prefix from the first compatible entry and use the remainder as modalias * * This routine returns 0 on success */ @@ -448,7 +449,21 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) if (!compatible) return -ENODEV; - /* 2. take first compatible entry and strip manufacturer */ + /* 2. search for linux, entry */ + p = compatible; + while (cplen > 0) { + if (!strncmp(p, "linux,", 6)) { + p += 6; + strlcpy(modalias, p, len); + return 0; + } + + i = strlen(p) + 1; + p += i; + cplen -= i; + } + + /* 3. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; @@ -458,112 +473,3 @@ int of_modalias_node(struct device_node *node, char *modalias, int len) } EXPORT_SYMBOL_GPL(of_modalias_node); -/** - * of_parse_phandles_with_args - Find a node pointed by phandle in a list - * @np: pointer to a device tree node containing a list - * @list_name: property name that contains a list - * @cells_name: property name that specifies phandles' arguments count - * @index: index of a phandle to parse out - * @out_node: pointer to device_node struct pointer (will be filled) - * @out_args: pointer to arguments pointer (will be filled) - * - * This function is useful to parse lists of phandles and their arguments. - * Returns 0 on success and fills out_node and out_args, on error returns - * appropriate errno value. - * - * Example: - * - * phandle1: node1 { - * #list-cells = <2>; - * } - * - * phandle2: node2 { - * #list-cells = <1>; - * } - * - * node3 { - * list = <&phandle1 1 2 &phandle2 3>; - * } - * - * To get a device_node of the `node2' node you may call this: - * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); - */ -int of_parse_phandles_with_args(struct device_node *np, const char *list_name, - const char *cells_name, int index, - struct device_node **out_node, - const void **out_args) -{ - int ret = -EINVAL; - const u32 *list; - const u32 *list_end; - int size; - int cur_index = 0; - struct device_node *node = NULL; - const void *args; - - list = of_get_property(np, list_name, &size); - if (!list) { - ret = -ENOENT; - goto err0; - } - list_end = list + size / sizeof(*list); - - while (list < list_end) { - const u32 *cells; - const phandle *phandle; - - phandle = list; - args = list + 1; - - /* one cell hole in the list = <>; */ - if (!*phandle) { - list++; - goto next; - } - - node = of_find_node_by_phandle(*phandle); - if (!node) { - pr_debug("%s: could not find phandle\n", - np->full_name); - goto err0; - } - - cells = of_get_property(node, cells_name, &size); - if (!cells || size != sizeof(*cells)) { - pr_debug("%s: could not get %s for %s\n", - np->full_name, cells_name, node->full_name); - goto err1; - } - - /* Next phandle is at offset of one phandle cell + #cells */ - list += 1 + *cells; - if (list > list_end) { - pr_debug("%s: insufficient arguments length\n", - np->full_name); - goto err1; - } -next: - if (cur_index == index) - break; - - of_node_put(node); - node = NULL; - cur_index++; - } - - if (!node) { - ret = -ENOENT; - goto err0; - } - - *out_node = node; - *out_args = args; - - return 0; -err1: - of_node_put(node); -err0: - pr_debug("%s failed with status %d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL(of_parse_phandles_with_args); diff --git a/trunk/drivers/of/gpio.c b/trunk/drivers/of/gpio.c index 7cd7301b5839..1c9cab844f10 100644 --- a/trunk/drivers/of/gpio.c +++ b/trunk/drivers/of/gpio.c @@ -28,35 +28,78 @@ */ int of_get_gpio(struct device_node *np, int index) { - int ret; + int ret = -EINVAL; struct device_node *gc; struct of_gpio_chip *of_gc = NULL; int size; + const u32 *gpios; + u32 nr_cells; + int i; const void *gpio_spec; const u32 *gpio_cells; + int gpio_index = 0; - ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, - &gc, &gpio_spec); - if (ret) { - pr_debug("%s: can't parse gpios property\n", __func__); + gpios = of_get_property(np, "gpios", &size); + if (!gpios) { + ret = -ENOENT; goto err0; } - - of_gc = gc->data; - if (!of_gc) { - pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gc->full_name); - ret = -ENODEV; - goto err1; + nr_cells = size / sizeof(u32); + + for (i = 0; i < nr_cells; gpio_index++) { + const phandle *gpio_phandle; + + gpio_phandle = gpios + i; + gpio_spec = gpio_phandle + 1; + + /* one cell hole in the gpios = <>; */ + if (!*gpio_phandle) { + if (gpio_index == index) + return -ENOENT; + i++; + continue; + } + + gc = of_find_node_by_phandle(*gpio_phandle); + if (!gc) { + pr_debug("%s: could not find phandle for gpios\n", + np->full_name); + goto err0; + } + + of_gc = gc->data; + if (!of_gc) { + pr_debug("%s: gpio controller %s isn't registered\n", + np->full_name, gc->full_name); + goto err1; + } + + gpio_cells = of_get_property(gc, "#gpio-cells", &size); + if (!gpio_cells || size != sizeof(*gpio_cells) || + *gpio_cells != of_gc->gpio_cells) { + pr_debug("%s: wrong #gpio-cells for %s\n", + np->full_name, gc->full_name); + goto err1; + } + + /* Next phandle is at phandle cells + #gpio-cells */ + i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells; + if (i >= nr_cells + 1) { + pr_debug("%s: insufficient gpio-spec length\n", + np->full_name); + goto err1; + } + + if (gpio_index == index) + break; + + of_gc = NULL; + of_node_put(gc); } - gpio_cells = of_get_property(gc, "#gpio-cells", &size); - if (!gpio_cells || size != sizeof(*gpio_cells) || - *gpio_cells != of_gc->gpio_cells) { - pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gc->full_name); - ret = -EINVAL; - goto err1; + if (!of_gc) { + ret = -ENOENT; + goto err0; } ret = of_gc->xlate(of_gc, np, gpio_spec); diff --git a/trunk/drivers/spi/mpc52xx_psc_spi.c b/trunk/drivers/spi/mpc52xx_psc_spi.c index 25eda71f4bf4..cdb3d3191719 100644 --- a/trunk/drivers/spi/mpc52xx_psc_spi.c +++ b/trunk/drivers/spi/mpc52xx_psc_spi.c @@ -108,13 +108,13 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) * Because psc->ccr is defined as 16bit register instead of 32bit * just set the lower byte of BitClkDiv */ - ccr = in_be16(&psc->ccr); + ccr = in_be16((u16 __iomem *)&psc->ccr); ccr &= 0xFF00; if (cs->speed_hz) ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; else /* by default SPI Clk 1MHz */ ccr |= (MCLK / 1000000 - 1) & 0xFF; - out_be16(&psc->ccr, ccr); + out_be16((u16 __iomem *)&psc->ccr, ccr); mps->bits_per_word = cs->bits_per_word; if (mps->activate_cs) @@ -347,7 +347,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) /* Configure 8bit codec mode as a SPI master and use EOF flags */ /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ out_be32(&psc->sicr, 0x0180C800); - out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */ + out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */ /* Set 2ms DTL delay */ out_8(&psc->ctur, 0x00); diff --git a/trunk/include/linux/of.h b/trunk/include/linux/of.h index e2488f5e7cb2..79886ade070f 100644 --- a/trunk/include/linux/of.h +++ b/trunk/include/linux/of.h @@ -71,8 +71,5 @@ extern int of_n_size_cells(struct device_node *np); extern const struct of_device_id *of_match_node( const struct of_device_id *matches, const struct device_node *node); extern int of_modalias_node(struct device_node *node, char *modalias, int len); -extern int of_parse_phandles_with_args(struct device_node *np, - const char *list_name, const char *cells_name, int index, - struct device_node **out_node, const void **out_args); #endif /* _LINUX_OF_H */