Skip to contentSkip to conversation

Cell updates for powerpc.git

PATCH New Arnd Bergmann 1 participant 9 messages Dec 9, 2005

Subsystems (3)
lore
Share & tools
lore
#0 lore raw
Quoted 3 lines · Paul Mackerras

I have put patches 1..7 and 9 into the powerpc.git tree. Please address Milton's comments on patches 3, 5, 8 and 10.

Milton's comment for patch 5 was about the patch comment, I don't think I can address that any more.

Here come updated version for patches 8 and 10, a fix for patch 3 and a number of other patches that have come up in the last week. All patches apply on top of today's powerpc.git tree.

More patches will be coming to address the concerns of Al Viro about spufs.

Thanks,

	Arnd <><
#2 lore raw

PATCH 2/8 spufs: trivial compile fix

One of my last patches contained a broken line
from splitting out some other changes, this
restores a working version.

arch/powerpc/platforms/cell/spufs/sched.c +1 -1
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/sched.c
===================================================================
@@ -45,7 +45,7 @@
 #include <asm/spu_csa.h>
 #include "spufs.h"
 
-#define SPU_MIN_TIMESLICE 	(100 * HZ / 1000))
+#define SPU_MIN_TIMESLICE 	(100 * HZ / 1000)
 
 #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
 struct spu_prio_array {

--

#6 lore raw

PATCH 6/8 cell: add iommu support for larger memory

In reply to Arnd Bergmann

So far, the iommu code was hardwired to a linear mapping between 0x20000000 and 0x40000000, so it could only support 512MB of RAM.

This patch still keeps the linear mapping, but looks for proper ibm,dma-window properties to set up larger windows, this makes the maximum supported RAM size 2GB.

If there is anything unusual about the dma-window properties, we fall back to the old behavior.

We also support switching off the iommu completely now with the regular iommu=off command line option.

From: [email protected]

arch/powerpc/platforms/cell/iommu.c +176 -49
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/iommu.c
===================================================================
@@ -29,6 +29,8 @@
 #include <linux/bootmem.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
 
 #include <asm/sections.h>
 #include <asm/iommu.h>
@@ -40,6 +42,7 @@
 #include <asm/abs_addr.h>
 #include <asm/system.h>
 #include <asm/ppc-pci.h>
+#include <asm/udbg.h>
 
 #include "iommu.h"
 
@@ -220,8 +223,6 @@ set_iopt_cache(void __iomem *base, unsig
 {
 	unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR;
 	unsigned long __iomem *p = base + IOC_PT_CACHE_REG;
-	pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n",
-		index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag);
 
 	out_be64(p, val);
 	out_be64(&tags[index], tag);
@@ -248,67 +249,176 @@ set_iocmd_config(void __iomem *base)
 	out_be64(p, conf | IOCMD_CONF_TE);
 }
 
-/* FIXME: get these from the device tree */
-#define ioc_base	0x20000511000ull
-#define ioc_mmio_base	0x20000510000ull
-#define ioid		0x48a
-#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */
-#define io_page_size	0x1000000
-
-static unsigned long map_iopt_entry(unsigned long address)
-{
-	switch (address >> 20) {
-	case 0x600:
-		address = 0x24020000000ull; /* spider i/o */
-		break;
-	default:
-		address += iopt_phys_offset;
-		break;
-	}
-
-	return get_iopt_entry(address, ioid, IOPT_PROT_RW);
+static void enable_mapping(void __iomem *base, void __iomem *mmio_base)
+{
+	set_iocmd_config(base);
+	set_iost_origin(mmio_base);
 }
 
-static void iommu_bus_setup_null(struct pci_bus *b) { }
 static void iommu_dev_setup_null(struct pci_dev *d) { }
+static void iommu_bus_setup_null(struct pci_bus *b) { }
+
+struct cell_iommu {
+	unsigned long base;
+	unsigned long mmio_base;
+	void __iomem *mapped_base;
+	void __iomem *mapped_mmio_base;
+};
+
+static struct cell_iommu cell_iommus[NR_CPUS];
 
 /* initialize the iommu to support a simple linear mapping
  * for each DMA window used by any device. For now, we
  * happen to know that there is only one DMA window in use,
  * starting at iopt_phys_offset. */
-static void cell_map_iommu(void)
+static void cell_do_map_iommu(struct cell_iommu *iommu,
+			      unsigned int ioid,
+			      unsigned long map_start,
+			      unsigned long map_size)
 {
-	unsigned long address;
-	void __iomem *base;
+	unsigned long io_address, real_address;
+	void __iomem *ioc_base, *ioc_mmio_base;
 	ioste ioste;
 	unsigned long index;
 
-	base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE);
-	pr_debug("%lx mapped to %p\n", ioc_base, base);
-	set_iocmd_config(base);
-	iounmap(base);
+	/* we pretend the io page table was at a very high address */
+	const unsigned long fake_iopt = 0x10000000000ul;
+	const unsigned long io_page_size = 0x1000000; /* use 16M pages */
+	const unsigned long io_segment_size = 0x10000000; /* 256M */
+
+	ioc_base = iommu->mapped_base;
+	ioc_mmio_base = iommu->mapped_mmio_base;
+
+	for (real_address = 0, io_address = 0;
+	     io_address <= map_start + map_size;
+	     real_address += io_page_size, io_address += io_page_size) {
+		ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
+		if ((real_address % io_segment_size) == 0) /* segment start */
+			set_iost_cache(ioc_mmio_base,
+				       io_address >> 28, ioste);
+		index = get_ioc_hash_1way(ioste, io_address);
+		pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
+					 io_address, index, ioste.val);
+		set_iopt_cache(ioc_mmio_base,
+			get_ioc_hash_1way(ioste, io_address),
+			get_ioc_tag(ioste, io_address),
+			get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW));
+	}
+}
 
