diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:31:42 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:31:42 -0500 |
commit | dde0013782dbd09e1cc68ca03860f3a62b03cb34 (patch) | |
tree | 5be40012944c0fab834a385f2410eaa60e2b0d6e | |
parent | f3aafa6c2535d36542a6dfc8647cd2fdb5999648 (diff) | |
parent | a99824f327c748b2753f4fa570eb1fefcd6a9c4d (diff) |
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
[POWERPC] Add arch-specific walk_memory_remove() for 64-bit powerpc
[POWERPC] Enable hotplug memory remove for 64-bit powerpc
[POWERPC] Add remove_memory() for 64-bit powerpc
[POWERPC] Make cell IOMMU fixed mapping printk more useful
[POWERPC] Fix potential cell IOMMU bug when switching back to default DMA ops
[POWERPC] Don't enable cell IOMMU fixed mapping if there are no dma-ranges
[POWERPC] Fix cell IOMMU null pointer explosion on old firmwares
[POWERPC] spufs: Fix timing dependent false return from spufs_run_spu
[POWERPC] spufs: No need to have a runnable SPU for libassist update
[POWERPC] spufs: Update SPU_Status[CISHP] in backing runcntl write
[POWERPC] spufs: Fix state_mutex leaks
[POWERPC] Disable G5 NAP mode during SMU commands on U3
-rw-r--r-- | arch/powerpc/Kconfig | 6 | ||||
-rw-r--r-- | arch/powerpc/mm/mem.c | 33 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/iommu.c | 48 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/backing_ops.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/fault.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 49 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 21 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/feature.c | 11 | ||||
-rw-r--r-- | drivers/macintosh/smu.c | 25 | ||||
-rw-r--r-- | include/asm-powerpc/pmac_feature.h | 8 | ||||
-rw-r--r-- | kernel/resource.c | 2 |
12 files changed, 166 insertions, 60 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 8dcac0b22d68..26b963c33c88 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -272,6 +272,12 @@ config HOTPLUG_CPU | |||
272 | config ARCH_ENABLE_MEMORY_HOTPLUG | 272 | config ARCH_ENABLE_MEMORY_HOTPLUG |
273 | def_bool y | 273 | def_bool y |
274 | 274 | ||
275 | config ARCH_HAS_WALK_MEMORY | ||
276 | def_bool y | ||
277 | |||
278 | config ARCH_ENABLE_MEMORY_HOTREMOVE | ||
279 | def_bool y | ||
280 | |||
275 | config KEXEC | 281 | config KEXEC |
276 | bool "kexec system call (EXPERIMENTAL)" | 282 | bool "kexec system call (EXPERIMENTAL)" |
277 | depends on (PPC_PRPMC2800 || PPC_MULTIPLATFORM) && EXPERIMENTAL | 283 | depends on (PPC_PRPMC2800 || PPC_MULTIPLATFORM) && EXPERIMENTAL |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 93a5c53e3423..be5c506779a7 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -129,6 +129,39 @@ int __devinit arch_add_memory(int nid, u64 start, u64 size) | |||
129 | return __add_pages(zone, start_pfn, nr_pages); | 129 | return __add_pages(zone, start_pfn, nr_pages); |
130 | } | 130 | } |
131 | 131 | ||
132 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
133 | int remove_memory(u64 start, u64 size) | ||
134 | { | ||
135 | unsigned long start_pfn, end_pfn; | ||
136 | int ret; | ||
137 | |||
138 | start_pfn = start >> PAGE_SHIFT; | ||
139 | end_pfn = start_pfn + (size >> PAGE_SHIFT); | ||
140 | ret = offline_pages(start_pfn, end_pfn, 120 * HZ); | ||
141 | if (ret) | ||
142 | goto out; | ||
143 | /* Arch-specific calls go here - next patch */ | ||
144 | out: | ||
145 | return ret; | ||
146 | } | ||
147 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
148 | |||
149 | /* | ||
150 | * walk_memory_resource() needs to make sure there is no holes in a given | ||
151 | * memory range. On PPC64, since this range comes from /sysfs, the range | ||
152 | * is guaranteed to be valid, non-overlapping and can not contain any | ||
153 | * holes. By the time we get here (memory add or remove), /proc/device-tree | ||
154 | * is updated and correct. Only reason we need to check against device-tree | ||
155 | * would be if we allow user-land to specify a memory range through a | ||
156 | * system call/ioctl etc. instead of doing offline/online through /sysfs. | ||
157 | */ | ||
158 | int | ||
159 | walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, | ||
160 | int (*func)(unsigned long, unsigned long, void *)) | ||
161 | { | ||
162 | return (*func)(start_pfn, nr_pages, arg); | ||
163 | } | ||
164 | |||
132 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 165 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
133 | 166 | ||
134 | void show_mem(void) | 167 | void show_mem(void) |
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index df330666ccc9..edab631a8dcb 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/notifier.h> | 28 | #include <linux/notifier.h> |
29 | #include <linux/of.h> | ||
29 | #include <linux/of_platform.h> | 30 | #include <linux/of_platform.h> |
30 | 31 | ||
31 | #include <asm/prom.h> | 32 | #include <asm/prom.h> |
@@ -789,18 +790,16 @@ static int __init cell_iommu_init_disabled(void) | |||
789 | static u64 cell_iommu_get_fixed_address(struct device *dev) | 790 | static u64 cell_iommu_get_fixed_address(struct device *dev) |
790 | { | 791 | { |
791 | u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR; | 792 | u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR; |
792 | struct device_node *tmp, *np; | 793 | struct device_node *np; |
793 | const u32 *ranges = NULL; | 794 | const u32 *ranges = NULL; |
794 | int i, len, best; | 795 | int i, len, best; |
795 | 796 | ||
796 | np = dev->archdata.of_node; | 797 | np = of_node_get(dev->archdata.of_node); |
797 | of_node_get(np); | 798 | while (np) { |
798 | ranges = of_get_property(np, "dma-ranges", &len); | ||
799 | while (!ranges && np) { | ||
800 | tmp = of_get_parent(np); | ||
801 | of_node_put(np); | ||
802 | np = tmp; | ||
803 | ranges = of_get_property(np, "dma-ranges", &len); | 799 | ranges = of_get_property(np, "dma-ranges", &len); |
800 | if (ranges) | ||
801 | break; | ||
802 | np = of_get_next_parent(np); | ||
804 | } | 803 | } |
805 | 804 | ||
806 | if (!ranges) { | 805 | if (!ranges) { |
@@ -842,19 +841,18 @@ static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask) | |||
842 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | 841 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) |
843 | return -EIO; | 842 | return -EIO; |
844 | 843 | ||
845 | if (dma_mask == DMA_BIT_MASK(64)) { | 844 | if (dma_mask == DMA_BIT_MASK(64) && |
846 | if (cell_iommu_get_fixed_address(dev) == OF_BAD_ADDR) | 845 | cell_iommu_get_fixed_address(dev) != OF_BAD_ADDR) |
847 | dev_dbg(dev, "iommu: 64-bit OK, but bad addr\n"); | 846 | { |
848 | else { | 847 | dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n"); |
849 | dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n"); | 848 | set_dma_ops(dev, &dma_iommu_fixed_ops); |
850 | set_dma_ops(dev, &dma_iommu_fixed_ops); | ||
851 | cell_dma_dev_setup(dev); | ||
852 | } | ||
853 | } else { | 849 | } else { |
854 | dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); | 850 | dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); |
855 | set_dma_ops(dev, get_pci_dma_ops()); | 851 | set_dma_ops(dev, get_pci_dma_ops()); |
856 | } | 852 | } |
857 | 853 | ||
854 | cell_dma_dev_setup(dev); | ||
855 | |||
858 | *dev->dma_mask = dma_mask; | 856 | *dev->dma_mask = dma_mask; |
859 | 857 | ||
860 | return 0; | 858 | return 0; |
@@ -918,6 +916,18 @@ static int __init cell_iommu_fixed_mapping_init(void) | |||
918 | return -1; | 916 | return -1; |
919 | } | 917 | } |
920 | 918 | ||
919 | /* We must have dma-ranges properties for fixed mapping to work */ | ||
920 | for (np = NULL; (np = of_find_all_nodes(np));) { | ||
921 | if (of_find_property(np, "dma-ranges", NULL)) | ||
922 | break; | ||
923 | } | ||
924 | of_node_put(np); | ||
925 | |||
926 | if (!np) { | ||
927 | pr_debug("iommu: no dma-ranges found, no fixed mapping\n"); | ||
928 | return -1; | ||
929 | } | ||
930 | |||
921 | /* The default setup is to have the fixed mapping sit after the | 931 | /* The default setup is to have the fixed mapping sit after the |
922 | * dynamic region, so find the top of the largest IOMMU window | 932 | * dynamic region, so find the top of the largest IOMMU window |
923 | * on any axon, then add the size of RAM and that's our max value. | 933 | * on any axon, then add the size of RAM and that's our max value. |
@@ -981,8 +991,8 @@ static int __init cell_iommu_fixed_mapping_init(void) | |||
981 | dsize = htab_size_bytes; | 991 | dsize = htab_size_bytes; |
982 | } | 992 | } |
983 | 993 | ||
984 | pr_debug("iommu: setting up %d, dynamic window %lx-%lx " \ | 994 | printk(KERN_DEBUG "iommu: node %d, dynamic window 0x%lx-0x%lx " |
985 | "fixed window %lx-%lx\n", iommu->nid, dbase, | 995 | "fixed window 0x%lx-0x%lx\n", iommu->nid, dbase, |
986 | dbase + dsize, fbase, fbase + fsize); | 996 | dbase + dsize, fbase, fbase + fsize); |
987 | 997 | ||
988 | cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize); | 998 | cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize); |
@@ -998,8 +1008,6 @@ static int __init cell_iommu_fixed_mapping_init(void) | |||
998 | dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; | 1008 | dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; |
999 | set_pci_dma_ops(&dma_iommu_ops); | 1009 | set_pci_dma_ops(&dma_iommu_ops); |
1000 | 1010 | ||
1001 | printk(KERN_DEBUG "IOMMU fixed mapping established.\n"); | ||
1002 | |||
1003 | return 0; | 1011 | return 0; |
1004 | } | 1012 | } |
1005 | 1013 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index 50d98a154aaf..64eb15b22040 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c | |||
@@ -288,6 +288,12 @@ static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val) | |||
288 | spin_lock(&ctx->csa.register_lock); | 288 | spin_lock(&ctx->csa.register_lock); |
289 | ctx->csa.prob.spu_runcntl_RW = val; | 289 | ctx->csa.prob.spu_runcntl_RW = val; |
290 | if (val & SPU_RUNCNTL_RUNNABLE) { | 290 | if (val & SPU_RUNCNTL_RUNNABLE) { |
291 | ctx->csa.prob.spu_status_R &= | ||
292 | ~SPU_STATUS_STOPPED_BY_STOP & | ||
293 | ~SPU_STATUS_STOPPED_BY_HALT & | ||
294 | ~SPU_STATUS_SINGLE_STEP & | ||
295 | ~SPU_STATUS_INVALID_INSTR & | ||
296 | ~SPU_STATUS_INVALID_CH; | ||
291 | ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING; | 297 | ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING; |
292 | } else { | 298 | } else { |
293 | ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING; | 299 | ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING; |
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index eff4d291ba85..e46d300e21a5 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c | |||
@@ -108,7 +108,7 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
108 | u64 ea, dsisr, access; | 108 | u64 ea, dsisr, access; |
109 | unsigned long flags; | 109 | unsigned long flags; |
110 | unsigned flt = 0; | 110 | unsigned flt = 0; |
111 | int ret, ret2; | 111 | int ret; |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * dar and dsisr get passed from the registers | 114 | * dar and dsisr get passed from the registers |
@@ -148,13 +148,10 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
148 | ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); | 148 | ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); |
149 | 149 | ||
150 | /* | 150 | /* |
151 | * If spu_acquire fails due to a pending signal we just want to return | 151 | * This is nasty: we need the state_mutex for all the bookkeeping even |
152 | * EINTR to userspace even if that means missing the dma restart or | 152 | * if the syscall was interrupted by a signal. ewww. |
153 | * updating the page fault statistics. | ||
154 | */ | 153 | */ |
155 | ret2 = spu_acquire(ctx); | 154 | mutex_lock(&ctx->state_mutex); |
156 | if (ret2) | ||
157 | goto out; | ||
158 | 155 | ||
159 | /* | 156 | /* |
160 | * Clear dsisr under ctxt lock after handling the fault, so that | 157 | * Clear dsisr under ctxt lock after handling the fault, so that |
@@ -185,7 +182,6 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
185 | } else | 182 | } else |
186 | spufs_handle_event(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); | 183 | spufs_handle_event(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); |
187 | 184 | ||
188 | out: | ||
189 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); | 185 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); |
190 | return ret; | 186 | return ret; |
191 | } | 187 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index e393144d533d..c66c3756970d 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -358,6 +358,7 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, | |||
358 | { | 358 | { |
359 | struct spu_context *ctx = vma->vm_file->private_data; | 359 | struct spu_context *ctx = vma->vm_file->private_data; |
360 | unsigned long area, offset = address - vma->vm_start; | 360 | unsigned long area, offset = address - vma->vm_start; |
361 | int ret = 0; | ||
361 | 362 | ||
362 | spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); | 363 | spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); |
363 | 364 | ||
@@ -379,7 +380,7 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, | |||
379 | if (ctx->state == SPU_STATE_SAVED) { | 380 | if (ctx->state == SPU_STATE_SAVED) { |
380 | up_read(¤t->mm->mmap_sem); | 381 | up_read(¤t->mm->mmap_sem); |
381 | spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); | 382 | spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); |
382 | spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); | 383 | ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); |
383 | spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); | 384 | spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); |
384 | down_read(¤t->mm->mmap_sem); | 385 | down_read(¤t->mm->mmap_sem); |
385 | } else { | 386 | } else { |
@@ -388,7 +389,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, | |||
388 | spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); | 389 | spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); |
389 | } | 390 | } |
390 | 391 | ||
391 | spu_release(ctx); | 392 | if (!ret) |
393 | spu_release(ctx); | ||
392 | return NOPFN_REFAULT; | 394 | return NOPFN_REFAULT; |
393 | } | 395 | } |
394 | 396 | ||
@@ -755,23 +757,25 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, | |||
755 | 757 | ||
756 | count = spu_acquire(ctx); | 758 | count = spu_acquire(ctx); |
757 | if (count) | 759 | if (count) |
758 | return count; | 760 | goto out; |
759 | 761 | ||
760 | /* wait only for the first element */ | 762 | /* wait only for the first element */ |
761 | count = 0; | 763 | count = 0; |
762 | if (file->f_flags & O_NONBLOCK) { | 764 | if (file->f_flags & O_NONBLOCK) { |
763 | if (!spu_ibox_read(ctx, &ibox_data)) | 765 | if (!spu_ibox_read(ctx, &ibox_data)) { |
764 | count = -EAGAIN; | 766 | count = -EAGAIN; |
767 | goto out_unlock; | ||
768 | } | ||
765 | } else { | 769 | } else { |
766 | count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); | 770 | count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); |
771 | if (count) | ||
772 | goto out; | ||
767 | } | 773 | } |
768 | if (count) | ||
769 | goto out; | ||
770 | 774 | ||
771 | /* if we can't write at all, return -EFAULT */ | 775 | /* if we can't write at all, return -EFAULT */ |
772 | count = __put_user(ibox_data, udata); | 776 | count = __put_user(ibox_data, udata); |
773 | if (count) | 777 | if (count) |
774 | goto out; | 778 | goto out_unlock; |
775 | 779 | ||
776 | for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { | 780 | for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { |
777 | int ret; | 781 | int ret; |
@@ -788,9 +792,9 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, | |||
788 | break; | 792 | break; |
789 | } | 793 | } |
790 | 794 | ||
791 | out: | 795 | out_unlock: |
792 | spu_release(ctx); | 796 | spu_release(ctx); |
793 | 797 | out: | |
794 | return count; | 798 | return count; |
795 | } | 799 | } |
796 | 800 | ||
@@ -905,7 +909,7 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, | |||
905 | 909 | ||
906 | count = spu_acquire(ctx); | 910 | count = spu_acquire(ctx); |
907 | if (count) | 911 | if (count) |
908 | return count; | 912 | goto out; |
909 | 913 | ||
910 | /* | 914 | /* |
911 | * make sure we can at least write one element, by waiting | 915 | * make sure we can at least write one element, by waiting |
@@ -913,14 +917,16 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, | |||
913 | */ | 917 | */ |
914 | count = 0; | 918 | count = 0; |
915 | if (file->f_flags & O_NONBLOCK) { | 919 | if (file->f_flags & O_NONBLOCK) { |
916 | if (!spu_wbox_write(ctx, wbox_data)) | 920 | if (!spu_wbox_write(ctx, wbox_data)) { |
917 | count = -EAGAIN; | 921 | count = -EAGAIN; |
922 | goto out_unlock; | ||
923 | } | ||
918 | } else { | 924 | } else { |
919 | count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); | 925 | count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); |
926 | if (count) | ||
927 | goto out; | ||
920 | } | 928 | } |
921 | 929 | ||
922 | if (count) | ||
923 | goto out; | ||
924 | 930 | ||
925 | /* write as much as possible */ | 931 | /* write as much as possible */ |
926 | for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { | 932 | for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) { |
@@ -934,8 +940,9 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, | |||
934 | break; | 940 | break; |
935 | } | 941 | } |
936 | 942 | ||
937 | out: | 943 | out_unlock: |
938 | spu_release(ctx); | 944 | spu_release(ctx); |
945 | out: | ||
939 | return count; | 946 | return count; |
940 | } | 947 | } |
941 | 948 | ||
@@ -1598,12 +1605,11 @@ static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, | |||
1598 | } else { | 1605 | } else { |
1599 | ret = spufs_wait(ctx->mfc_wq, | 1606 | ret = spufs_wait(ctx->mfc_wq, |
1600 | spufs_read_mfc_tagstatus(ctx, &status)); | 1607 | spufs_read_mfc_tagstatus(ctx, &status)); |
1608 | if (ret) | ||
1609 | goto out; | ||
1601 | } | 1610 | } |
1602 | spu_release(ctx); | 1611 | spu_release(ctx); |
1603 | 1612 | ||
1604 | if (ret) | ||
1605 | goto out; | ||
1606 | |||
1607 | ret = 4; | 1613 | ret = 4; |
1608 | if (copy_to_user(buffer, &status, 4)) | 1614 | if (copy_to_user(buffer, &status, 4)) |
1609 | ret = -EFAULT; | 1615 | ret = -EFAULT; |
@@ -1732,6 +1738,8 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | |||
1732 | int status; | 1738 | int status; |
1733 | ret = spufs_wait(ctx->mfc_wq, | 1739 | ret = spufs_wait(ctx->mfc_wq, |
1734 | spu_send_mfc_command(ctx, cmd, &status)); | 1740 | spu_send_mfc_command(ctx, cmd, &status)); |
1741 | if (ret) | ||
1742 | goto out; | ||
1735 | if (status) | 1743 | if (status) |
1736 | ret = status; | 1744 | ret = status; |
1737 | } | 1745 | } |
@@ -1785,7 +1793,7 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id) | |||
1785 | 1793 | ||
1786 | ret = spu_acquire(ctx); | 1794 | ret = spu_acquire(ctx); |
1787 | if (ret) | 1795 | if (ret) |
1788 | return ret; | 1796 | goto out; |
1789 | #if 0 | 1797 | #if 0 |
1790 | /* this currently hangs */ | 1798 | /* this currently hangs */ |
1791 | ret = spufs_wait(ctx->mfc_wq, | 1799 | ret = spufs_wait(ctx->mfc_wq, |
@@ -1794,12 +1802,13 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id) | |||
1794 | goto out; | 1802 | goto out; |
1795 | ret = spufs_wait(ctx->mfc_wq, | 1803 | ret = spufs_wait(ctx->mfc_wq, |
1796 | ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); | 1804 | ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); |
1797 | out: | 1805 | if (ret) |
1806 | goto out; | ||
1798 | #else | 1807 | #else |
1799 | ret = 0; | 1808 | ret = 0; |
1800 | #endif | 1809 | #endif |
1801 | spu_release(ctx); | 1810 | spu_release(ctx); |
1802 | 1811 | out: | |
1803 | return ret; | 1812 | return ret; |
1804 | } | 1813 | } |
1805 | 1814 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index b4814c740d8a..fca22e18069a 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -53,7 +53,7 @@ int spu_stopped(struct spu_context *ctx, u32 *stat) | |||
53 | 53 | ||
54 | stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | | 54 | stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | |
55 | SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; | 55 | SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; |
56 | if (*stat & stopped) | 56 | if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped)) |
57 | return 1; | 57 | return 1; |
58 | 58 | ||
59 | dsisr = ctx->csa.dsisr; | 59 | dsisr = ctx->csa.dsisr; |
@@ -354,8 +354,15 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | |||
354 | 354 | ||
355 | do { | 355 | do { |
356 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); | 356 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); |
357 | if (unlikely(ret)) | 357 | if (unlikely(ret)) { |
358 | /* | ||
359 | * This is nasty: we need the state_mutex for all the | ||
360 | * bookkeeping even if the syscall was interrupted by | ||
361 | * a signal. ewww. | ||
362 | */ | ||
363 | mutex_lock(&ctx->state_mutex); | ||
358 | break; | 364 | break; |
365 | } | ||
359 | spu = ctx->spu; | 366 | spu = ctx->spu; |
360 | if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, | 367 | if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, |
361 | &ctx->sched_flags))) { | 368 | &ctx->sched_flags))) { |
@@ -388,16 +395,14 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | |||
388 | SPU_STATUS_STOPPED_BY_HALT | | 395 | SPU_STATUS_STOPPED_BY_HALT | |
389 | SPU_STATUS_SINGLE_STEP))); | 396 | SPU_STATUS_SINGLE_STEP))); |
390 | 397 | ||
391 | if ((status & SPU_STATUS_STOPPED_BY_STOP) && | ||
392 | (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && | ||
393 | (ctx->state == SPU_STATE_RUNNABLE)) | ||
394 | ctx->stats.libassist++; | ||
395 | |||
396 | |||
397 | spu_disable_spu(ctx); | 398 | spu_disable_spu(ctx); |
398 | ret = spu_run_fini(ctx, npc, &status); | 399 | ret = spu_run_fini(ctx, npc, &status); |
399 | spu_yield(ctx); | 400 | spu_yield(ctx); |
400 | 401 | ||
402 | if ((status & SPU_STATUS_STOPPED_BY_STOP) && | ||
403 | (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) | ||
404 | ctx->stats.libassist++; | ||
405 | |||
401 | if ((ret == 0) || | 406 | if ((ret == 0) || |
402 | ((ret == -ERESTARTSYS) && | 407 | ((ret == -ERESTARTSYS) && |
403 | ((status & SPU_STATUS_STOPPED_BY_HALT) || | 408 | ((status & SPU_STATUS_STOPPED_BY_HALT) || |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 795a1b52538b..2c2fe3c07d72 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -268,6 +268,9 @@ extern char *isolated_loader; | |||
268 | * Same as wait_event_interruptible(), except that here | 268 | * Same as wait_event_interruptible(), except that here |
269 | * we need to call spu_release(ctx) before sleeping, and | 269 | * we need to call spu_release(ctx) before sleeping, and |
270 | * then spu_acquire(ctx) when awoken. | 270 | * then spu_acquire(ctx) when awoken. |
271 | * | ||
272 | * Returns with state_mutex re-acquired when successfull or | ||
273 | * with -ERESTARTSYS and the state_mutex dropped when interrupted. | ||
271 | */ | 274 | */ |
272 | 275 | ||
273 | #define spufs_wait(wq, condition) \ | 276 | #define spufs_wait(wq, condition) \ |
@@ -278,11 +281,11 @@ extern char *isolated_loader; | |||
278 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | 281 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ |
279 | if (condition) \ | 282 | if (condition) \ |
280 | break; \ | 283 | break; \ |
284 | spu_release(ctx); \ | ||
281 | if (signal_pending(current)) { \ | 285 | if (signal_pending(current)) { \ |
282 | __ret = -ERESTARTSYS; \ | 286 | __ret = -ERESTARTSYS; \ |
283 | break; \ | 287 | break; \ |
284 | } \ | 288 | } \ |
285 | spu_release(ctx); \ | ||
286 | schedule(); \ | 289 | schedule(); \ |
287 | __ret = spu_acquire(ctx); \ | 290 | __ret = spu_acquire(ctx); \ |
288 | if (__ret) \ | 291 | if (__ret) \ |
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index ba931be2175c..5169ecc37123 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c | |||
@@ -2565,6 +2565,8 @@ static void __init probe_uninorth(void) | |||
2565 | 2565 | ||
2566 | /* Locate core99 Uni-N */ | 2566 | /* Locate core99 Uni-N */ |
2567 | uninorth_node = of_find_node_by_name(NULL, "uni-n"); | 2567 | uninorth_node = of_find_node_by_name(NULL, "uni-n"); |
2568 | uninorth_maj = 1; | ||
2569 | |||
2568 | /* Locate G5 u3 */ | 2570 | /* Locate G5 u3 */ |
2569 | if (uninorth_node == NULL) { | 2571 | if (uninorth_node == NULL) { |
2570 | uninorth_node = of_find_node_by_name(NULL, "u3"); | 2572 | uninorth_node = of_find_node_by_name(NULL, "u3"); |
@@ -2575,8 +2577,10 @@ static void __init probe_uninorth(void) | |||
2575 | uninorth_node = of_find_node_by_name(NULL, "u4"); | 2577 | uninorth_node = of_find_node_by_name(NULL, "u4"); |
2576 | uninorth_maj = 4; | 2578 | uninorth_maj = 4; |
2577 | } | 2579 | } |
2578 | if (uninorth_node == NULL) | 2580 | if (uninorth_node == NULL) { |
2581 | uninorth_maj = 0; | ||
2579 | return; | 2582 | return; |
2583 | } | ||
2580 | 2584 | ||
2581 | addrp = of_get_property(uninorth_node, "reg", NULL); | 2585 | addrp = of_get_property(uninorth_node, "reg", NULL); |
2582 | if (addrp == NULL) | 2586 | if (addrp == NULL) |
@@ -3029,3 +3033,8 @@ void pmac_resume_agp_for_card(struct pci_dev *dev) | |||
3029 | pmac_agp_resume(pmac_agp_bridge); | 3033 | pmac_agp_resume(pmac_agp_bridge); |
3030 | } | 3034 | } |
3031 | EXPORT_SYMBOL(pmac_resume_agp_for_card); | 3035 | EXPORT_SYMBOL(pmac_resume_agp_for_card); |
3036 | |||
3037 | int pmac_get_uninorth_variant(void) | ||
3038 | { | ||
3039 | return uninorth_maj; | ||
3040 | } | ||
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 8ba49385c3ff..77ad192962c5 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c | |||
@@ -85,6 +85,7 @@ struct smu_device { | |||
85 | u32 cmd_buf_abs; /* command buffer absolute */ | 85 | u32 cmd_buf_abs; /* command buffer absolute */ |
86 | struct list_head cmd_list; | 86 | struct list_head cmd_list; |
87 | struct smu_cmd *cmd_cur; /* pending command */ | 87 | struct smu_cmd *cmd_cur; /* pending command */ |
88 | int broken_nap; | ||
88 | struct list_head cmd_i2c_list; | 89 | struct list_head cmd_i2c_list; |
89 | struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */ | 90 | struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */ |
90 | struct timer_list i2c_timer; | 91 | struct timer_list i2c_timer; |
@@ -135,6 +136,19 @@ static void smu_start_cmd(void) | |||
135 | fend = faddr + smu->cmd_buf->length + 2; | 136 | fend = faddr + smu->cmd_buf->length + 2; |
136 | flush_inval_dcache_range(faddr, fend); | 137 | flush_inval_dcache_range(faddr, fend); |
137 | 138 | ||
139 | |||
140 | /* We also disable NAP mode for the duration of the command | ||
141 | * on U3 based machines. | ||
142 | * This is slightly racy as it can be written back to 1 by a sysctl | ||
143 | * but that never happens in practice. There seem to be an issue with | ||
144 | * U3 based machines such as the iMac G5 where napping for the | ||
145 | * whole duration of the command prevents the SMU from fetching it | ||
146 | * from memory. This might be related to the strange i2c based | ||
147 | * mechanism the SMU uses to access memory. | ||
148 | */ | ||
149 | if (smu->broken_nap) | ||
150 | powersave_nap = 0; | ||
151 | |||
138 | /* This isn't exactly a DMA mapping here, I suspect | 152 | /* This isn't exactly a DMA mapping here, I suspect |
139 | * the SMU is actually communicating with us via i2c to the | 153 | * the SMU is actually communicating with us via i2c to the |
140 | * northbridge or the CPU to access RAM. | 154 | * northbridge or the CPU to access RAM. |
@@ -211,6 +225,10 @@ static irqreturn_t smu_db_intr(int irq, void *arg) | |||
211 | misc = cmd->misc; | 225 | misc = cmd->misc; |
212 | mb(); | 226 | mb(); |
213 | cmd->status = rc; | 227 | cmd->status = rc; |
228 | |||
229 | /* Re-enable NAP mode */ | ||
230 | if (smu->broken_nap) | ||
231 | powersave_nap = 1; | ||
214 | bail: | 232 | bail: |
215 | /* Start next command if any */ | 233 | /* Start next command if any */ |
216 | smu_start_cmd(); | 234 | smu_start_cmd(); |
@@ -461,7 +479,7 @@ int __init smu_init (void) | |||
461 | if (np == NULL) | 479 | if (np == NULL) |
462 | return -ENODEV; | 480 | return -ENODEV; |
463 | 481 | ||
464 | printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR); | 482 | printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR); |
465 | 483 | ||
466 | if (smu_cmdbuf_abs == 0) { | 484 | if (smu_cmdbuf_abs == 0) { |
467 | printk(KERN_ERR "SMU: Command buffer not allocated !\n"); | 485 | printk(KERN_ERR "SMU: Command buffer not allocated !\n"); |
@@ -533,6 +551,11 @@ int __init smu_init (void) | |||
533 | goto fail; | 551 | goto fail; |
534 | } | 552 | } |
535 | 553 | ||
554 | /* U3 has an issue with NAP mode when issuing SMU commands */ | ||
555 | smu->broken_nap = pmac_get_uninorth_variant() < 4; | ||
556 | if (smu->broken_nap) | ||
557 | printk(KERN_INFO "SMU: using NAP mode workaround\n"); | ||
558 | |||
536 | sys_ctrler = SYS_CTRLER_SMU; | 559 | sys_ctrler = SYS_CTRLER_SMU; |
537 | return 0; | 560 | return 0; |
538 | 561 | ||
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h index 26bcb0aa164a..877c35a4356e 100644 --- a/include/asm-powerpc/pmac_feature.h +++ b/include/asm-powerpc/pmac_feature.h | |||
@@ -392,6 +392,14 @@ extern u32 __iomem *uninorth_base; | |||
392 | #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) | 392 | #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) |
393 | #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) | 393 | #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) |
394 | 394 | ||
395 | /* Uninorth variant: | ||
396 | * | ||
397 | * 0 = not uninorth | ||
398 | * 1 = U1.x or U2.x | ||
399 | * 3 = U3 | ||
400 | * 4 = U4 | ||
401 | */ | ||
402 | extern int pmac_get_uninorth_variant(void); | ||
395 | 403 | ||
396 | #endif /* __ASM_POWERPC_PMAC_FEATURE_H */ | 404 | #endif /* __ASM_POWERPC_PMAC_FEATURE_H */ |
397 | #endif /* __KERNEL__ */ | 405 | #endif /* __KERNEL__ */ |
diff --git a/kernel/resource.c b/kernel/resource.c index 2eb553d9b517..82aea814d409 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -228,7 +228,7 @@ int release_resource(struct resource *old) | |||
228 | 228 | ||
229 | EXPORT_SYMBOL(release_resource); | 229 | EXPORT_SYMBOL(release_resource); |
230 | 230 | ||
231 | #ifdef CONFIG_MEMORY_HOTPLUG | 231 | #if defined(CONFIG_MEMORY_HOTPLUG) && !defined(CONFIG_ARCH_HAS_WALK_MEMORY) |
232 | /* | 232 | /* |
233 | * Finds the lowest memory reosurce exists within [res->start.res->end) | 233 | * Finds the lowest memory reosurce exists within [res->start.res->end) |
234 | * the caller must specify res->start, res->end, res->flags. | 234 | * the caller must specify res->start, res->end, res->flags. |