aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:31:42 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:31:42 -0500
commitdde0013782dbd09e1cc68ca03860f3a62b03cb34 (patch)
tree5be40012944c0fab834a385f2410eaa60e2b0d6e
parentf3aafa6c2535d36542a6dfc8647cd2fdb5999648 (diff)
parenta99824f327c748b2753f4fa570eb1fefcd6a9c4d (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/Kconfig6
-rw-r--r--arch/powerpc/mm/mem.c33
-rw-r--r--arch/powerpc/platforms/cell/iommu.c48
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c12
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c49
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c21
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h5
-rw-r--r--arch/powerpc/platforms/powermac/feature.c11
-rw-r--r--drivers/macintosh/smu.c25
-rw-r--r--include/asm-powerpc/pmac_feature.h8
-rw-r--r--kernel/resource.c2
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
272config ARCH_ENABLE_MEMORY_HOTPLUG 272config ARCH_ENABLE_MEMORY_HOTPLUG
273 def_bool y 273 def_bool y
274 274
275config ARCH_HAS_WALK_MEMORY
276 def_bool y
277
278config ARCH_ENABLE_MEMORY_HOTREMOVE
279 def_bool y
280
275config KEXEC 281config 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
133int 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 */
144out:
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 */
158int
159walk_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
134void show_mem(void) 167void 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)
789static u64 cell_iommu_get_fixed_address(struct device *dev) 790static 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(&current->mm->mmap_sem); 381 up_read(&current->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(&current->mm->mmap_sem); 385 down_read(&current->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
791out: 795out_unlock:
792 spu_release(ctx); 796 spu_release(ctx);
793 797out:
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
937out: 943out_unlock:
938 spu_release(ctx); 944 spu_release(ctx);
945out:
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);
1797out: 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 1811out:
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}
3031EXPORT_SYMBOL(pmac_resume_agp_for_card); 3035EXPORT_SYMBOL(pmac_resume_agp_for_card);
3036
3037int 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 */
402extern 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
229EXPORT_SYMBOL(release_resource); 229EXPORT_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.