-	base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE);
-	pr_debug("%lx mapped to %p\n", ioc_mmio_base, base);
+static void iommu_devnode_setup(struct device_node *d)
+{
+	unsigned int *ioid;
+	unsigned long *dma_window, map_start, map_size, token;
+	struct cell_iommu *iommu;
 
-	set_iost_origin(base);
+	ioid = (unsigned int *)get_property(d, "ioid", NULL);
+	if (!ioid)
+		pr_debug("No ioid entry found !\n");
 
-	for (address = 0; address < 0x100000000ul; address += io_page_size) {
-		ioste = get_iost_entry(0x10000000000ul, address, io_page_size);
-		if ((address & 0xfffffff) == 0) /* segment start */
-			set_iost_cache(base, address >> 28, ioste);
-		index = get_ioc_hash_1way(ioste, address);
-		pr_debug("addr %08lx, index %02lx, ioste %016lx\n",
-					 address, index, ioste.val);
-		set_iopt_cache(base,
-			get_ioc_hash_1way(ioste, address),
-			get_ioc_tag(ioste, address),
-			map_iopt_entry(address));
-	}
-	iounmap(base);
+	dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL);
+	if (!dma_window)
+		pr_debug("No ibm,dma-window entry found !\n");
+
+	map_start = dma_window[1];
+	map_size = dma_window[2];
+	token = dma_window[0] >> 32;
+
+	iommu = &cell_iommus[token];
+
+	cell_do_map_iommu(iommu, *ioid, map_start, map_size);
+}
+
+static void iommu_bus_setup(struct pci_bus *b)
+{
+	struct device_node *d = (struct device_node *)b->sysdata;
+	iommu_devnode_setup(d);
+}
+
+
+static int cell_map_iommu_hardcoded(int num_nodes)
+{
+	struct cell_iommu *iommu = NULL;
+
+	pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
+
+	/* node 0 */
+	iommu = &cell_iommus[0];
+	iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE);
+
+	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+	cell_do_map_iommu(iommu, 0x048a,
+			  0x20000000ul,0x20000000ul);
+
+	if (num_nodes < 2)
+		return 0;
+
+	/* node 1 */
+	iommu = &cell_iommus[1];
+	iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE);
+	iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE);
+
+	enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
+
+	cell_do_map_iommu(iommu, 0x048a,
+			  0x20000000,0x20000000ul);
+
+	return 0;
 }
 
 
+static int cell_map_iommu(void)
+{
+	unsigned int num_nodes = 0, *node_id;
+	unsigned long *base, *mmio_base;
+	struct device_node *dn;
+	struct cell_iommu *iommu = NULL;
+
+	/* determine number of nodes (=iommus) */
+	pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__);
+	for(dn = of_find_node_by_type(NULL, "cpu");
+	    dn;
+	    dn = of_find_node_by_type(dn, "cpu")) {
+		node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+
+		if (num_nodes < *node_id)
+			num_nodes = *node_id;
+		}
+
+	num_nodes++;
+	pr_debug("%i found.\n", num_nodes);
+
+	/* map the iommu registers for each node */
+	pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__);
+	for(dn = of_find_node_by_type(NULL, "cpu");
+	    dn;
+	    dn = of_find_node_by_type(dn, "cpu")) {
+
+		node_id = (unsigned int *)get_property(dn, "node-id", NULL);
+		base = (unsigned long *)get_property(dn, "ioc-cache", NULL);
+		mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL);
+
+		if (!base || !mmio_base || !node_id)
+			return cell_map_iommu_hardcoded(num_nodes);
+
+		iommu = &cell_iommus[*node_id];
+		iommu->base = *base;
+		iommu->mmio_base = *mmio_base;
+
+		iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE);
+		iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE);
+
+		enable_mapping(iommu->mapped_base,
+			       iommu->mapped_mmio_base);
+
+		/* everything else will be done in iommu_bus_setup */
+	}
+
+	return 1;
+}
+
 static void *cell_alloc_coherent(struct device *hwdev, size_t size,
 			   dma_addr_t *dma_handle, gfp_t flag)
 {
@@ -365,11 +475,28 @@ static int cell_dma_supported(struct dev
 
 void cell_init_iommu(void)
 {
-	cell_map_iommu();
+	int setup_bus = 0;
 
-	/* Direct I/O, IOMMU off */
-	ppc_md.iommu_dev_setup = iommu_dev_setup_null;
-	ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+	if (of_find_node_by_path("/mambo")) {
+		pr_info("Not using iommu on systemsim\n");
+	} else {
+
+		if (!(of_chosen &&
+		      get_property(of_chosen, "linux,iommu-off", NULL)))
+			setup_bus = cell_map_iommu();
+
+		if (setup_bus) {
+			pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__);
+			ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+			ppc_md.iommu_bus_setup = iommu_bus_setup;
+		} else {
+			pr_debug("%s: IOMMU mapping activated, "
+				 "no device action necessary\n", __FUNCTION__);
+			/* Direct I/O, IOMMU off */
+			ppc_md.iommu_dev_setup = iommu_dev_setup_null;
+			ppc_md.iommu_bus_setup = iommu_bus_setup_null;
+		}
+	}
 
 	pci_dma_ops.alloc_coherent = cell_alloc_coherent;
 	pci_dma_ops.free_coherent = cell_free_coherent;

--

#4 lore raw

PATCH 4/8 spufs: clear dsisr on CLASS1[Mf] exception

In reply to Arnd Bergmann

Because of always clearing DSISR at spu class 1 interrupt handler, kernel may lose Class1[Mf] interrupt.

arch/powerpc/platforms/cell/spu_base.c +2 -1
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_base.c
===================================================================
@@ -240,7 +240,8 @@ spu_irq_class_1(int irq, void *data, str
 	stat  = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
 	dar   = in_be64(&spu->priv1->mfc_dar_RW);
 	dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
-	out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
+	if (stat & 2) /* mapping fault */
+		out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
 	out_be64(&spu->priv1->int_stat_class1_RW, stat);
 	spin_unlock(&spu->register_lock);
 

--

#3 lore raw

PATCH 3/8 spufs: fix hexdump format

In reply to Arnd Bergmann

Output from hexdump with "%08x" depends on HOST platform's endian. When building linux by cross toolchain, that difference makes errors.

arch/powerpc/platforms/cell/spufs/Makefile +1 -1
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spufs/Makefile
===================================================================
@@ -46,7 +46,7 @@ cmd_hexdump   = ( \
 		echo " * Do not edit!" ; \
 		echo " */" ; \
 		echo "static unsigned int $*_code[] __page_aligned = {" ; \
-		hexdump -v -e '4/4 "0x%08x, " "\n"' $< ; \
+		hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \
 		echo "};" ; \
 		) > $@
 quiet_cmd_hexdump = HEXDUMP $@

--

#8 lore raw

PATCH 8/8 powerpc: fix large nvram access

In reply to Arnd Bergmann

/dev/nvram uses the user-provided read/write size for kmalloc, which fails, if a large number is passed. This will always use a single page at most, which can be expected to succeed.

arch/powerpc/kernel/nvram_64.c +54 -60
Index: linux-2.6.15-rc/arch/powerpc/kernel/nvram_64.c
===================================================================
@@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct fi
 static ssize_t dev_nvram_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos)
 {
-	ssize_t len;
-	char *tmp_buffer;
-	int size;
+	ssize_t ret;
+	char *tmp = NULL;
+	ssize_t size;
+
+	ret = -ENODEV;
+	if (!ppc_md.nvram_size)
+		goto out;
 
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
+	ret = 0;
 	size = ppc_md.nvram_size();
+	if (*ppos >= size || size < 0)
+		goto out;
 
-	if (!access_ok(VERIFY_WRITE, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size) 
-		count = size;
-
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
-		return -ENOMEM;
-	}
-
-	len = ppc_md.nvram_read(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
-
-	if (copy_to_user(buf, tmp_buffer, len)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
+	count = min_t(size_t, count, size - *ppos);
+	count = min(count, PAGE_SIZE);
 
-	kfree(tmp_buffer);
-	return len;
+	ret = -ENOMEM;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (!tmp)
+		goto out;
+
+	ret = ppc_md.nvram_read(tmp, count, ppos);
+	if (ret <= 0)
+		goto out;
+
+	if (copy_to_user(buf, tmp, ret))
+		ret = -EFAULT;
+
+out:
+	kfree(tmp);
+	return ret;
 
 }
 
 static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
-			   size_t count, loff_t *ppos)
+			  size_t count, loff_t *ppos)
 {
-	ssize_t len;
-	char * tmp_buffer;
-	int size;
+	ssize_t ret;
+	char *tmp = NULL;
+	ssize_t size;
+
+	ret = -ENODEV;
+	if (!ppc_md.nvram_size)
+		goto out;
 
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
+	ret = 0;
 	size = ppc_md.nvram_size();
+	if (*ppos >= size || size < 0)
+		goto out;
 
-	if (!access_ok(VERIFY_READ, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size)
-		count = size;
-
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
-		return -ENOMEM;
-	}
-	
-	if (copy_from_user(tmp_buffer, buf, count)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
+	count = min_t(size_t, count, size - *ppos);
+	count = min(count, PAGE_SIZE);
 
-	len = ppc_md.nvram_write(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
+	ret = -ENOMEM;
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (!tmp)
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_from_user(tmp, buf, count))
+		goto out;
+
+	ret = ppc_md.nvram_write(tmp, count, ppos);
+
+out:
+	kfree(tmp);
+	return ret;
 
-	kfree(tmp_buffer);
-	return len;
 }
 
 static int dev_nvram_ioctl(struct inode *inode, struct file *file,

--

#1 lore raw

PATCH 1/8 spufs: fix module refcount race

In reply to Arnd Bergmann

One of the two users of spufs_calls.owner still has a race when calling try_module_get while the module is removed. This makes it use the correct instance of owner.

Noticed by Milton Miller.

arch/powerpc/platforms/cell/spu_syscalls.c +1 -1
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/spu_syscalls.c
===================================================================
@@ -40,7 +40,7 @@ asmlinkage long sys_spu_create(const cha
 	struct module *owner = spufs_calls.owner;
 
 	ret = -ENOSYS;
-	if (owner && try_module_get(spufs_calls.owner)) {
+	if (owner && try_module_get(owner)) {
 		ret = spufs_calls.create_thread(name, flags, mode);
 		module_put(owner);
 	}

--

#7 lore raw

PATCH 7/8 cell: disable legacy i/o area

In reply to Arnd Bergmann

We currently crash in the fedora installer because the keyboard driver tries to access I/O space that is not there on our hardware.

This uses the same solution as powermac by just marking all legacy i/o as invalied.

From: David Woodhouse <[email protected]>

arch/powerpc/platforms/cell/setup.c +10 -0
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/setup.c
===================================================================
@@ -203,6 +203,15 @@ static int __init cell_probe(int platfor
 	return 1;
 }
 
+/*
+ * Cell has no legacy IO; anything calling this function has to
+ * fail or bad things will happen
+ */
+static int cell_check_legacy_ioport(unsigned int baseport)
+{
+	return -ENODEV;
+}
+
 struct machdep_calls __initdata cell_md = {
 	.probe			= cell_probe,
 	.setup_arch		= cell_setup_arch,
@@ -215,6 +224,7 @@ struct machdep_calls __initdata cell_md 
 	.get_rtc_time		= rtas_get_rtc_time,
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
+	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,

--

#5 lore raw

PATCH 5/8 cell: enable pause(0) in cpu_idle

In reply to Arnd Bergmann

This patch enables support for pause(0) power management state for the Cell Broadband Processor, which is import for power efficient operation. The pervasive infrastructure will in the future enable us to introduce more functionality specific to the Cell's pervasive unit.

This version contains fixes for a few problems found by Milton Miller and a fix to keep running on Cell BE DD2 CPUs, where the hardware feature is broken.

From: Maximino Aguilar <[email protected]>

arch/powerpc/platforms/cell/Makefile +2 -0
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/Makefile
===================================================================
@@ -1,4 +1,6 @@
 obj-y			+= interrupt.o iommu.o setup.o spider-pic.o
+obj-y			+= pervasive.o
+
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_SPU_FS)	+= spufs/ spu_base.o
 builtin-spufs-$(CONFIG_SPU_FS)	+= spu_syscalls.o
arch/powerpc/platforms/cell/pervasive.c new file +169 -0

169 lines not on this page · raw message

arch/powerpc/platforms/cell/pervasive.h new file +62 -0

62 lines not on this page · raw message

arch/powerpc/platforms/cell/setup.c +2 -0
Index: linux-2.6.15-rc/arch/powerpc/platforms/cell/setup.c
===================================================================
@@ -49,6 +49,7 @@
 
 #include "interrupt.h"
 #include "iommu.h"
+#include "pervasive.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -165,6 +166,7 @@ static void __init cell_setup_arch(void)
 	init_pci_config_tokens();
 	find_and_init_phbs();
 	spider_init_IRQ();
+	cell_pervasive_init();
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
arch/powerpc/kernel/head_64.S +23 -1
Index: linux-2.6.15-rc/arch/powerpc/kernel/head_64.S
===================================================================
@@ -401,7 +401,7 @@ label##_common:						\
 	.globl __start_interrupts
 __start_interrupts:
 
-	STD_EXCEPTION_PSERIES(0x100, system_reset)
+	STD_EXCEPTION_PSERIES(0x100, system_reset_check)
 
 	. = 0x200
 _machine_check_pSeries:
@@ -880,6 +880,28 @@ unrecov_fer:
 	bl	.unrecoverable_exception
 	b	1b
 
+/* This is a new system reset handler for the BE processor.
+ * SRR1 stores wake information that must be decoded to determine why
+ * the processor was at the system reset handler.
+ */
+
+	.align 7
+	.globl system_reset_check_common
+system_reset_check_common:
+BEGIN_FTR_SECTION
+	mr	r22,r12    /* r12 has SRR1 saved */
+	srwi	r22,r22,16
+	andi.	r22,r22,MSR_WAKEMASK
+	cmpwi	r22,MSR_WAKEEE
+	beq	hardware_interrupt_common
+	cmpwi	r22,MSR_WAKEDEC
+	beq	decrementer_common
+	cmpwi	r22,MSR_WAKEMT
+	bne	system_reset_common
+END_FTR_SECTION_IFSET(CPU_FTR_PAUSE_ZERO)
+	EXCEPTION_PROLOG_COMMON(0x100, PACA_EXGEN);
+	b	fast_exception_return
+
 /*
  * Here r13 points to the paca, r9 contains the saved CR,
  * SRR0 and SRR1 are saved in r11 and r12,
arch/powerpc/kernel/idle_64.c +0 -1
Index: linux-2.6.15-rc/arch/powerpc/kernel/idle_64.c
===================================================================
@@ -40,7 +40,6 @@ void default_idle(void)
 		if (!need_resched()) {
 			while (!need_resched() && !cpu_is_offline(cpu)) {
 				ppc64_runlatch_off();
-
 				/*
 				 * Go into low thread priority and possibly
 				 * low power mode.
include/asm-powerpc/cputable.h +6 -3
Index: linux-2.6.15-rc/include/asm-powerpc/cputable.h
===================================================================
@@ -106,6 +106,7 @@ extern void do_cpu_ftr_fixups(unsigned l
 #define CPU_FTR_LOCKLESS_TLBIE		ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV		ASM_CONST(0x0000080000000000)
 #define CPU_FTR_CI_LARGE_PAGE		ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO		ASM_CONST(0x0000200000000000)
 #else
 /* ensure on 32b processors the flags are available for compiling but
  * don't do anything */
@@ -303,9 +304,11 @@ enum {
 	    CPU_FTR_MMCRA | CPU_FTR_SMT |
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
 	    CPU_FTR_MMCRA_SIHV,
-	CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
+	CPU_FTRS_CELL_V2 = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
+	    CPU_FTR_CTRL,
+	CPU_FTRS_CELL = CPU_FTRS_CELL_V2 | CPU_FTR_PAUSE_ZERO,
 	CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
 #endif
@@ -387,7 +390,7 @@ enum {
 #endif
 #ifdef __powerpc64__
 	    CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 &
-	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL &
+	    CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL_V2 &
 #endif
 	    CPU_FTRS_POSSIBLE,
 };
include/asm-powerpc/reg.h +14 -5
Index: linux-2.6.15-rc/include/asm-powerpc/reg.h
===================================================================
@@ -92,6 +92,15 @@
 #define MSR_RI		__MASK(MSR_RI_LG)	/* Recoverable Exception */
 #define MSR_LE		__MASK(MSR_LE_LG)	/* Little Endian */
 
+/* Wake Events */
+#define MSR_WAKEMASK	0x0038
+#define MSR_WAKERESET	0x0038
+#define MSR_WAKESYSERR	0x0030
+#define MSR_WAKEEE	0x0020
+#define MSR_WAKEMT	0x0028
+#define MSR_WAKEDEC	0x0018
+#define MSR_WAKETHERM	0x0010
+
 #ifdef CONFIG_PPC64
 #define MSR_		MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF
 #define MSR_KERNEL      MSR_ | MSR_SF | MSR_HV
@@ -257,11 +266,11 @@
 #define	SPRN_HID6	0x3F9	/* BE HID 6 */
 #define	  HID6_LB	(0x0F<<12) /* Concurrent Large Page Modes */
 #define	  HID6_DLP	(1<<20)	/* Disable all large page modes (4K only) */
-#define	SPRN_TSCR	0x399   /* Thread switch control on BE */
-#define	SPRN_TTR	0x39A   /* Thread switch timeout on BE */
-#define	  TSCR_DEC_ENABLE	0x200000 /* Decrementer Interrupt */
-#define	  TSCR_EE_ENABLE	0x100000 /* External Interrupt */
-#define	  TSCR_EE_BOOST		0x080000 /* External Interrupt Boost */
+#define	SPRN_TSC_CELL	0x399	/* Thread switch control on Cell */
+#define	  TSC_CELL_DEC_ENABLE_0	0x400000 /* Decrementer Interrupt */
+#define	  TSC_CELL_DEC_ENABLE_1	0x200000 /* Decrementer Interrupt */
+#define	  TSC_CELL_EE_ENABLE	0x100000 /* External Interrupt */
+#define	  TSC_CELL_EE_BOOST	0x080000 /* External Interrupt Boost */
 #define	SPRN_TSC 	0x3FD	/* Thread switch control on others */
 #define	SPRN_TST 	0x3FC	/* Thread switch timeout on others */
 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
arch/powerpc/kernel/cputable.c +12 -1
Index: linux-2.6.15-rc/arch/powerpc/kernel/cputable.c
===================================================================
@@ -273,7 +273,18 @@ struct cpu_spec	cpu_specs[] = {
 		.oprofile_model		= &op_model_power4,
 #endif
 	},
-	{	/* BE DD1.x */
+	{	/* Cell BE 2.x */
+		.pvr_mask		= 0xffffff00,
+		.pvr_value		= 0x00700400,
+		.cpu_name		= "Cell Broadband Engine",
+		.cpu_features		= CPU_FTRS_CELL_V2,
+		.cpu_user_features	= COMMON_USER_PPC64 |
+			PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.cpu_setup		= __setup_cpu_be,
+	},
+	{	/* Generic Cell BE */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x00700000,
 		.cpu_name		= "Cell Broadband Engine",

--