From a244b25217978ffd54d2cd87013b3cd564689462 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 7 Apr 2010 10:08:49 +1000 Subject: Remove unused HDPU driver This driver seems to be specific to a "Sky CPU" board for which we don't appear to have upstream support (or not any more). No Kconfig file in the kernel ever enables it. So remove it. Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 27c4843..208ae30 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -3,7 +3,6 @@ # obj-$(CONFIG_IBM_ASM) += ibmasm/ -obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o diff --git a/drivers/misc/hdpuftrs/Makefile b/drivers/misc/hdpuftrs/Makefile deleted file mode 100644 index ac74ae6..0000000 --- a/drivers/misc/hdpuftrs/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_HDPU_FEATURES) := hdpu_cpustate.o hdpu_nexus.o diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c deleted file mode 100644 index 176fe4e..0000000 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Sky CPU State Driver - * - * Copyright (C) 2002 Brian Waite - * - * This driver allows use of the CPU state bits - * It exports the /dev/sky_cpustate and also - * /proc/sky_cpustate pseudo-file for status information. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SKY_CPUSTATE_VERSION "1.1" - -static int hdpu_cpustate_probe(struct platform_device *pdev); -static int hdpu_cpustate_remove(struct platform_device *pdev); - -static unsigned char cpustate_get_state(void); -static int cpustate_proc_open(struct inode *inode, struct file *file); -static int cpustate_proc_read(struct seq_file *seq, void *offset); - -static struct cpustate_t cpustate; - -static const struct file_operations proc_cpustate = { - .open = cpustate_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int cpustate_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cpustate_proc_read, NULL); -} - -static int cpustate_proc_read(struct seq_file *seq, void *offset) -{ - seq_printf(seq, "CPU State: %04x\n", cpustate_get_state()); - return 0; -} - -static int cpustate_get_ref(int excl) -{ - - int retval = -EBUSY; - - spin_lock(&cpustate.lock); - - if (cpustate.excl) - goto out_busy; - - if (excl) { - if (cpustate.open_count) - goto out_busy; - cpustate.excl = 1; - } - - cpustate.open_count++; - retval = 0; - - out_busy: - spin_unlock(&cpustate.lock); - return retval; -} - -static int cpustate_free_ref(void) -{ - - spin_lock(&cpustate.lock); - - cpustate.excl = 0; - cpustate.open_count--; - - spin_unlock(&cpustate.lock); - return 0; -} - -static unsigned char cpustate_get_state(void) -{ - - return cpustate.cached_val; -} - -static void cpustate_set_state(unsigned char new_state) -{ - unsigned int state = (new_state << 21); - -#ifdef DEBUG_CPUSTATE - printk("CPUSTATE -> 0x%x\n", new_state); -#endif - spin_lock(&cpustate.lock); - cpustate.cached_val = new_state; - writel((0xff << 21), cpustate.clr_addr); - writel(state, cpustate.set_addr); - spin_unlock(&cpustate.lock); -} - -/* - * Now all the various file operations that we export. - */ - -static ssize_t cpustate_read(struct file *file, char *buf, - size_t count, loff_t * ppos) -{ - unsigned char data; - - if (count < 0) - return -EFAULT; - if (count == 0) - return 0; - - data = cpustate_get_state(); - if (copy_to_user(buf, &data, sizeof(unsigned char))) - return -EFAULT; - return sizeof(unsigned char); -} - -static ssize_t cpustate_write(struct file *file, const char *buf, - size_t count, loff_t * ppos) -{ - unsigned char data; - - if (count < 0) - return -EFAULT; - - if (count == 0) - return 0; - - if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char))) - return -EFAULT; - - cpustate_set_state(data); - return sizeof(unsigned char); -} - -static int cpustate_open(struct inode *inode, struct file *file) -{ - int ret; - - lock_kernel(); - ret = cpustate_get_ref((file->f_flags & O_EXCL)); - unlock_kernel(); - - return ret; -} - -static int cpustate_release(struct inode *inode, struct file *file) -{ - return cpustate_free_ref(); -} - -static struct platform_driver hdpu_cpustate_driver = { - .probe = hdpu_cpustate_probe, - .remove = hdpu_cpustate_remove, - .driver = { - .name = HDPU_CPUSTATE_NAME, - .owner = THIS_MODULE, - }, -}; - -/* - * The various file operations we support. - */ -static const struct file_operations cpustate_fops = { - .owner = THIS_MODULE, - .open = cpustate_open, - .release = cpustate_release, - .read = cpustate_read, - .write = cpustate_write, - .llseek = no_llseek, -}; - -static struct miscdevice cpustate_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "sky_cpustate", - .fops = &cpustate_fops, -}; - -static int hdpu_cpustate_probe(struct platform_device *pdev) -{ - struct resource *res; - struct proc_dir_entry *proc_de; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - printk(KERN_ERR "sky_cpustate: " - "Invalid memory resource.\n"); - return -EINVAL; - } - cpustate.set_addr = (unsigned long *)res->start; - cpustate.clr_addr = (unsigned long *)res->end - 1; - - ret = misc_register(&cpustate_dev); - if (ret) { - printk(KERN_WARNING "sky_cpustate: " - "Unable to register misc device.\n"); - cpustate.set_addr = NULL; - cpustate.clr_addr = NULL; - return ret; - } - - proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate); - if (!proc_de) { - printk(KERN_WARNING "sky_cpustate: " - "Unable to create proc entry\n"); - } - - printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); - return 0; -} - -static int hdpu_cpustate_remove(struct platform_device *pdev) -{ - cpustate.set_addr = NULL; - cpustate.clr_addr = NULL; - - remove_proc_entry("sky_cpustate", NULL); - misc_deregister(&cpustate_dev); - - return 0; -} - -static int __init cpustate_init(void) -{ - return platform_driver_register(&hdpu_cpustate_driver); -} - -static void __exit cpustate_exit(void) -{ - platform_driver_unregister(&hdpu_cpustate_driver); -} - -module_init(cpustate_init); -module_exit(cpustate_exit); - -MODULE_AUTHOR("Brian Waite"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" HDPU_CPUSTATE_NAME); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c deleted file mode 100644 index ce39fa5..0000000 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Sky Nexus Register Driver - * - * Copyright (C) 2002 Brian Waite - * - * This driver allows reading the Nexus register - * It exports the /proc/sky_chassis_id and also - * /proc/sky_slot_id pseudo-file for status information. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -static int hdpu_nexus_probe(struct platform_device *pdev); -static int hdpu_nexus_remove(struct platform_device *pdev); -static int hdpu_slot_id_open(struct inode *inode, struct file *file); -static int hdpu_slot_id_read(struct seq_file *seq, void *offset); -static int hdpu_chassis_id_open(struct inode *inode, struct file *file); -static int hdpu_chassis_id_read(struct seq_file *seq, void *offset); - -static struct proc_dir_entry *hdpu_slot_id; -static struct proc_dir_entry *hdpu_chassis_id; -static int slot_id = -1; -static int chassis_id = -1; - -static const struct file_operations proc_slot_id = { - .open = hdpu_slot_id_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations proc_chassis_id = { - .open = hdpu_chassis_id_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static struct platform_driver hdpu_nexus_driver = { - .probe = hdpu_nexus_probe, - .remove = hdpu_nexus_remove, - .driver = { - .name = HDPU_NEXUS_NAME, - .owner = THIS_MODULE, - }, -}; - -static int hdpu_slot_id_open(struct inode *inode, struct file *file) -{ - return single_open(file, hdpu_slot_id_read, NULL); -} - -static int hdpu_slot_id_read(struct seq_file *seq, void *offset) -{ - seq_printf(seq, "%d\n", slot_id); - return 0; -} - -static int hdpu_chassis_id_open(struct inode *inode, struct file *file) -{ - return single_open(file, hdpu_chassis_id_read, NULL); -} - -static int hdpu_chassis_id_read(struct seq_file *seq, void *offset) -{ - seq_printf(seq, "%d\n", chassis_id); - return 0; -} - -static int hdpu_nexus_probe(struct platform_device *pdev) -{ - struct resource *res; - int *nexus_id_addr; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - printk(KERN_ERR "sky_nexus: " - "Invalid memory resource.\n"); - return -EINVAL; - } - nexus_id_addr = ioremap(res->start, - (unsigned long)(res->end - res->start)); - if (nexus_id_addr) { - slot_id = (*nexus_id_addr >> 8) & 0x1f; - chassis_id = *nexus_id_addr & 0xff; - iounmap(nexus_id_addr); - } else { - printk(KERN_ERR "sky_nexus: Could not map slot id\n"); - } - - hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id); - if (!hdpu_slot_id) { - printk(KERN_WARNING "sky_nexus: " - "Unable to create proc dir entry: sky_slot_id\n"); - } - - hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL, - &proc_chassis_id); - if (!hdpu_chassis_id) - printk(KERN_WARNING "sky_nexus: " - "Unable to create proc dir entry: sky_chassis_id\n"); - - return 0; -} - -static int hdpu_nexus_remove(struct platform_device *pdev) -{ - slot_id = -1; - chassis_id = -1; - - remove_proc_entry("sky_slot_id", NULL); - remove_proc_entry("sky_chassis_id", NULL); - - hdpu_slot_id = 0; - hdpu_chassis_id = 0; - - return 0; -} - -static int __init nexus_init(void) -{ - return platform_driver_register(&hdpu_nexus_driver); -} - -static void __exit nexus_exit(void) -{ - platform_driver_unregister(&hdpu_nexus_driver); -} - -module_init(nexus_init); -module_exit(nexus_exit); - -MODULE_AUTHOR("Brian Waite"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" HDPU_NEXUS_NAME); diff --git a/include/linux/hdpu_features.h b/include/linux/hdpu_features.h deleted file mode 100644 index 6a87154..0000000 --- a/include/linux/hdpu_features.h +++ /dev/null @@ -1,26 +0,0 @@ -#include - -struct cpustate_t { - spinlock_t lock; - int excl; - int open_count; - unsigned char cached_val; - int inited; - unsigned long *set_addr; - unsigned long *clr_addr; -}; - - -#define HDPU_CPUSTATE_NAME "hdpu cpustate" -#define HDPU_NEXUS_NAME "hdpu nexus" - -#define CPUSTATE_KERNEL_MAJOR 0x10 - -#define CPUSTATE_KERNEL_INIT_DRV 0 /* CPU State Driver Initialized */ -#define CPUSTATE_KERNEL_INIT_PCI 1 /* 64360 PCI Busses Init */ -#define CPUSTATE_KERNEL_INIT_REG 2 /* 64360 Bridge Init */ -#define CPUSTATE_KERNEL_CPU1_KICK 3 /* Boot cpu 1 */ -#define CPUSTATE_KERNEL_CPU1_OK 4 /* Cpu 1 has checked in */ -#define CPUSTATE_KERNEL_OK 5 /* Terminal state */ -#define CPUSTATE_KERNEL_RESET 14 /* Board reset via SW*/ -#define CPUSTATE_KERNEL_HALT 15 /* Board halted via SW*/ -- cgit v0.10.2 From 58706ef96fa10edad1ce492313c8314cd5916fbe Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 29 Jan 2010 14:18:20 +0000 Subject: powerpc: Add a new zImage for maple using a different link address The maple platform failed to load because it's firmware could not take a link address of 0x4000000. A new platform type with a link address of 0x400000 had to be created for the maple. Signed-off-by: Corey Minyard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index bb2465b..25e889c 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -169,7 +169,7 @@ quiet_cmd_wrap = WRAP $@ $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux image-$(CONFIG_PPC_PSERIES) += zImage.pseries -image-$(CONFIG_PPC_MAPLE) += zImage.pseries +image-$(CONFIG_PPC_MAPLE) += zImage.maple image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries image-$(CONFIG_PPC_PS3) += dtbImage.ps3 image-$(CONFIG_PPC_CELLEB) += zImage.pseries @@ -351,7 +351,7 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ zImage.iseries zImage.miboot zImage.pmac zImage.pseries \ - simpleImage.* otheros.bld *.dtb + zImage.maple simpleImage.* otheros.bld *.dtb # clean up files cached by wrapper clean-kernel := vmlinux.strip vmlinux.bin diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index f4594ed..7160b3b 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -149,6 +149,10 @@ pseries) platformo=$object/of.o link_address='0x4000000' ;; +maple) + platformo=$object/of.o + link_address='0x400000' + ;; pmac|chrp) platformo=$object/of.o ;; @@ -321,7 +325,7 @@ fi # post-processing needed for some platforms case "$platform" in -pseries|chrp) +pseries|chrp|maple) $objbin/addnote "$ofile" ;; coff) -- cgit v0.10.2 From f467bc148d05a1465211102804858df9c667f8b9 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 1 Feb 2010 09:37:46 +0000 Subject: powerpc/mpsc: Set the port device in the mpsc serial driver The mpsc serial driver needx to set the port's device tree element to register properly. Signed-off-by: Corey Minyard Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index 55e113a..6a9c660 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -2071,6 +2071,7 @@ static int mpsc_drv_probe(struct platform_device *dev) if (!(rc = mpsc_drv_map_regs(pi, dev))) { mpsc_drv_get_platform_data(pi, dev, dev->id); + pi->port.dev = &dev->dev; if (!(rc = mpsc_make_ready(pi))) { spin_lock_init(&pi->tx_lock); -- cgit v0.10.2 From 55052eeca6d71d76f7c3f156c0501814d8e5e6d3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 7 Apr 2010 14:39:36 +1000 Subject: powerpc: Fix ioremap_flags() with book3e pte definition We can't just clear the user read permission in book3e pte, because that will also clear supervisor read permission. This surely isn't desired. Fix the problem by adding the supervisor read back. BenH: Slightly simplified the ifdef and applied to ppc64 too Signed-off-by: Li Yang Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index b9243e7..767b0cf 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -146,6 +146,14 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */ flags &= ~(_PAGE_USER | _PAGE_EXEC); +#ifdef _PAGE_BAP_SR + /* _PAGE_USER contains _PAGE_BAP_SR on BookE using the new PTE format + * which means that we just cleared supervisor access... oops ;-) This + * restores it + */ + flags |= _PAGE_BAP_SR; +#endif + return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } EXPORT_SYMBOL(ioremap_flags); diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index d95679a..d050fc8 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -265,6 +265,14 @@ void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */ flags &= ~(_PAGE_USER | _PAGE_EXEC); +#ifdef _PAGE_BAP_SR + /* _PAGE_USER contains _PAGE_BAP_SR on BookE using the new PTE format + * which means that we just cleared supervisor access... oops ;-) This + * restores it + */ + flags |= _PAGE_BAP_SR; +#endif + if (ppc_md.ioremap) return ppc_md.ioremap(addr, size, flags, caller); return __ioremap_caller(addr, size, flags, caller); -- cgit v0.10.2 From 578b7cd1518f8d1b17a7fb1671d3d756c9cb49f1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 7 Apr 2010 14:44:28 +1000 Subject: powerpc/vio: Add modalias support BenH: Added to vio_cmo_dev_attrs as well Provide a modalias entry for VIO devices in sysfs. I believe this was another initrd generation bugfix for anaconda. Signed-off-by: David Woodhouse Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 8223717..2f57956 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -958,9 +958,12 @@ viodev_cmo_rd_attr(allocated); static ssize_t name_show(struct device *, struct device_attribute *, char *); static ssize_t devspec_show(struct device *, struct device_attribute *, char *); +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf); static struct device_attribute vio_cmo_dev_attrs[] = { __ATTR_RO(name), __ATTR_RO(devspec), + __ATTR_RO(modalias), __ATTR(cmo_desired, S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IROTH, viodev_cmo_desired_show, viodev_cmo_desired_set), __ATTR(cmo_entitled, S_IRUGO, viodev_cmo_entitled_show, NULL), @@ -1320,9 +1323,27 @@ static ssize_t devspec_show(struct device *dev, return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); } +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + const struct vio_dev *vio_dev = to_vio_dev(dev); + struct device_node *dn; + const char *cp; + + dn = dev->archdata.of_node; + if (!dn) + return -ENODEV; + cp = of_get_property(dn, "compatible", NULL); + if (!cp) + return -ENODEV; + + return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp); +} + static struct device_attribute vio_dev_attrs[] = { __ATTR_RO(name), __ATTR_RO(devspec), + __ATTR_RO(modalias), __ATTR_NULL }; -- cgit v0.10.2 From 9c7cc234dc5edf5379fbbab4973f6704f59bc57b Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Mon, 29 Mar 2010 23:59:25 +0000 Subject: powerpc: Disable interrupts for data breakpoint exceptions Data address breakpoint exceptions are currently handled along with page-faults which require interrupts to remain in enabled state. Since exception handling for data breakpoints aren't pre-empt safe, we handle them separately. Signed-off-by: K.Prasad Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e3be98f..3e423fb 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -735,8 +735,11 @@ _STATIC(do_hash_page) std r3,_DAR(r1) std r4,_DSISR(r1) - andis. r0,r4,0xa450 /* weird error? */ + andis. r0,r4,0xa410 /* weird error? */ bne- handle_page_fault /* if not, try to insert a HPTE */ + andis. r0,r4,DSISR_DABRMATCH@h + bne- handle_dabr_fault + BEGIN_FTR_SECTION andis. r0,r4,0x0020 /* Is it a segment table fault? */ bne- do_ste_alloc /* If so handle it */ @@ -823,6 +826,14 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) bl .raw_local_irq_restore b 11f +/* We have a data breakpoint exception - handle it */ +handle_dabr_fault: + ld r4,_DAR(r1) + ld r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_dabr + b .ret_from_except_lite + /* Here we have a page fault that hash_page can't handle. */ handle_page_fault: ENABLE_INTS diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 26fb6b9..83ac493 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -151,13 +151,14 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && (address >= TASK_SIZE)) return SIGSEGV; -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) +#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \ + defined(CONFIG_PPC_BOOK3S_64)) if (error_code & DSISR_DABRMATCH) { /* DABR match */ do_dabr(regs, address, error_code); return 0; } -#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ +#endif if (in_atomic() || mm == NULL) { if (!user_mode(regs)) -- cgit v0.10.2 From 6fe9d1facb5346a615f9b571df3b91593afb29c3 Mon Sep 17 00:00:00 2001 From: Vaidyanathan Srinivasan Date: Wed, 31 Mar 2010 21:39:24 +0000 Subject: powerpc/pseries: Export data from new hcall H_EM_GET_PARMS Add support for H_EM_GET_PARMS hcall that will return data related to power modes from the platform. Export the data directly to user space for administrative tools to interpret and use. cat /proc/powerpc/lparcfg will export power mode data Signed-off-by: Vaidyanathan Srinivasan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index f027581..ebe7493 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -228,6 +228,7 @@ #define H_JOIN 0x298 #define H_VASI_STATE 0x2A4 #define H_ENABLE_CRQ 0x2B0 +#define H_GET_EM_PARMS 0x2B8 #define H_SET_MPP 0x2D0 #define H_GET_MPP 0x2D4 #define MAX_HCALL_OPCODE H_GET_MPP diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index c2c70e1..50362b6 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -38,7 +38,7 @@ #include #include -#define MODULE_VERS "1.8" +#define MODULE_VERS "1.9" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ @@ -487,6 +487,14 @@ static void splpar_dispatch_data(struct seq_file *m) seq_printf(m, "dispatch_dispersions=%lu\n", dispatch_dispersions); } +static void parse_em_data(struct seq_file *m) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + if (plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS) + seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]); +} + static int pseries_lparcfg_data(struct seq_file *m, void *v) { int partition_potential_processors; @@ -541,6 +549,8 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) seq_printf(m, "slb_size=%d\n", mmu_slb_size); + parse_em_data(m); + return 0; } -- cgit v0.10.2 From 43b5fefc24157def813154d1867d2960cefff837 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 9 Mar 2010 09:35:00 +0000 Subject: powerpc/ppc32: Fixup pmd_page to work when ARCH_PFN_OFFSET is non-zero Instead of referencing mem_map directly, use pfn_to_page. Otherwise the kernel crashes when trying to start userspace if ARCH_PFN_OFFSET is non-zero and CONFIG_BOOKE is not defined Signed-off-by: Jason Gunthorpe Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index 55646ad..a7db96f 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h @@ -287,7 +287,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) #define pmd_page_vaddr(pmd) \ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) #define pmd_page(pmd) \ - (mem_map + (pmd_val(pmd) >> PAGE_SHIFT)) + pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) #else #define pmd_page_vaddr(pmd) \ ((unsigned long) (pmd_val(pmd) & PAGE_MASK)) -- cgit v0.10.2 From fe1691e3f49d41452832f5aee2b952bd201ccab1 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 2 Mar 2010 05:37:09 +0000 Subject: powerpc/8xx: Optimze TLB Miss handlers This removes a couple of insn's from the TLB Miss handlers whithout changing functionality. Signed-off-by: Joakim Tjernlund Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 3ef743f..ecc4a02 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -343,17 +343,14 @@ InstructionTLBMiss: cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT bne- cr0, 2f - /* Clear PP lsb, 0x400 */ - rlwinm r10, r10, 0, 22, 20 - /* The Linux PTE won't go exactly into the MMU TLB. - * Software indicator bits 22 and 28 must be clear. + * Software indicator bits 21 and 28 must be clear. * Software indicator bits 24, 25, 26, and 27 must be * set. All other Linux PTE bits control the behavior * of the MMU. */ li r11, 0x00f0 - rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ + rlwimi r10, r11, 0, 0x07f8 /* Set 24-27, clear 21-23,28 */ DO_8xx_CPU6(0x2d80, r3) mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ @@ -444,9 +441,7 @@ DataStoreTLBMiss: /* Honour kernel RO, User NA */ /* 0x200 == Extended encoding, bit 22 */ - /* r11 = (r10 & _PAGE_USER) >> 2 */ - rlwinm r11, r10, 32-2, 0x200 - or r10, r11, r10 + rlwimi r10, r10, 32-2, 0x200 /* Copy USER to bit 22, 0x200 */ /* r11 = (r10 & _PAGE_RW) >> 1 */ rlwinm r11, r10, 32-1, 0x200 or r10, r11, r10 -- cgit v0.10.2 From 4afb0be7ccda0ca551cc37572bab74ba4a3c18dd Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 2 Mar 2010 05:37:10 +0000 Subject: powerpc/8xx: Avoid testing for kernel space in ITLB Miss. Only modules will cause ITLB Misses as we always pin the first 8MB of kernel memory. Signed-off-by: Joakim Tjernlund Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index ecc4a02..84ca1d9 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -318,12 +318,16 @@ InstructionTLBMiss: /* If we are faulting a kernel address, we have to use the * kernel page tables. */ +#ifdef CONFIG_MODULES + /* Only modules will cause ITLB Misses as we always + * pin the first 8MB of kernel memory */ andi. r11, r10, 0x0800 /* Address >= 0x80000000 */ beq 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l rlwimi r10, r11, 0, 2, 19 3: +#endif lwz r11, 0(r10) /* Get the level 1 entry */ rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ beq 2f /* If zero, don't try to find a pte */ -- cgit v0.10.2 From d069cb4373fe0d451357c4d3769623a7564dfa9f Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 2 Mar 2010 05:37:11 +0000 Subject: powerpc/8xx: Don't touch ACCESSED when no SWAP. Only the swap function cares about the ACCESSED bit in the pte. Do not waste cycles updateting ACCESSED when swap is not compiled into the kernel. Signed-off-by: Joakim Tjernlund Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 84ca1d9..6478a96 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -343,10 +343,11 @@ InstructionTLBMiss: mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ lwz r10, 0(r11) /* Get the pte */ +#ifdef CONFIG_SWAP andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT bne- cr0, 2f - +#endif /* The Linux PTE won't go exactly into the MMU TLB. * Software indicator bits 21 and 28 must be clear. * Software indicator bits 24, 25, 26, and 27 must be @@ -439,10 +440,11 @@ DataStoreTLBMiss: * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5)); * r10 = (r10 & ~PRESENT) | r11; */ +#ifdef CONFIG_SWAP rlwinm r11, r10, 32-5, _PAGE_PRESENT and r11, r11, r10 rlwimi r10, r11, 0, _PAGE_PRESENT - +#endif /* Honour kernel RO, User NA */ /* 0x200 == Extended encoding, bit 22 */ rlwimi r10, r10, 32-2, 0x200 /* Copy USER to bit 22, 0x200 */ -- cgit v0.10.2 From 469d62be9263b92f2c3329540cbb1c076111f4f3 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 2 Mar 2010 05:37:12 +0000 Subject: powerpc/8xx: Use SPRG2 and DAR registers to stash r11 and cr. This avoids storing these registers in memory. CPU6 errata will still use the old way. Remove some G2 leftover accesses from 2.4 Signed-off-by: Joakim Tjernlund Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 6478a96..1f1a04b 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -71,9 +71,6 @@ _ENTRY(_start); * in the first level table, but that would require many changes to the * Linux page directory/table functions that I don't want to do right now. * - * I used to use SPRG2 for a temporary register in the TLB handler, but it - * has since been put to other uses. I now use a hack to save a register - * and the CCR at memory location 0.....Someday I'll fix this..... * -- Dan */ .globl __start @@ -302,8 +299,13 @@ InstructionTLBMiss: DO_8xx_CPU6(0x3f80, r3) mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ mfcr r10 +#ifdef CONFIG_8xx_CPU6 stw r10, 0(r0) stw r11, 4(r0) +#else + mtspr SPRN_DAR, r10 + mtspr SPRN_SPRG2, r11 +#endif mfspr r10, SPRN_SRR0 /* Get effective address of fault */ #ifdef CONFIG_8xx_CPU15 addi r11, r10, 0x1000 @@ -359,13 +361,19 @@ InstructionTLBMiss: DO_8xx_CPU6(0x2d80, r3) mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ - mfspr r10, SPRN_M_TW /* Restore registers */ + /* Restore registers */ +#ifndef CONFIG_8xx_CPU6 + mfspr r10, SPRN_DAR + mtcr r10 + mtspr SPRN_DAR, r11 /* Tag DAR */ + mfspr r11, SPRN_SPRG2 +#else lwz r11, 0(r0) mtcr r11 lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 lwz r3, 8(r0) #endif + mfspr r10, SPRN_M_TW rfi 2: mfspr r11, SPRN_SRR1 @@ -375,13 +383,20 @@ InstructionTLBMiss: rlwinm r11, r11, 0, 0xffff mtspr SPRN_SRR1, r11 - mfspr r10, SPRN_M_TW /* Restore registers */ + /* Restore registers */ +#ifndef CONFIG_8xx_CPU6 + mfspr r10, SPRN_DAR + mtcr r10 + li r11, 0x00f0 + mtspr SPRN_DAR, r11 /* Tag DAR */ + mfspr r11, SPRN_SPRG2 +#else lwz r11, 0(r0) mtcr r11 lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 lwz r3, 8(r0) #endif + mfspr r10, SPRN_M_TW b InstructionAccess . = 0x1200 @@ -392,8 +407,13 @@ DataStoreTLBMiss: DO_8xx_CPU6(0x3f80, r3) mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ mfcr r10 +#ifdef CONFIG_8xx_CPU6 stw r10, 0(r0) stw r11, 4(r0) +#else + mtspr SPRN_DAR, r10 + mtspr SPRN_SPRG2, r11 +#endif mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ /* If we are faulting a kernel address, we have to use the @@ -461,18 +481,24 @@ DataStoreTLBMiss: * of the MMU. */ 2: li r11, 0x00f0 - mtspr SPRN_DAR,r11 /* Tag DAR */ rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ DO_8xx_CPU6(0x3d80, r3) mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ - mfspr r10, SPRN_M_TW /* Restore registers */ + /* Restore registers */ +#ifndef CONFIG_8xx_CPU6 + mfspr r10, SPRN_DAR + mtcr r10 + mtspr SPRN_DAR, r11 /* Tag DAR */ + mfspr r11, SPRN_SPRG2 +#else + mtspr SPRN_DAR, r11 /* Tag DAR */ lwz r11, 0(r0) mtcr r11 lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 lwz r3, 8(r0) #endif + mfspr r10, SPRN_M_TW rfi /* This is an instruction TLB error on the MPC8xx. This could be due @@ -684,9 +710,6 @@ start_here: tophys(r4,r2) addi r4,r4,THREAD /* init task's THREAD */ mtspr SPRN_SPRG_THREAD,r4 - li r3,0 - /* XXX What is that for ? SPRG2 appears otherwise unused on 8xx */ - mtspr SPRN_SPRG2,r3 /* 0 => r1 has kernel sp */ /* stack */ lis r1,init_thread_union@ha -- cgit v0.10.2 From 6237cdac5dd26d5ba81acf5daa737c8645614410 Mon Sep 17 00:00:00 2001 From: d binderman Date: Fri, 19 Mar 2010 00:12:22 +0000 Subject: powerpc/aoa: gpio-pmf.c: 3 * redundant code Signed-off-by: David Binderman Signed-off-by: Benjamin Herrenschmidt diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/gpio-pmf.c index 6776d1c..7e267c9 100644 --- a/sound/aoa/core/gpio-pmf.c +++ b/sound/aoa/core/gpio-pmf.c @@ -116,12 +116,9 @@ static void pmf_gpio_exit(struct gpio_runtime *rt) mutex_destroy(&rt->line_in_notify.mutex); mutex_destroy(&rt->line_out_notify.mutex); - if (rt->headphone_notify.gpio_private) - kfree(rt->headphone_notify.gpio_private); - if (rt->line_in_notify.gpio_private) - kfree(rt->line_in_notify.gpio_private); - if (rt->line_out_notify.gpio_private) - kfree(rt->line_out_notify.gpio_private); + kfree(rt->headphone_notify.gpio_private); + kfree(rt->line_in_notify.gpio_private); + kfree(rt->line_out_notify.gpio_private); } static void pmf_handle_notify_irq(void *data) -- cgit v0.10.2 From 213972e9faf8a16b27fee01ae7c7071de5080268 Mon Sep 17 00:00:00 2001 From: d binderman Date: Sat, 6 Feb 2010 02:13:29 +0000 Subject: powerpc/pmac/low_i2c.c: three minor problems Fix minor nits found by cppcheck [./arch/powerpc/platforms/powermac/low_i2c.c:594]: (style) The scope of the variable chans can be reduced [./arch/powerpc/platforms/powermac/low_i2c.c:594]: (style) The scope of the variable i can be reduced [./arch/powerpc/platforms/powermac/low_i2c.c:1260]: (style) Redundant condition. It is safe to deallocate a NULL pointer Signed-off-by: David Binderman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f45331a..06a137c 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -592,7 +592,7 @@ static void __init kw_i2c_probe(void) /* Probe keywest-i2c busses */ for_each_compatible_node(np, "i2c","keywest-i2c") { struct pmac_i2c_host_kw *host; - int multibus, chans, i; + int multibus; /* Found one, init a host structure */ host = kw_i2c_host_init(np); @@ -614,6 +614,8 @@ static void __init kw_i2c_probe(void) * parent type */ if (multibus) { + int chans, i; + parent = of_get_parent(np); if (parent == NULL) continue; @@ -1258,8 +1260,7 @@ static void pmac_i2c_do_end(struct pmf_function *func, void *instdata) if (inst == NULL) return; pmac_i2c_close(inst->bus); - if (inst) - kfree(inst); + kfree(inst); } static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len) -- cgit v0.10.2 From 6d1bdd2afbed74b3adcf3a7aec49e430eeb6c5f3 Mon Sep 17 00:00:00 2001 From: d binderman Date: Thu, 18 Mar 2010 23:01:42 +0000 Subject: powerpc/pmac/windfarm: Don't test pointers before kfree() Fix minor nits found by cppcheck [./macintosh/windfarm_pm81.c:760]: (style) Redundant condition. It is safe to deallocate a NULL pointer [./macintosh/windfarm_pm81.c:762]: (style) Redundant condition. It is safe to deallocate a NULL pointer Signed-off-by: David Binderman Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 565d5b2..e6e46a2 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -757,10 +757,8 @@ static int __devexit wf_smu_remove(struct platform_device *ddev) wf_put_control(cpufreq_clamp); /* Destroy control loops state structures */ - if (wf_smu_sys_fans) - kfree(wf_smu_sys_fans); - if (wf_smu_cpu_fans) - kfree(wf_smu_cpu_fans); + kfree(wf_smu_sys_fans); + kfree(wf_smu_cpu_fans); return 0; } -- cgit v0.10.2 From 637a99022fb119b90fb281715d13172f0394fc12 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 17 Mar 2010 10:55:51 +0000 Subject: powerpc: Fix handling of strncmp with zero len Commit 0119536c, which added the assembly version of strncmp to powerpc, mentions that it adds two instructions to the version from boot/string.S to allow it to handle len=0. Unfortunately, it doesn't always return 0 when that is the case. The length is passed in r5, but the return value is passed back in r3. In certain cases, this will happen to work. Otherwise it will pass back the address of the first string as the return value. This patch lifts the len <= 0 handling code from memcpy to handle that case. Reported by: Christian_Sellars@symantec.com Signed-off-by: Jeff Mahoney CC: Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index 64e2e49..3ac0cd3 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -71,7 +71,7 @@ _GLOBAL(strcmp) _GLOBAL(strncmp) PPC_LCMPI r5,0 - beqlr + ble- 2f mtctr r5 addi r5,r3,-1 addi r4,r4,-1 @@ -82,6 +82,8 @@ _GLOBAL(strncmp) beqlr 1 bdnzt eq,1b blr +2: li r3,0 + blr _GLOBAL(strlen) addi r4,r3,-1 -- cgit v0.10.2 From ab30f78c0afbb86584144925e25c7ca68ba9a91f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 28 Mar 2010 23:39:22 +0000 Subject: powerpc/pmac/windfarm: Correct potential double free The conditionals were testing different values, but then all freeing the same one, which could result in a double free. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,e; identifier f; iterator I; statement S; @@ *kfree(x); ... when != &x when != x = e when != I(x,...) S *x // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index bea9916..3442732 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -687,12 +687,9 @@ static int __devexit wf_smu_remove(struct platform_device *ddev) wf_put_control(cpufreq_clamp); /* Destroy control loops state structures */ - if (wf_smu_slots_fans) - kfree(wf_smu_cpu_fans); - if (wf_smu_drive_fans) - kfree(wf_smu_cpu_fans); - if (wf_smu_cpu_fans) - kfree(wf_smu_cpu_fans); + kfree(wf_smu_slots_fans); + kfree(wf_smu_drive_fans); + kfree(wf_smu_cpu_fans); return 0; } -- cgit v0.10.2 From a7df5c5e52a545774c4db1f2adf09ede018ab139 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 2 Apr 2010 02:47:13 +0000 Subject: powerpc/pseries/dlpar: Eliminate use after free dlpar_free_cc_nodes frees its argument, so dlpar_online_cpu should not be called on the same value. Skip over the call to dlpar_online_cpu by jumping directly to out. A simplified version of the semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression E,E2; @@ dlpar_free_cc_nodes(E) ... ( E = E2 | * E ) // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index e1682bc..1540a41 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -433,6 +433,7 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count) if (rc) { dlpar_release_drc(drc_index); dlpar_free_cc_nodes(dn); + goto out; } rc = dlpar_online_cpu(dn); -- cgit v0.10.2 From 43caa61f154da85a620965f3f61c2f45366d8dc7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 10 Mar 2010 11:15:01 +0000 Subject: powerpc/pseries/dlpar: Use kasprintf kasprintf combines kmalloc and sprintf, and takes care of the size calculation itself. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression a,flag; expression list args; statement S; @@ a = - \(kmalloc\|kzalloc\)(...,flag) + kasprintf(flag,args) <... when != a if (a == NULL || ...) S ...> - sprintf(a,args); // Signed-off-by: Julia Lawall Acked-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 1540a41..d71e585 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -79,13 +79,12 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa) * prepend this to the full_name. */ name = (char *)ccwa + ccwa->name_offset; - dn->full_name = kmalloc(strlen(name) + 2, GFP_KERNEL); + dn->full_name = kasprintf(GFP_KERNEL, "/%s", name); if (!dn->full_name) { kfree(dn); return NULL; } - sprintf(dn->full_name, "/%s", name); return dn; } @@ -410,15 +409,13 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count) * directory of the device tree. CPUs actually live in the * cpus directory so we need to fixup the full_name. */ - cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus") + 1, - GFP_KERNEL); + cpu_name = kasprintf(GFP_KERNEL, "/cpus%s", dn->full_name); if (!cpu_name) { dlpar_free_cc_nodes(dn); rc = -ENOMEM; goto out; } - sprintf(cpu_name, "/cpus%s", dn->full_name); kfree(dn->full_name); dn->full_name = cpu_name; -- cgit v0.10.2 From f6d8c8bb1d360272d795927d39f3d2c5934e77d9 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 29 Mar 2010 05:33:34 +0000 Subject: powerpc/vio: Add missing unlock in error path Add an unlock before exiting the function. A simplified version of the semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression E1; identifier f; @@ f (...) { <+... * spin_lock_irq (E1,...); ... when != E1 * return ...; ...+> } // Signed-off-by: Julia Lawall Acked-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 2f57956..2a3428b 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -645,8 +645,10 @@ void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) found = 1; break; } - if (!found) + if (!found) { + spin_unlock_irqrestore(&vio_cmo.lock, flags); return; + } /* Increase/decrease in desired device entitlement */ if (desired >= viodev->cmo.desired) { -- cgit v0.10.2 From 86e4754ac8fde9a9c913571016bc31257aa2e195 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 29 Mar 2010 05:34:46 +0000 Subject: powerpc/pmac: Add missing unlocks in error path In some error handling cases the lock is not unlocked. A simplified version of the semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression E1; identifier f; @@ f (...) { <+... * spin_lock_irqsave (E1,...); ... when != E1 * return ...; ...+> } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 79119f5..bd6da7a 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -155,6 +155,7 @@ static int macio_adb_reset_bus(void) while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) { if (--timeout == 0) { out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) & ~ADB_RST); + spin_unlock_irqrestore(&macio_lock, flags); return -1; } } diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 888448c..c9da5c4 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -1183,8 +1183,10 @@ static ssize_t smu_read_command(struct file *file, struct smu_private *pp, return -EOVERFLOW; spin_lock_irqsave(&pp->lock, flags); if (pp->cmd.status == 1) { - if (file->f_flags & O_NONBLOCK) + if (file->f_flags & O_NONBLOCK) { + spin_unlock_irqrestore(&pp->lock, flags); return -EAGAIN; + } add_wait_queue(&pp->wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); -- cgit v0.10.2 From 21dbeb91a24d867af0e98ba155bfa80d2906344f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 26 Mar 2010 12:03:29 +0000 Subject: powerpc: Use set_cpus_allowed_ptr Use set_cpus_allowed_ptr rather than set_cpus_allowed. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression E1,E2; @@ - set_cpus_allowed(E1, cpumask_of_cpu(E2)) + set_cpus_allowed_ptr(E1, cpumask_of(E2)) @@ expression E; identifier I; @@ - set_cpus_allowed(E, I) + set_cpus_allowed_ptr(E, &I) // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index c2ee144..e36f94f 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -561,12 +561,12 @@ void __init smp_cpus_done(unsigned int max_cpus) * se we pin us down to CPU 0 for a short while */ old_mask = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid)); + set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid)); if (smp_ops && smp_ops->setup_cpu) smp_ops->setup_cpu(boot_cpuid); - set_cpus_allowed(current, old_mask); + set_cpus_allowed_ptr(current, &old_mask); snapshot_timebases(); -- cgit v0.10.2 From 7429b3842cfb2b8ef5d333d8f680d80f8f7c787f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 20 Mar 2010 04:12:50 +0000 Subject: powerpc/pmac: Fix dangling pointers Fix I2C-drivers which missed setting clientdata to NULL before freeing the structure it points to. Also fix drivers which do this _after_ the structure was freed already. Signed-off-by: Wolfram Sang Cc: Colin Leroy Cc: Benjamin Herrenschmidt Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c42eeb4..16d82f1 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -182,6 +182,7 @@ remove_thermostat(struct i2c_client *client) thermostat = NULL; + i2c_set_clientdata(client, NULL); kfree(th); return 0; @@ -399,6 +400,7 @@ static int probe_thermostat(struct i2c_client *client, rc = read_reg(th, CONFIG_REG); if (rc < 0) { dev_err(&client->dev, "Thermostat failed to read config!\n"); + i2c_set_clientdata(client, NULL); kfree(th); return -ENODEV; } -- cgit v0.10.2 From 27f10907b7cca57df5e2a9c94c14354dd1b7879d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 18 Feb 2010 12:29:23 +0000 Subject: powerpc/numa: Set a smaller value for RECLAIM_DISTANCE to enable zone reclaim I noticed /proc/sys/vm/zone_reclaim_mode was 0 on a ppc64 NUMA box. It gets enabled via this: /* * If another node is sufficiently far away then it is better * to reclaim pages in a zone before going off node. */ if (distance > RECLAIM_DISTANCE) zone_reclaim_mode = 1; Since we use the default value of 20 for REMOTE_DISTANCE and 20 for RECLAIM_DISTANCE it never kicks in. The local to remote bandwidth ratios can be quite large on System p machines so it makes sense for us to reclaim clean pagecache locally before going off node. The patch below sets a smaller value for RECLAIM_DISTANCE and thus enables zone reclaim. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 8eaec31..a7d7694 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -8,6 +8,16 @@ struct device_node; #ifdef CONFIG_NUMA +/* + * Before going off node we want the VM to try and reclaim from the local + * node. It does this if the remote distance is larger than RECLAIM_DISTANCE. + * With the default REMOTE_DISTANCE of 20 and the default RECLAIM_DISTANCE of + * 20, we never reclaim and go off node straight away. + * + * To fix this we choose a smaller value of RECLAIM_DISTANCE. + */ +#define RECLAIM_DISTANCE 10 + #include static inline int cpu_to_node(int cpu) -- cgit v0.10.2 From e9bbc8cde0e3c33b42ddbe1b02108cb5c97275eb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 18 Feb 2010 12:11:51 +0000 Subject: powerpc/pseries: Call ibm,os-term if the ibm,extended-os-term is present We have had issues in the past with ibm,os-term initiating shutdown of a partition. This is confusing to the user, especially if panic_timeout is non zero. The temporary fix was to avoid calling ibm,os-term if a panic_timeout was set and since we set it on every boot we basically never call ibm,os-term. An extended version of ibm,os-term has since been implemented which gives us the behaviour we want: "When the platform supports extended ibm,os-term behavior, the return to the RTAS will always occur unless there is a kernel assisted dump active as initiated by an ibm,configure-kernel-dump call." This patch checks for the ibm,extended-os-term property and calls ibm,os-term if it exists. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 7436784..0e1ec6f 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -691,10 +691,14 @@ void rtas_os_term(char *str) { int status; - if (panic_timeout) - return; - - if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term")) + /* + * Firmware with the ibm,extended-os-term property is guaranteed + * to always return from an ibm,os-term call. Earlier versions without + * this property may terminate the partition which we want to avoid + * since it interferes with panic_timeout. + */ + if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term") || + RTAS_UNKNOWN_SERVICE == rtas_token("ibm,extended-os-term")) return; snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str); @@ -705,8 +709,7 @@ void rtas_os_term(char *str) } while (rtas_busy_delay(status)); if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", - status); + printk(KERN_EMERG "ibm,os-term call failed %d\n", status); } static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; -- cgit v0.10.2 From 7545ba6f82924d4523f8f8a2baf2e517a750265d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 25 Feb 2010 20:18:46 +0000 Subject: powerpc/mm: Bump SECTION_SIZE_BITS from 16MB to 256MB The current setting for SECTION_SIZE_BITS is quite small compared to everyone else: arch/powerpc/include/asm/sparsemem.h:#define SECTION_SIZE_BITS 24 arch/sparc/include/asm/sparsemem.h:#define SECTION_SIZE_BITS 30 arch/ia64/include/asm/sparsemem.h:#define SECTION_SIZE_BITS (30) arch/s390/include/asm/sparsemem.h:#define SECTION_SIZE_BITS 28 arch/x86/include/asm/sparsemem.h:# define SECTION_SIZE_BITS 27 And it has proven to be an issue during boot on very large machines. If hotplug memory is enabled, drivers/base/memory.c does this: for (i = 0; i < NR_MEM_SECTIONS; i++) { if (!present_section_nr(i)) continue; err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0, BOOT); if (!ret) ret = err; } Which creates a sysfs directory for every 16MB of memory. As a result I'm seeing up to 30 minutes spent here during boot: c000000000248ee0 .__sysfs_add_one+0x28/0x128 c0000000002492a8 .sysfs_add_one+0x38/0x188 c000000000249c88 .create_dir+0x70/0x138 c000000000249d98 .sysfs_create_dir+0x48/0x78 c00000000032bad8 .kobject_add_internal+0x140/0x308 c00000000032beb4 .kobject_init_and_add+0x4c/0x68 c00000000046c2c0 .sysdev_register+0xa0/0x220 c00000000047b1dc .add_memory_block+0x124/0x1e8 c0000000008d1f28 .memory_dev_init+0xf4/0x168 c0000000008d1b64 .driver_init+0x50/0x64 c000000000890378 .do_basic_setup+0x40/0xd4 I assume there are some O(n^2) issues in sysfs as we add all the memory nodes. Bumping SECTION_SIZE_BITS to 256 MB drops the time to about 10 seconds and results in a much smaller /sys. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 54a47ea..13fe0a0 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -8,7 +8,7 @@ * MAX_PHYSADDR_BITS 2^N: how much physical address space we have * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space */ -#define SECTION_SIZE_BITS 24 +#define SECTION_SIZE_BITS 28 #define MAX_PHYSADDR_BITS 44 #define MAX_PHYSMEM_BITS 44 -- cgit v0.10.2 From 8260cf6f40014860cb857f5245194900dd6c9b94 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 28 Feb 2010 00:58:16 +0000 Subject: powerpc/iseries/pci: Use __ratelimit Replace open-coded rate limiting logic with __ratelimit(). Signed-off-by: Akinobu Mita Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index b841c9a..3fc2e64 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -584,14 +585,9 @@ static inline struct device_node *xlate_iomm_address( orig_addr = (unsigned long __force)addr; if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { - static unsigned long last_jiffies; - static int num_printed; + static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10); - if (time_after(jiffies, last_jiffies + 60 * HZ)) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) + if (__ratelimit(&ratelimit)) printk(KERN_ERR "iSeries_%s: invalid access at IO address %p\n", func, addr); -- cgit v0.10.2 From a32aaf14513da776556ad9995de8d83cd76ae60a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 7 Apr 2010 18:09:15 +1000 Subject: powerpc/vio: Add power management support Adds support for suspend/resume for VIO devices. This is needed for support for HMC initiated hibernation. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 2a3428b..b8e311d 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -1381,6 +1381,29 @@ static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env) return 0; } +static int vio_pm_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->suspend) + return pm->suspend(dev); + return 0; +} + +static int vio_pm_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->resume) + return pm->resume(dev); + return 0; +} + +const struct dev_pm_ops vio_dev_pm_ops = { + .suspend = vio_pm_suspend, + .resume = vio_pm_resume, +}; + static struct bus_type vio_bus_type = { .name = "vio", .dev_attrs = vio_dev_attrs, @@ -1388,6 +1411,7 @@ static struct bus_type vio_bus_type = { .match = vio_bus_match, .probe = vio_bus_probe, .remove = vio_bus_remove, + .pm = &vio_dev_pm_ops, }; /** -- cgit v0.10.2 From 359e4284a3f37aba7fd06d993863de2509d86f54 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Wed, 7 Apr 2010 18:10:20 +1000 Subject: powerpc: Add kprobe-based event tracer This patch ports the kprobe-based event tracer to powerpc. This patch is based on x86 port. This brings powerpc on par with x86. Signed-off-by: Mahesh Salgaonkar Acked-by: Masami Hiramatsu Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 2e19500..c4c4549 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -140,6 +140,7 @@ config PPC select HAVE_SYSCALL_WRAPPERS if PPC64 select GENERIC_ATOMIC64 if PPC32 select HAVE_PERF_EVENTS + select HAVE_REGS_AND_STACK_ACCESS_API config EARLY_PRINTK bool diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 9e2d84c..5d8be04 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -89,6 +89,7 @@ struct pt_regs { #define instruction_pointer(regs) ((regs)->nip) #define user_stack_pointer(regs) ((regs)->gpr[1]) +#define kernel_stack_pointer(regs) ((regs)->gpr[1]) #define regs_return_value(regs) ((regs)->gpr[3]) #ifdef CONFIG_SMP @@ -141,6 +142,69 @@ do { \ #define arch_has_block_step() (!cpu_has_feature(CPU_FTR_601)) #define ARCH_HAS_USER_SINGLE_STEP_INFO +/* + * kprobe-based event tracer support + */ + +#include +#include +extern int regs_query_register_offset(const char *name); +extern const char *regs_query_register_name(unsigned int offset); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, dsisr)) + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten + * @offset: offset number of the register. + * + * regs_get_register returns the value of a register whose offset from @regs. + * The @offset is the offset of the register in struct pt_regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ + +static inline bool regs_within_kernel_stack(struct pt_regs *regs, + unsigned long addr) +{ + return ((addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index ed2cfe1..7a0c0199 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -39,6 +39,109 @@ #include /* + * The parameter save area on the stack is used to store arguments being passed + * to callee function and is located at fixed offset from stack pointer. + */ +#ifdef CONFIG_PPC32 +#define PARAMETER_SAVE_AREA_OFFSET 24 /* bytes */ +#else /* CONFIG_PPC32 */ +#define PARAMETER_SAVE_AREA_OFFSET 48 /* bytes */ +#endif + +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define STR(s) #s /* convert to string */ +#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} +#define GPR_OFFSET_NAME(num) \ + {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])} +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +static const struct pt_regs_offset regoffset_table[] = { + GPR_OFFSET_NAME(0), + GPR_OFFSET_NAME(1), + GPR_OFFSET_NAME(2), + GPR_OFFSET_NAME(3), + GPR_OFFSET_NAME(4), + GPR_OFFSET_NAME(5), + GPR_OFFSET_NAME(6), + GPR_OFFSET_NAME(7), + GPR_OFFSET_NAME(8), + GPR_OFFSET_NAME(9), + GPR_OFFSET_NAME(10), + GPR_OFFSET_NAME(11), + GPR_OFFSET_NAME(12), + GPR_OFFSET_NAME(13), + GPR_OFFSET_NAME(14), + GPR_OFFSET_NAME(15), + GPR_OFFSET_NAME(16), + GPR_OFFSET_NAME(17), + GPR_OFFSET_NAME(18), + GPR_OFFSET_NAME(19), + GPR_OFFSET_NAME(20), + GPR_OFFSET_NAME(21), + GPR_OFFSET_NAME(22), + GPR_OFFSET_NAME(23), + GPR_OFFSET_NAME(24), + GPR_OFFSET_NAME(25), + GPR_OFFSET_NAME(26), + GPR_OFFSET_NAME(27), + GPR_OFFSET_NAME(28), + GPR_OFFSET_NAME(29), + GPR_OFFSET_NAME(30), + GPR_OFFSET_NAME(31), + REG_OFFSET_NAME(nip), + REG_OFFSET_NAME(msr), + REG_OFFSET_NAME(ctr), + REG_OFFSET_NAME(link), + REG_OFFSET_NAME(xer), + REG_OFFSET_NAME(ccr), +#ifdef CONFIG_PPC64 + REG_OFFSET_NAME(softe), +#else + REG_OFFSET_NAME(mq), +#endif + REG_OFFSET_NAME(trap), + REG_OFFSET_NAME(dar), + REG_OFFSET_NAME(dsisr), + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + +/** + * regs_query_register_name() - query register name from its offset + * @offset: the offset of a register in struct pt_regs. + * + * regs_query_register_name() returns the name of a register from its + * offset in struct pt_regs. If the @offset is invalid, this returns NULL; + */ +const char *regs_query_register_name(unsigned int offset) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (roff->offset == offset) + return roff->name; + return NULL; +} + +/* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. */ -- cgit v0.10.2 From cb694769f0d0c1f6fb8c9dc806c0a68da1056055 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Apr 2010 13:54:39 +1000 Subject: Revert "powerpc/mm: Bump SECTION_SIZE_BITS from 16MB to 256MB" This reverts commit 7545ba6f82924d4523f8f8a2baf2e517a750265d. It breaks eHEA among other issues diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 13fe0a0..54a47ea 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -8,7 +8,7 @@ * MAX_PHYSADDR_BITS 2^N: how much physical address space we have * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space */ -#define SECTION_SIZE_BITS 28 +#define SECTION_SIZE_BITS 24 #define MAX_PHYSADDR_BITS 44 #define MAX_PHYSMEM_BITS 44 -- cgit v0.10.2 From 471c70ff39809af783c7718defe574a9ba81dd26 Mon Sep 17 00:00:00 2001 From: Torez Smith Date: Fri, 5 Mar 2010 10:43:01 +0000 Subject: powerpc/booke: Add Stack Marking support to Booke Exception Prolog This patch adds a marker to the exception stack frame to aid in debugging. It's already inserted on other platforms and xmon recognizes it and identifies exception frames when showing stack traces. Signed-off-by: Torez Smith Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index 50504ae..a0bf158 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -1,6 +1,7 @@ #ifndef __HEAD_BOOKE_H__ #define __HEAD_BOOKE_H__ +#include /* for STACK_FRAME_REGS_MARKER */ /* * Macros used for common Book-e exception handling */ @@ -48,6 +49,9 @@ stw r10,0(r11); \ rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ stw r0,GPR0(r11); \ + lis r10, STACK_FRAME_REGS_MARKER@ha;/* exception frame marker */ \ + addi r10, r10, STACK_FRAME_REGS_MARKER@l; \ + stw r10, 8(r11); \ SAVE_4GPRS(3, r11); \ SAVE_2GPRS(7, r11) -- cgit v0.10.2 From 795033c344d88dc6aa5106d0cc358656f29bd722 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 5 Mar 2010 10:43:07 +0000 Subject: powerpc/44x: break out cpu init code into stand-alone function The 47x platform supports multiple cores and shares code with 44x. Break out code that is common for initializing the primary and secondary cpus into a function which can be called for both. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 711368b..39be049 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -69,165 +69,7 @@ _ENTRY(_start); mr r27,r7 li r24,0 /* CPU number */ -/* - * In case the firmware didn't do it, we apply some workarounds - * that are good for all 440 core variants here - */ - mfspr r3,SPRN_CCR0 - rlwinm r3,r3,0,0,27 /* disable icache prefetch */ - isync - mtspr SPRN_CCR0,r3 - isync - sync - -/* - * Set up the initial MMU state - * - * We are still executing code at the virtual address - * mappings set by the firmware for the base of RAM. - * - * We first invalidate all TLB entries but the one - * we are running from. We then load the KERNELBASE - * mappings so we can begin to use kernel addresses - * natively and so the interrupt vector locations are - * permanently pinned (necessary since Book E - * implementations always have translation enabled). - * - * TODO: Use the known TLB entry we are running from to - * determine which physical region we are located - * in. This can be used to determine where in RAM - * (on a shared CPU system) or PCI memory space - * (on a DRAMless system) we are located. - * For now, we assume a perfect world which means - * we are located at the base of DRAM (physical 0). - */ - -/* - * Search TLB for entry that we are currently using. - * Invalidate all entries but the one we are using. - */ - /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ - mfspr r3,SPRN_PID /* Get PID */ - mfmsr r4 /* Get MSR */ - andi. r4,r4,MSR_IS@l /* TS=1? */ - beq wmmucr /* If not, leave STS=0 */ - oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ -wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ - sync - - bl invstr /* Find our address */ -invstr: mflr r5 /* Make it accessible */ - tlbsx r23,0,r5 /* Find entry we are in */ - li r4,0 /* Start at TLB entry 0 */ - li r3,0 /* Set PAGEID inval value */ -1: cmpw r23,r4 /* Is this our entry? */ - beq skpinv /* If so, skip the inval */ - tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ -skpinv: addi r4,r4,1 /* Increment */ - cmpwi r4,64 /* Are we done? */ - bne 1b /* If not, repeat */ - isync /* If so, context change */ - -/* - * Configure and load pinned entry into TLB slot 63. - */ - - lis r3,PAGE_OFFSET@h - ori r3,r3,PAGE_OFFSET@l - - /* Kernel is at the base of RAM */ - li r4, 0 /* Load the kernel physical address */ - - /* Load the kernel PID = 0 */ - li r0,0 - mtspr SPRN_PID,r0 - sync - - /* Initialize MMUCR */ - li r5,0 - mtspr SPRN_MMUCR,r5 - sync - - /* pageid fields */ - clrrwi r3,r3,10 /* Mask off the effective page number */ - ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M - - /* xlat fields */ - clrrwi r4,r4,10 /* Mask off the real page number */ - /* ERPN is 0 for first 4GB page */ - - /* attrib fields */ - /* Added guarded bit to protect against speculative loads/stores */ - li r5,0 - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) - - li r0,63 /* TLB slot 63 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ - tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ - tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ - - /* Force context change */ - mfmsr r0 - mtspr SPRN_SRR1, r0 - lis r0,3f@h - ori r0,r0,3f@l - mtspr SPRN_SRR0,r0 - sync - rfi - - /* If necessary, invalidate original entry we used */ -3: cmpwi r23,63 - beq 4f - li r6,0 - tlbwe r6,r23,PPC44x_TLB_PAGEID - isync - -4: -#ifdef CONFIG_PPC_EARLY_DEBUG_44x - /* Add UART mapping for early debug. */ - - /* pageid fields */ - lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h - ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K - - /* xlat fields */ - lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h - ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH - - /* attrib fields */ - li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) - li r0,62 /* TLB slot 0 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID - tlbwe r4,r0,PPC44x_TLB_XLAT - tlbwe r5,r0,PPC44x_TLB_ATTRIB - - /* Force context change */ - isync -#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ - - /* Establish the interrupt vector offsets */ - SET_IVOR(0, CriticalInput); - SET_IVOR(1, MachineCheck); - SET_IVOR(2, DataStorage); - SET_IVOR(3, InstructionStorage); - SET_IVOR(4, ExternalInput); - SET_IVOR(5, Alignment); - SET_IVOR(6, Program); - SET_IVOR(7, FloatingPointUnavailable); - SET_IVOR(8, SystemCall); - SET_IVOR(9, AuxillaryProcessorUnavailable); - SET_IVOR(10, Decrementer); - SET_IVOR(11, FixedIntervalTimer); - SET_IVOR(12, WatchdogTimer); - SET_IVOR(13, DataTLBError); - SET_IVOR(14, InstructionTLBError); - SET_IVOR(15, DebugCrit); - - /* Establish the interrupt vector base */ - lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ - mtspr SPRN_IVPR,r4 + bl init_cpu_state /* * This is where the main kernel code starts. @@ -647,6 +489,176 @@ _GLOBAL(set_context) blr /* + * Init CPU state. This is called at boot time or for secondary CPUs + * to setup initial TLB entries, setup IVORs, etc... + */ +_GLOBAL(init_cpu_state) + mflr r22 +/* + * In case the firmware didn't do it, we apply some workarounds + * that are good for all 440 core variants here + */ + mfspr r3,SPRN_CCR0 + rlwinm r3,r3,0,0,27 /* disable icache prefetch */ + isync + mtspr SPRN_CCR0,r3 + isync + sync + +/* + * Set up the initial MMU state + * + * We are still executing code at the virtual address + * mappings set by the firmware for the base of RAM. + * + * We first invalidate all TLB entries but the one + * we are running from. We then load the KERNELBASE + * mappings so we can begin to use kernel addresses + * natively and so the interrupt vector locations are + * permanently pinned (necessary since Book E + * implementations always have translation enabled). + * + * TODO: Use the known TLB entry we are running from to + * determine which physical region we are located + * in. This can be used to determine where in RAM + * (on a shared CPU system) or PCI memory space + * (on a DRAMless system) we are located. + * For now, we assume a perfect world which means + * we are located at the base of DRAM (physical 0). + */ + +/* + * Search TLB for entry that we are currently using. + * Invalidate all entries but the one we are using. + */ + /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ + mfspr r3,SPRN_PID /* Get PID */ + mfmsr r4 /* Get MSR */ + andi. r4,r4,MSR_IS@l /* TS=1? */ + beq wmmucr /* If not, leave STS=0 */ + oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ +wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ + sync + + bl invstr /* Find our address */ +invstr: mflr r5 /* Make it accessible */ + tlbsx r23,0,r5 /* Find entry we are in */ + li r4,0 /* Start at TLB entry 0 */ + li r3,0 /* Set PAGEID inval value */ +1: cmpw r23,r4 /* Is this our entry? */ + beq skpinv /* If so, skip the inval */ + tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ +skpinv: addi r4,r4,1 /* Increment */ + cmpwi r4,64 /* Are we done? */ + bne 1b /* If not, repeat */ + isync /* If so, context change */ + +/* + * Configure and load pinned entry into TLB slot 63. + */ + + lis r3,PAGE_OFFSET@h + ori r3,r3,PAGE_OFFSET@l + + /* Kernel is at the base of RAM */ + li r4, 0 /* Load the kernel physical address */ + + /* Load the kernel PID = 0 */ + li r0,0 + mtspr SPRN_PID,r0 + sync + + /* Initialize MMUCR */ + li r5,0 + mtspr SPRN_MMUCR,r5 + sync + + /* pageid fields */ + clrrwi r3,r3,10 /* Mask off the effective page number */ + ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M + + /* xlat fields */ + clrrwi r4,r4,10 /* Mask off the real page number */ + /* ERPN is 0 for first 4GB page */ + + /* attrib fields */ + /* Added guarded bit to protect against speculative loads/stores */ + li r5,0 + ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) + + li r0,63 /* TLB slot 63 */ + + tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ + tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ + tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + + /* Force context change */ + mfmsr r0 + mtspr SPRN_SRR1, r0 + lis r0,3f@h + ori r0,r0,3f@l + mtspr SPRN_SRR0,r0 + sync + rfi + + /* If necessary, invalidate original entry we used */ +3: cmpwi r23,63 + beq 4f + li r6,0 + tlbwe r6,r23,PPC44x_TLB_PAGEID + isync + +4: +#ifdef CONFIG_PPC_EARLY_DEBUG_44x + /* Add UART mapping for early debug. */ + + /* pageid fields */ + lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h + ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K + + /* xlat fields */ + lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h + ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH + + /* attrib fields */ + li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) + li r0,62 /* TLB slot 0 */ + + tlbwe r3,r0,PPC44x_TLB_PAGEID + tlbwe r4,r0,PPC44x_TLB_XLAT + tlbwe r5,r0,PPC44x_TLB_ATTRIB + + /* Force context change */ + isync +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ + + /* Establish the interrupt vector offsets */ + SET_IVOR(0, CriticalInput); + SET_IVOR(1, MachineCheck); + SET_IVOR(2, DataStorage); + SET_IVOR(3, InstructionStorage); + SET_IVOR(4, ExternalInput); + SET_IVOR(5, Alignment); + SET_IVOR(6, Program); + SET_IVOR(7, FloatingPointUnavailable); + SET_IVOR(8, SystemCall); + SET_IVOR(9, AuxillaryProcessorUnavailable); + SET_IVOR(10, Decrementer); + SET_IVOR(11, FixedIntervalTimer); + SET_IVOR(12, WatchdogTimer); + SET_IVOR(13, DataTLBError); + SET_IVOR(14, InstructionTLBError); + SET_IVOR(15, DebugCrit); + + /* Establish the interrupt vector base */ + lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ + mtspr SPRN_IVPR,r4 + + addis r22,r22,KERNELBASE@h + mtlr r22 + blr + +/* * We put a few things here that have to be page-aligned. This stuff * goes at the beginning of the data segment, which is page-aligned. */ -- cgit v0.10.2 From e7f75ad01d590243904c2d95ab47e6b2e9ef6dad Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 5 Mar 2010 10:43:12 +0000 Subject: powerpc/47x: Base ppc476 support This patch adds the base support for the 476 processor. The code was primarily written by Ben Herrenschmidt and Torez Smith, but I've been maintaining it for a while. The goal is to have a single binary that will run on 44x and 47x, but we still have some details to work out. The biggest is that the L1 cache line size differs on the two platforms, but it's currently a compile-time option. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Torez Smith Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 81de6eb..725634f 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -12,8 +12,12 @@ #define L1_CACHE_SHIFT 6 #define MAX_COPY_PREFETCH 4 #elif defined(CONFIG_PPC32) -#define L1_CACHE_SHIFT 5 #define MAX_COPY_PREFETCH 4 +#if defined(CONFIG_PPC_47x) +#define L1_CACHE_SHIFT 7 +#else +#define L1_CACHE_SHIFT 5 +#endif #else /* CONFIG_PPC64 */ #define L1_CACHE_SHIFT 7 #endif diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index abb833b..97ab508 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -365,6 +365,7 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) #define CPU_FTRS_440x6 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \ CPU_FTR_INDEXED_DCR) +#define CPU_FTRS_47X (CPU_FTRS_440x6) #define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_UNIFIED_ID_CACHE | CPU_FTR_NOEXECUTE) @@ -453,6 +454,9 @@ enum { #ifdef CONFIG_44x CPU_FTRS_44X | CPU_FTRS_440x6 | #endif +#ifdef CONFIG_PPC_47x + CPU_FTRS_47X | +#endif #ifdef CONFIG_E200 CPU_FTRS_E200 | #endif diff --git a/arch/powerpc/include/asm/mmu-44x.h b/arch/powerpc/include/asm/mmu-44x.h index 0372669..bf52d70 100644 --- a/arch/powerpc/include/asm/mmu-44x.h +++ b/arch/powerpc/include/asm/mmu-44x.h @@ -40,7 +40,7 @@ #define PPC44x_TLB_I 0x00000400 /* Caching is inhibited */ #define PPC44x_TLB_M 0x00000200 /* Memory is coherent */ #define PPC44x_TLB_G 0x00000100 /* Memory is guarded */ -#define PPC44x_TLB_E 0x00000080 /* Memory is guarded */ +#define PPC44x_TLB_E 0x00000080 /* Memory is little endian */ #define PPC44x_TLB_PERM_MASK 0x0000003f #define PPC44x_TLB_UX 0x00000020 /* User execution */ @@ -53,6 +53,52 @@ /* Number of TLB entries */ #define PPC44x_TLB_SIZE 64 +/* 47x bits */ +#define PPC47x_MMUCR_TID 0x0000ffff +#define PPC47x_MMUCR_STS 0x00010000 + +/* Page identification fields */ +#define PPC47x_TLB0_EPN_MASK 0xfffff000 /* Effective Page Number */ +#define PPC47x_TLB0_VALID 0x00000800 /* Valid flag */ +#define PPC47x_TLB0_TS 0x00000400 /* Translation address space */ +#define PPC47x_TLB0_4K 0x00000000 +#define PPC47x_TLB0_16K 0x00000010 +#define PPC47x_TLB0_64K 0x00000030 +#define PPC47x_TLB0_1M 0x00000070 +#define PPC47x_TLB0_16M 0x000000f0 +#define PPC47x_TLB0_256M 0x000001f0 +#define PPC47x_TLB0_1G 0x000003f0 +#define PPC47x_TLB0_BOLTED_R 0x00000008 /* tlbre only */ + +/* Translation fields */ +#define PPC47x_TLB1_RPN_MASK 0xfffff000 /* Real Page Number */ +#define PPC47x_TLB1_ERPN_MASK 0x000003ff + +/* Storage attribute and access control fields */ +#define PPC47x_TLB2_ATTR_MASK 0x0003ff80 +#define PPC47x_TLB2_IL1I 0x00020000 /* Memory is guarded */ +#define PPC47x_TLB2_IL1D 0x00010000 /* Memory is guarded */ +#define PPC47x_TLB2_U0 0x00008000 /* User 0 */ +#define PPC47x_TLB2_U1 0x00004000 /* User 1 */ +#define PPC47x_TLB2_U2 0x00002000 /* User 2 */ +#define PPC47x_TLB2_U3 0x00001000 /* User 3 */ +#define PPC47x_TLB2_W 0x00000800 /* Caching is write-through */ +#define PPC47x_TLB2_I 0x00000400 /* Caching is inhibited */ +#define PPC47x_TLB2_M 0x00000200 /* Memory is coherent */ +#define PPC47x_TLB2_G 0x00000100 /* Memory is guarded */ +#define PPC47x_TLB2_E 0x00000080 /* Memory is little endian */ +#define PPC47x_TLB2_PERM_MASK 0x0000003f +#define PPC47x_TLB2_UX 0x00000020 /* User execution */ +#define PPC47x_TLB2_UW 0x00000010 /* User write */ +#define PPC47x_TLB2_UR 0x00000008 /* User read */ +#define PPC47x_TLB2_SX 0x00000004 /* Super execution */ +#define PPC47x_TLB2_SW 0x00000002 /* Super write */ +#define PPC47x_TLB2_SR 0x00000001 /* Super read */ +#define PPC47x_TLB2_U_RWX (PPC47x_TLB2_UX|PPC47x_TLB2_UW|PPC47x_TLB2_UR) +#define PPC47x_TLB2_S_RWX (PPC47x_TLB2_SX|PPC47x_TLB2_SW|PPC47x_TLB2_SR) +#define PPC47x_TLB2_S_RW (PPC47x_TLB2_SW | PPC47x_TLB2_SR) +#define PPC47x_TLB2_IMG (PPC47x_TLB2_I | PPC47x_TLB2_M | PPC47x_TLB2_G) + #ifndef __ASSEMBLY__ extern unsigned int tlb_44x_hwater; @@ -79,12 +125,15 @@ typedef struct { #if (PAGE_SHIFT == 12) #define PPC44x_TLBE_SIZE PPC44x_TLB_4K +#define PPC47x_TLBE_SIZE PPC47x_TLB0_4K #define mmu_virtual_psize MMU_PAGE_4K #elif (PAGE_SHIFT == 14) #define PPC44x_TLBE_SIZE PPC44x_TLB_16K +#define PPC47x_TLBE_SIZE PPC47x_TLB0_16K #define mmu_virtual_psize MMU_PAGE_16K #elif (PAGE_SHIFT == 16) #define PPC44x_TLBE_SIZE PPC44x_TLB_64K +#define PPC47x_TLBE_SIZE PPC47x_TLB0_64K #define mmu_virtual_psize MMU_PAGE_64K #elif (PAGE_SHIFT == 18) #define PPC44x_TLBE_SIZE PPC44x_TLB_256K diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 7ffbb65..7ebf42e 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -18,6 +18,7 @@ #define MMU_FTR_TYPE_44x ASM_CONST(0x00000008) #define MMU_FTR_TYPE_FSL_E ASM_CONST(0x00000010) #define MMU_FTR_TYPE_3E ASM_CONST(0x00000020) +#define MMU_FTR_TYPE_47x ASM_CONST(0x00000040) /* * This is individual features diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 5572e86..b2d1ac6 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -817,6 +817,7 @@ #define PVR_403GC 0x00200200 #define PVR_403GCX 0x00201400 #define PVR_405GP 0x40110000 +#define PVR_476 0x11a52000 #define PVR_STB03XXX 0x40310000 #define PVR_NP405H 0x41410000 #define PVR_NP405L 0x41610000 diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 414d434..5304a37 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -191,6 +191,10 @@ #define MCSR_DCFP 0x01000000 /* D-Cache Flush Parity Error */ #define MCSR_IMPE 0x00800000 /* Imprecise Machine Check Exception */ +#define PPC47x_MCSR_GPR 0x01000000 /* GPR parity error */ +#define PPC47x_MCSR_FPR 0x00800000 /* FPR parity error */ +#define PPC47x_MCSR_IPR 0x00400000 /* Imprecise Machine Check Exception */ + #ifdef CONFIG_E500 #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ #define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */ @@ -604,5 +608,25 @@ #define DBCR_JOI 0x00000002 /* JTAG Serial Outbound Int. Enable */ #define DBCR_JII 0x00000001 /* JTAG Serial Inbound Int. Enable */ #endif /* 403GCX */ + +/* Some 476 specific registers */ +#define SPRN_SSPCR 830 +#define SPRN_USPCR 831 +#define SPRN_ISPCR 829 +#define SPRN_MMUBE0 820 +#define MMUBE0_IBE0_SHIFT 24 +#define MMUBE0_IBE1_SHIFT 16 +#define MMUBE0_IBE2_SHIFT 8 +#define MMUBE0_VBE0 0x00000004 +#define MMUBE0_VBE1 0x00000002 +#define MMUBE0_VBE2 0x00000001 +#define SPRN_MMUBE1 821 +#define MMUBE1_IBE3_SHIFT 24 +#define MMUBE1_IBE4_SHIFT 16 +#define MMUBE1_IBE5_SHIFT 8 +#define MMUBE1_VBE3 0x00000004 +#define MMUBE1_VBE4 0x00000002 +#define MMUBE1_VBE5 0x00000001 + #endif /* __ASM_POWERPC_REG_BOOKE_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 8af4949..a1d8458 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1701,6 +1701,19 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_440A, .platform = "ppc440", }, + { /* 476 core */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x11a50000, + .cpu_name = "476", + .cpu_features = CPU_FTRS_47X, + .cpu_user_features = COMMON_USER_BOOKE | + PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_47x | + MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, + .icache_bsize = 32, + .dcache_bsize = 128, + .platform = "ppc470", + }, { /* default match */ .pvr_mask = 0x00000000, .pvr_value = 0x00000000, diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 1175a85..ed4aeb9 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -373,11 +373,13 @@ syscall_exit_cont: bnel- load_dbcr0 #endif #ifdef CONFIG_44x +BEGIN_MMU_FTR_SECTION lis r4,icache_44x_need_flush@ha lwz r5,icache_44x_need_flush@l(r4) cmplwi cr0,r5,0 bne- 2f 1: +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_47x) #endif /* CONFIG_44x */ BEGIN_FTR_SECTION lwarx r7,0,r1 @@ -848,6 +850,9 @@ resume_kernel: /* interrupts are hard-disabled at this point */ restore: #ifdef CONFIG_44x +BEGIN_MMU_FTR_SECTION + b 1f +END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x) lis r4,icache_44x_need_flush@ha lwz r5,icache_44x_need_flush@l(r4) cmplwi cr0,r5,0 diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 39be049..1acd175 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -37,6 +37,7 @@ #include #include #include +#include #include "head_booke.h" @@ -191,7 +192,7 @@ interrupt_base: #endif /* Data TLB Error Interrupt */ - START_EXCEPTION(DataTLBError) + START_EXCEPTION(DataTLBError44x) mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */ mtspr SPRN_SPRG_WSCRATCH1, r11 mtspr SPRN_SPRG_WSCRATCH2, r12 @@ -282,7 +283,7 @@ tlb_44x_patch_hwater_D: mfspr r10,SPRN_DEAR /* Jump to common tlb load */ - b finish_tlb_load + b finish_tlb_load_44x 2: /* The bailout. Restore registers to pre-exception conditions @@ -302,7 +303,7 @@ tlb_44x_patch_hwater_D: * information from different registers and bailout * to a different point. */ - START_EXCEPTION(InstructionTLBError) + START_EXCEPTION(InstructionTLBError44x) mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */ mtspr SPRN_SPRG_WSCRATCH1, r11 mtspr SPRN_SPRG_WSCRATCH2, r12 @@ -378,7 +379,7 @@ tlb_44x_patch_hwater_I: mfspr r10,SPRN_SRR0 /* Jump to common TLB load point */ - b finish_tlb_load + b finish_tlb_load_44x 2: /* The bailout. Restore registers to pre-exception conditions @@ -392,15 +393,7 @@ tlb_44x_patch_hwater_I: mfspr r10, SPRN_SPRG_RSCRATCH0 b InstructionStorage - /* Debug Interrupt */ - DEBUG_CRIT_EXCEPTION - -/* - * Local functions - */ - /* - * Both the instruction and data TLB miss get to this * point to load the TLB. * r10 - EA of fault @@ -410,7 +403,7 @@ tlb_44x_patch_hwater_I: * MMUCR - loaded with proper value when we get here * Upon exit, we reload everything and RFI. */ -finish_tlb_load: +finish_tlb_load_44x: /* Combine RPN & ERPN an write WS 0 */ rlwimi r11,r12,0,0,31-PAGE_SHIFT tlbwe r11,r13,PPC44x_TLB_XLAT @@ -443,6 +436,227 @@ finish_tlb_load: mfspr r10, SPRN_SPRG_RSCRATCH0 rfi /* Force context change */ +/* TLB error interrupts for 476 + */ +#ifdef CONFIG_PPC_47x + START_EXCEPTION(DataTLBError47x) + mtspr SPRN_SPRG_WSCRATCH0,r10 /* Save some working registers */ + mtspr SPRN_SPRG_WSCRATCH1,r11 + mtspr SPRN_SPRG_WSCRATCH2,r12 + mtspr SPRN_SPRG_WSCRATCH3,r13 + mfcr r11 + mtspr SPRN_SPRG_WSCRATCH4,r11 + mfspr r10,SPRN_DEAR /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11,PAGE_OFFSET@h + cmplw cr0,r10,r11 + blt+ 3f + lis r11,swapper_pg_dir@h + ori r11,r11, swapper_pg_dir@l + li r12,0 /* MMUCR = 0 */ + b 4f + + /* Get the PGD for the current thread and setup MMUCR */ +3: mfspr r11,SPRN_SPRG3 + lwz r11,PGDIR(r11) + mfspr r12,SPRN_PID /* Get PID */ +4: mtspr SPRN_MMUCR,r12 /* Set MMUCR */ + + /* Mask of required permission bits. Note that while we + * do copy ESR:ST to _PAGE_RW position as trying to write + * to an RO page is pretty common, we don't do it with + * _PAGE_DIRTY. We could do it, but it's a fairly rare + * event so I'd rather take the overhead when it happens + * rather than adding an instruction here. We should measure + * whether the whole thing is worth it in the first place + * as we could avoid loading SPRN_ESR completely in the first + * place... + * + * TODO: Is it worth doing that mfspr & rlwimi in the first + * place or can we save a couple of instructions here ? + */ + mfspr r12,SPRN_ESR + li r13,_PAGE_PRESENT|_PAGE_ACCESSED + rlwimi r13,r12,10,30,30 + + /* Load the PTE */ + /* Compute pgdir/pmd offset */ + rlwinm r12,r10,PPC44x_PGD_OFF_SHIFT,PPC44x_PGD_OFF_MASK_BIT,29 + lwzx r11,r12,r11 /* Get pgd/pmd entry */ + + /* Word 0 is EPN,V,TS,DSIZ */ + li r12,PPC47x_TLB0_VALID | PPC47x_TLBE_SIZE + rlwimi r10,r12,0,32-PAGE_SHIFT,31 /* Insert valid and page size*/ + li r12,0 + tlbwe r10,r12,0 + + /* XXX can we do better ? Need to make sure tlbwe has established + * latch V bit in MMUCR0 before the PTE is loaded further down */ +#ifdef CONFIG_SMP + isync +#endif + + rlwinm. r12,r11,0,0,20 /* Extract pt base address */ + /* Compute pte address */ + rlwimi r12,r10,PPC44x_PTE_ADD_SHIFT,PPC44x_PTE_ADD_MASK_BIT,28 + beq 2f /* Bail if no table */ + lwz r11,0(r12) /* Get high word of pte entry */ + + /* XXX can we do better ? maybe insert a known 0 bit from r11 into the + * bottom of r12 to create a data dependency... We can also use r10 + * as destination nowadays + */ +#ifdef CONFIG_SMP + lwsync +#endif + lwz r12,4(r12) /* Get low word of pte entry */ + + andc. r13,r13,r12 /* Check permission */ + + /* Jump to common tlb load */ + beq finish_tlb_load_47x + +2: /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11,SPRN_SPRG_RSCRATCH4 + mtcr r11 + mfspr r13,SPRN_SPRG_RSCRATCH3 + mfspr r12,SPRN_SPRG_RSCRATCH2 + mfspr r11,SPRN_SPRG_RSCRATCH1 + mfspr r10,SPRN_SPRG_RSCRATCH0 + b DataStorage + + /* Instruction TLB Error Interrupt */ + /* + * Nearly the same as above, except we get our + * information from different registers and bailout + * to a different point. + */ + START_EXCEPTION(InstructionTLBError47x) + mtspr SPRN_SPRG_WSCRATCH0,r10 /* Save some working registers */ + mtspr SPRN_SPRG_WSCRATCH1,r11 + mtspr SPRN_SPRG_WSCRATCH2,r12 + mtspr SPRN_SPRG_WSCRATCH3,r13 + mfcr r11 + mtspr SPRN_SPRG_WSCRATCH4,r11 + mfspr r10,SPRN_SRR0 /* Get faulting address */ + + /* If we are faulting a kernel address, we have to use the + * kernel page tables. + */ + lis r11,PAGE_OFFSET@h + cmplw cr0,r10,r11 + blt+ 3f + lis r11,swapper_pg_dir@h + ori r11,r11, swapper_pg_dir@l + li r12,0 /* MMUCR = 0 */ + b 4f + + /* Get the PGD for the current thread and setup MMUCR */ +3: mfspr r11,SPRN_SPRG_THREAD + lwz r11,PGDIR(r11) + mfspr r12,SPRN_PID /* Get PID */ +4: mtspr SPRN_MMUCR,r12 /* Set MMUCR */ + + /* Make up the required permissions */ + li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC + + /* Load PTE */ + /* Compute pgdir/pmd offset */ + rlwinm r12,r10,PPC44x_PGD_OFF_SHIFT,PPC44x_PGD_OFF_MASK_BIT,29 + lwzx r11,r12,r11 /* Get pgd/pmd entry */ + + /* Word 0 is EPN,V,TS,DSIZ */ + li r12,PPC47x_TLB0_VALID | PPC47x_TLBE_SIZE + rlwimi r10,r12,0,32-PAGE_SHIFT,31 /* Insert valid and page size*/ + li r12,0 + tlbwe r10,r12,0 + + /* XXX can we do better ? Need to make sure tlbwe has established + * latch V bit in MMUCR0 before the PTE is loaded further down */ +#ifdef CONFIG_SMP + isync +#endif + + rlwinm. r12,r11,0,0,20 /* Extract pt base address */ + /* Compute pte address */ + rlwimi r12,r10,PPC44x_PTE_ADD_SHIFT,PPC44x_PTE_ADD_MASK_BIT,28 + beq 2f /* Bail if no table */ + + lwz r11,0(r12) /* Get high word of pte entry */ + /* XXX can we do better ? maybe insert a known 0 bit from r11 into the + * bottom of r12 to create a data dependency... We can also use r10 + * as destination nowadays + */ +#ifdef CONFIG_SMP + lwsync +#endif + lwz r12,4(r12) /* Get low word of pte entry */ + + andc. r13,r13,r12 /* Check permission */ + + /* Jump to common TLB load point */ + beq finish_tlb_load_47x + +2: /* The bailout. Restore registers to pre-exception conditions + * and call the heavyweights to help us out. + */ + mfspr r11, SPRN_SPRG_RSCRATCH4 + mtcr r11 + mfspr r13, SPRN_SPRG_RSCRATCH3 + mfspr r12, SPRN_SPRG_RSCRATCH2 + mfspr r11, SPRN_SPRG_RSCRATCH1 + mfspr r10, SPRN_SPRG_RSCRATCH0 + b InstructionStorage + +/* + * Both the instruction and data TLB miss get to this + * point to load the TLB. + * r10 - free to use + * r11 - PTE high word value + * r12 - PTE low word value + * r13 - free to use + * MMUCR - loaded with proper value when we get here + * Upon exit, we reload everything and RFI. + */ +finish_tlb_load_47x: + /* Combine RPN & ERPN an write WS 1 */ + rlwimi r11,r12,0,0,31-PAGE_SHIFT + tlbwe r11,r13,1 + + /* And make up word 2 */ + li r10,0xf85 /* Mask to apply from PTE */ + rlwimi r10,r12,29,30,30 /* DIRTY -> SW position */ + and r11,r12,r10 /* Mask PTE bits to keep */ + andi. r10,r12,_PAGE_USER /* User page ? */ + beq 1f /* nope, leave U bits empty */ + rlwimi r11,r11,3,26,28 /* yes, copy S bits to U */ +1: tlbwe r11,r13,2 + + /* Done...restore registers and get out of here. + */ + mfspr r11, SPRN_SPRG_RSCRATCH4 + mtcr r11 + mfspr r13, SPRN_SPRG_RSCRATCH3 + mfspr r12, SPRN_SPRG_RSCRATCH2 + mfspr r11, SPRN_SPRG_RSCRATCH1 + mfspr r10, SPRN_SPRG_RSCRATCH0 + rfi + +#endif /* CONFIG_PPC_47x */ + + /* Debug Interrupt */ + /* + * This statement needs to exist at the end of the IVPR + * definition just in case you end up taking a debug + * exception within another exception. + */ + DEBUG_CRIT_EXCEPTION + /* * Global functions */ @@ -491,9 +705,18 @@ _GLOBAL(set_context) /* * Init CPU state. This is called at boot time or for secondary CPUs * to setup initial TLB entries, setup IVORs, etc... + * */ _GLOBAL(init_cpu_state) mflr r22 +#ifdef CONFIG_PPC_47x + /* We use the PVR to differenciate 44x cores from 476 */ + mfspr r3,SPRN_PVR + srwi r3,r3,16 + cmplwi cr0,r3,PVR_476@h + beq head_start_47x +#endif /* CONFIG_PPC_47x */ + /* * In case the firmware didn't do it, we apply some workarounds * that are good for all 440 core variants here @@ -506,7 +729,7 @@ _GLOBAL(init_cpu_state) sync /* - * Set up the initial MMU state + * Set up the initial MMU state for 44x * * We are still executing code at the virtual address * mappings set by the firmware for the base of RAM. @@ -646,16 +869,257 @@ skpinv: addi r4,r4,1 /* Increment */ SET_IVOR(10, Decrementer); SET_IVOR(11, FixedIntervalTimer); SET_IVOR(12, WatchdogTimer); - SET_IVOR(13, DataTLBError); - SET_IVOR(14, InstructionTLBError); + SET_IVOR(13, DataTLBError44x); + SET_IVOR(14, InstructionTLBError44x); SET_IVOR(15, DebugCrit); + b head_start_common + + +#ifdef CONFIG_PPC_47x + +#ifdef CONFIG_SMP + +/* Entry point for secondary 47x processors */ +_GLOBAL(start_secondary_47x) + mr r24,r3 /* CPU number */ + + bl init_cpu_state + + /* Now we need to bolt the rest of kernel memory which + * is done in C code. We must be careful because our task + * struct or our stack can (and will probably) be out + * of reach of the initial 256M TLB entry, so we use a + * small temporary stack in .bss for that. This works + * because only one CPU at a time can be in this code + */ + lis r1,temp_boot_stack@h + ori r1,r1,temp_boot_stack@l + addi r1,r1,1024-STACK_FRAME_OVERHEAD + li r0,0 + stw r0,0(r1) + bl mmu_init_secondary + + /* Now we can get our task struct and real stack pointer */ + + /* Get current_thread_info and current */ + lis r1,secondary_ti@ha + lwz r1,secondary_ti@l(r1) + lwz r2,TI_TASK(r1) + + /* Current stack pointer */ + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + stw r0,0(r1) + + /* Kernel stack for exception entry in SPRG3 */ + addi r4,r2,THREAD /* init task's THREAD */ + mtspr SPRN_SPRG3,r4 + + b start_secondary + +#endif /* CONFIG_SMP */ + +/* + * Set up the initial MMU state for 44x + * + * We are still executing code at the virtual address + * mappings set by the firmware for the base of RAM. + */ + +head_start_47x: + /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ + mfspr r3,SPRN_PID /* Get PID */ + mfmsr r4 /* Get MSR */ + andi. r4,r4,MSR_IS@l /* TS=1? */ + beq 1f /* If not, leave STS=0 */ + oris r3,r3,PPC47x_MMUCR_STS@h /* Set STS=1 */ +1: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ + sync + + /* Find the entry we are running from */ + bl 1f +1: mflr r23 + tlbsx r23,0,r23 + tlbre r24,r23,0 + tlbre r25,r23,1 + tlbre r26,r23,2 + +/* + * Cleanup time + */ + + /* Initialize MMUCR */ + li r5,0 + mtspr SPRN_MMUCR,r5 + sync + +clear_all_utlb_entries: + + #; Set initial values. + + addis r3,0,0x8000 + addi r4,0,0 + addi r5,0,0 + b clear_utlb_entry + + #; Align the loop to speed things up. + + .align 6 + +clear_utlb_entry: + + tlbwe r4,r3,0 + tlbwe r5,r3,1 + tlbwe r5,r3,2 + addis r3,r3,0x2000 + cmpwi r3,0 + bne clear_utlb_entry + addis r3,0,0x8000 + addis r4,r4,0x100 + cmpwi r4,0 + bne clear_utlb_entry + + #; Restore original entry. + + oris r23,r23,0x8000 /* specify the way */ + tlbwe r24,r23,0 + tlbwe r25,r23,1 + tlbwe r26,r23,2 + +/* + * Configure and load pinned entry into TLB for the kernel core + */ + + lis r3,PAGE_OFFSET@h + ori r3,r3,PAGE_OFFSET@l + + /* Kernel is at the base of RAM */ + li r4, 0 /* Load the kernel physical address */ + + /* Load the kernel PID = 0 */ + li r0,0 + mtspr SPRN_PID,r0 + sync + + /* Word 0 */ + clrrwi r3,r3,12 /* Mask off the effective page number */ + ori r3,r3,PPC47x_TLB0_VALID | PPC47x_TLB0_256M + + /* Word 1 */ + clrrwi r4,r4,12 /* Mask off the real page number */ + /* ERPN is 0 for first 4GB page */ + /* Word 2 */ + li r5,0 + ori r5,r5,PPC47x_TLB2_S_RWX +#ifdef CONFIG_SMP + ori r5,r5,PPC47x_TLB2_M +#endif + + /* We write to way 0 and bolted 0 */ + lis r0,0x8800 + tlbwe r3,r0,0 + tlbwe r4,r0,1 + tlbwe r5,r0,2 + +/* + * Configure SSPCR, ISPCR and USPCR for now to search everything, we can fix + * them up later + */ + LOAD_REG_IMMEDIATE(r3, 0x9abcdef0) + mtspr SPRN_SSPCR,r3 + mtspr SPRN_USPCR,r3 + LOAD_REG_IMMEDIATE(r3, 0x12345670) + mtspr SPRN_ISPCR,r3 + + /* Force context change */ + mfmsr r0 + mtspr SPRN_SRR1, r0 + lis r0,3f@h + ori r0,r0,3f@l + mtspr SPRN_SRR0,r0 + sync + rfi + + /* Invalidate original entry we used */ +3: + rlwinm r24,r24,0,21,19 /* clear the "valid" bit */ + tlbwe r24,r23,0 + addi r24,0,0 + tlbwe r24,r23,1 + tlbwe r24,r23,2 + isync /* Clear out the shadow TLB entries */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_44x + /* Add UART mapping for early debug. */ + + /* Word 0 */ + lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h + ori r3,r3,PPC47x_TLB0_VALID | PPC47x_TLB0_TS | PPC47x_TLB0_1M + + /* Word 1 */ + lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h + ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH + + /* Word 2 */ + li r5,(PPC47x_TLB2_S_RW | PPC47x_TLB2_IMG) + + /* Bolted in way 0, bolt slot 5, we -hope- we don't hit the same + * congruence class as the kernel, we need to make sure of it at + * some point + */ + lis r0,0x8d00 + tlbwe r3,r0,0 + tlbwe r4,r0,1 + tlbwe r5,r0,2 + + /* Force context change */ + isync +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ + + /* Establish the interrupt vector offsets */ + SET_IVOR(0, CriticalInput); + SET_IVOR(1, MachineCheckA); + SET_IVOR(2, DataStorage); + SET_IVOR(3, InstructionStorage); + SET_IVOR(4, ExternalInput); + SET_IVOR(5, Alignment); + SET_IVOR(6, Program); + SET_IVOR(7, FloatingPointUnavailable); + SET_IVOR(8, SystemCall); + SET_IVOR(9, AuxillaryProcessorUnavailable); + SET_IVOR(10, Decrementer); + SET_IVOR(11, FixedIntervalTimer); + SET_IVOR(12, WatchdogTimer); + SET_IVOR(13, DataTLBError47x); + SET_IVOR(14, InstructionTLBError47x); + SET_IVOR(15, DebugCrit); + + /* We configure icbi to invalidate 128 bytes at a time since the + * current 32-bit kernel code isn't too happy with icache != dcache + * block size + */ + mfspr r3,SPRN_CCR0 + oris r3,r3,0x0020 + mtspr SPRN_CCR0,r3 + isync + +#endif /* CONFIG_PPC_47x */ + +/* + * Here we are back to code that is common between 44x and 47x + * + * We proceed to further kernel initialization and return to the + * main kernel entry + */ +head_start_common: /* Establish the interrupt vector base */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ mtspr SPRN_IVPR,r4 addis r22,r22,KERNELBASE@h mtlr r22 + isync blr /* @@ -683,3 +1147,9 @@ swapper_pg_dir: */ abatron_pteptrs: .space 8 + +#ifdef CONFIG_SMP + .align 12 +temp_boot_stack: + .space 1024 +#endif /* CONFIG_SMP */ diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 8649f53..8043d1b 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -441,7 +441,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) addi r3,r3,L1_CACHE_BYTES bdnz 0b sync -#ifndef CONFIG_44x +#ifdef CONFIG_44x /* We don't flush the icache on 44x. Those have a virtual icache * and we don't have access to the virtual address here (it's * not the page vaddr but where it's mapped in user space). The @@ -449,15 +449,19 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) * a change in the address space occurs, before returning to * user space */ +BEGIN_MMU_FTR_SECTION + blr +END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x) +#endif /* CONFIG_44x */ mtctr r4 1: icbi 0,r6 addi r6,r6,L1_CACHE_BYTES bdnz 1b sync isync -#endif /* CONFIG_44x */ blr +#ifndef CONFIG_BOOKE /* * Flush a particular page from the data cache to RAM, identified * by its physical address. We turn off the MMU so we can just use @@ -490,6 +494,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) mtmsr r10 /* restore DR */ isync blr +#endif /* CONFIG_BOOKE */ /* * Clear pages using the dcbz instruction, which doesn't cause any diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index e36f94f..3fe4de2 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -495,6 +495,14 @@ int __devinit start_secondary(void *unused) current->active_mm = &init_mm; smp_store_cpu_info(cpu); + +#if defined(CONFIG_BOOKE) || defined(CONFIG_40x) + /* Clear any pending timer interrupts */ + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); + + /* Enable decrementer interrupt */ + mtspr(SPRN_TCR, TCR_DIE); +#endif set_dec(tb_ticks_per_jiffy); preempt_disable(); cpu_callin_map[cpu] = 1; diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c index 3986264..d8c6efb 100644 --- a/arch/powerpc/mm/44x_mmu.c +++ b/arch/powerpc/mm/44x_mmu.c @@ -38,7 +38,9 @@ unsigned int tlb_44x_index; /* = 0 */ unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS; int icache_44x_need_flush; -static void __init ppc44x_update_tlb_hwater(void) +unsigned long tlb_47x_boltmap[1024/8]; + +static void __cpuinit ppc44x_update_tlb_hwater(void) { extern unsigned int tlb_44x_patch_hwater_D[]; extern unsigned int tlb_44x_patch_hwater_I[]; @@ -59,7 +61,7 @@ static void __init ppc44x_update_tlb_hwater(void) } /* - * "Pins" a 256MB TLB entry in AS0 for kernel lowmem + * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 44x type MMU */ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) { @@ -67,12 +69,18 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) ppc44x_update_tlb_hwater(); + mtspr(SPRN_MMUCR, 0); + __asm__ __volatile__( "tlbwe %2,%3,%4\n" "tlbwe %1,%3,%5\n" "tlbwe %0,%3,%6\n" : +#ifdef CONFIG_PPC47x + : "r" (PPC47x_TLB2_S_RWX), +#else : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), +#endif "r" (phys), "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M), "r" (entry), @@ -81,8 +89,93 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) "i" (PPC44x_TLB_ATTRIB)); } +static int __init ppc47x_find_free_bolted(void) +{ + unsigned int mmube0 = mfspr(SPRN_MMUBE0); + unsigned int mmube1 = mfspr(SPRN_MMUBE1); + + if (!(mmube0 & MMUBE0_VBE0)) + return 0; + if (!(mmube0 & MMUBE0_VBE1)) + return 1; + if (!(mmube0 & MMUBE0_VBE2)) + return 2; + if (!(mmube1 & MMUBE1_VBE3)) + return 3; + if (!(mmube1 & MMUBE1_VBE4)) + return 4; + if (!(mmube1 & MMUBE1_VBE5)) + return 5; + return -1; +} + +static void __init ppc47x_update_boltmap(void) +{ + unsigned int mmube0 = mfspr(SPRN_MMUBE0); + unsigned int mmube1 = mfspr(SPRN_MMUBE1); + + if (mmube0 & MMUBE0_VBE0) + __set_bit((mmube0 >> MMUBE0_IBE0_SHIFT) & 0xff, + tlb_47x_boltmap); + if (mmube0 & MMUBE0_VBE1) + __set_bit((mmube0 >> MMUBE0_IBE1_SHIFT) & 0xff, + tlb_47x_boltmap); + if (mmube0 & MMUBE0_VBE2) + __set_bit((mmube0 >> MMUBE0_IBE2_SHIFT) & 0xff, + tlb_47x_boltmap); + if (mmube1 & MMUBE1_VBE3) + __set_bit((mmube1 >> MMUBE1_IBE3_SHIFT) & 0xff, + tlb_47x_boltmap); + if (mmube1 & MMUBE1_VBE4) + __set_bit((mmube1 >> MMUBE1_IBE4_SHIFT) & 0xff, + tlb_47x_boltmap); + if (mmube1 & MMUBE1_VBE5) + __set_bit((mmube1 >> MMUBE1_IBE5_SHIFT) & 0xff, + tlb_47x_boltmap); +} + +/* + * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 47x type MMU + */ +static void __cpuinit ppc47x_pin_tlb(unsigned int virt, unsigned int phys) +{ + unsigned int rA; + int bolted; + + /* Base rA is HW way select, way 0, bolted bit set */ + rA = 0x88000000; + + /* Look for a bolted entry slot */ + bolted = ppc47x_find_free_bolted(); + BUG_ON(bolted < 0); + + /* Insert bolted slot number */ + rA |= bolted << 24; + + pr_debug("256M TLB entry for 0x%08x->0x%08x in bolt slot %d\n", + virt, phys, bolted); + + mtspr(SPRN_MMUCR, 0); + + __asm__ __volatile__( + "tlbwe %2,%3,0\n" + "tlbwe %1,%3,1\n" + "tlbwe %0,%3,2\n" + : + : "r" (PPC47x_TLB2_SW | PPC47x_TLB2_SR | + PPC47x_TLB2_SX +#ifdef CONFIG_SMP + | PPC47x_TLB2_M +#endif + ), + "r" (phys), + "r" (virt | PPC47x_TLB0_VALID | PPC47x_TLB0_256M), + "r" (rA)); +} + void __init MMU_init_hw(void) { + /* This is not useful on 47x but won't hurt either */ ppc44x_update_tlb_hwater(); flush_instruction_cache(); @@ -95,8 +188,51 @@ unsigned long __init mmu_mapin_ram(unsigned long top) /* Pin in enough TLBs to cover any lowmem not covered by the * initial 256M mapping established in head_44x.S */ for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; - addr += PPC_PIN_SIZE) - ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); + addr += PPC_PIN_SIZE) { + if (mmu_has_feature(MMU_FTR_TYPE_47x)) + ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); + else + ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); + } + if (mmu_has_feature(MMU_FTR_TYPE_47x)) { + ppc47x_update_boltmap(); +#ifdef DEBUG + { + int i; + + printk(KERN_DEBUG "bolted entries: "); + for (i = 0; i < 255; i++) { + if (test_bit(i, tlb_47x_boltmap)) + printk("%d ", i); + } + printk("\n"); + } +#endif /* DEBUG */ + } return total_lowmem; } + +#ifdef CONFIG_SMP +void __cpuinit mmu_init_secondary(int cpu) +{ + unsigned long addr; + + /* Pin in enough TLBs to cover any lowmem not covered by the + * initial 256M mapping established in head_44x.S + * + * WARNING: This is called with only the first 256M of the + * linear mapping in the TLB and we can't take faults yet + * so beware of what this code uses. It runs off a temporary + * stack. current (r2) isn't initialized, smp_processor_id() + * will not work, current thread info isn't accessible, ... + */ + for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; + addr += PPC_PIN_SIZE) { + if (mmu_has_feature(MMU_FTR_TYPE_47x)) + ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); + else + ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); + } +} +#endif /* CONFIG_SMP */ diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index 1f2d9ff..ddfd7ad 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -395,10 +395,18 @@ void __init mmu_context_init(void) * the PID/TID comparison is disabled, so we can use a TID of zero * to represent all kernel pages as shared among all contexts. * -- Dan + * + * The IBM 47x core supports 16-bit PIDs, thus 65535 contexts. We + * should normally never have to steal though the facility is + * present if needed. + * -- BenH */ if (mmu_has_feature(MMU_FTR_TYPE_8xx)) { first_context = 0; last_context = 15; + } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { + first_context = 1; + last_context = 65535; } else { first_context = 1; last_context = 255; diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index d49a775..eb11d5d 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -69,12 +69,7 @@ static inline void _tlbil_va(unsigned long address, unsigned int pid, } #endif /* CONIFG_8xx */ -/* - * As of today, we don't support tlbivax broadcast on any - * implementation. When that becomes the case, this will be - * an extern. - */ -#ifdef CONFIG_PPC_BOOK3E +#if defined(CONFIG_PPC_BOOK3E) || defined(CONFIG_PPC_47x) extern void _tlbivax_bcast(unsigned long address, unsigned int pid, unsigned int tsize, unsigned int ind); #else diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index bbdc5b5..e925cb5 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -10,7 +10,7 @@ * - tlbil_va * - tlbil_pid * - tlbil_all - * - tlbivax_bcast (not yet) + * - tlbivax_bcast * * Code mostly moved over from misc_32.S * @@ -33,6 +33,7 @@ #include #include #include +#include #if defined(CONFIG_40x) @@ -65,7 +66,7 @@ _GLOBAL(__tlbil_va) * Nothing to do for 8xx, everything is inline */ -#elif defined(CONFIG_44x) +#elif defined(CONFIG_44x) /* Includes 47x */ /* * 440 implementation uses tlbsx/we for tlbil_va and a full sweep @@ -73,7 +74,13 @@ _GLOBAL(__tlbil_va) */ _GLOBAL(__tlbil_va) mfspr r5,SPRN_MMUCR - rlwimi r5,r4,0,24,31 /* Set TID */ + mfmsr r10 + + /* + * We write 16 bits of STID since 47x supports that much, we + * will never be passed out of bounds values on 440 (hopefully) + */ + rlwimi r5,r4,0,16,31 /* We have to run the search with interrupts disabled, otherwise * an interrupt which causes a TLB miss can clobber the MMUCR @@ -83,24 +90,41 @@ _GLOBAL(__tlbil_va) * and restoring MMUCR, so only normal interrupts have to be * taken care of. */ - mfmsr r4 wrteei 0 mtspr SPRN_MMUCR,r5 - tlbsx. r3, 0, r3 - wrtee r4 - bne 1f + tlbsx. r6,0,r3 + bne 10f sync - /* There are only 64 TLB entries, so r3 < 64, - * which means bit 22, is clear. Since 22 is - * the V bit in the TLB_PAGEID, loading this +BEGIN_MMU_FTR_SECTION + b 2f +END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x) + /* On 440 There are only 64 TLB entries, so r3 < 64, which means bit + * 22, is clear. Since 22 is the V bit in the TLB_PAGEID, loading this * value will invalidate the TLB entry. */ - tlbwe r3, r3, PPC44x_TLB_PAGEID + tlbwe r6,r6,PPC44x_TLB_PAGEID isync -1: blr +10: wrtee r10 + blr +2: +#ifdef CONFIG_PPC_47x + oris r7,r6,0x8000 /* specify way explicitely */ + clrrwi r4,r3,12 /* get an EPN for the hashing with V = 0 */ + ori r4,r4,PPC47x_TLBE_SIZE + tlbwe r4,r7,0 /* write it */ + isync + wrtee r10 + blr +#else /* CONFIG_PPC_47x */ +1: trap + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; +#endif /* !CONFIG_PPC_47x */ _GLOBAL(_tlbil_all) _GLOBAL(_tlbil_pid) +BEGIN_MMU_FTR_SECTION + b 2f +END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x) li r3,0 sync @@ -115,6 +139,76 @@ _GLOBAL(_tlbil_pid) isync blr +2: +#ifdef CONFIG_PPC_47x + /* 476 variant. There's not simple way to do this, hopefully we'll + * try to limit the amount of such full invalidates + */ + mfmsr r11 /* Interrupts off */ + wrteei 0 + li r3,-1 /* Current set */ + lis r10,tlb_47x_boltmap@h + ori r10,r10,tlb_47x_boltmap@l + lis r7,0x8000 /* Specify way explicitely */ + + b 9f /* For each set */ + +1: li r9,4 /* Number of ways */ + li r4,0 /* Current way */ + li r6,0 /* Default entry value 0 */ + andi. r0,r8,1 /* Check if way 0 is bolted */ + mtctr r9 /* Load way counter */ + bne- 3f /* Bolted, skip loading it */ + +2: /* For each way */ + or r5,r3,r4 /* Make way|index for tlbre */ + rlwimi r5,r5,16,8,15 /* Copy index into position */ + tlbre r6,r5,0 /* Read entry */ +3: addis r4,r4,0x2000 /* Next way */ + andi. r0,r6,PPC47x_TLB0_VALID /* Valid entry ? */ + beq 4f /* Nope, skip it */ + rlwimi r7,r5,0,1,2 /* Insert way number */ + rlwinm r6,r6,0,21,19 /* Clear V */ + tlbwe r6,r7,0 /* Write it */ +4: bdnz 2b /* Loop for each way */ + srwi r8,r8,1 /* Next boltmap bit */ +9: cmpwi cr1,r3,255 /* Last set done ? */ + addi r3,r3,1 /* Next set */ + beq cr1,1f /* End of loop */ + andi. r0,r3,0x1f /* Need to load a new boltmap word ? */ + bne 1b /* No, loop */ + lwz r8,0(r10) /* Load boltmap entry */ + addi r10,r10,4 /* Next word */ + b 1b /* Then loop */ +1: isync /* Sync shadows */ + wrtee r11 +#else /* CONFIG_PPC_47x */ +1: trap + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; +#endif /* !CONFIG_PPC_47x */ + blr + +#ifdef CONFIG_PPC_47x +/* + * _tlbivax_bcast is only on 47x. We don't bother doing a runtime + * check though, it will blow up soon enough if we mistakenly try + * to use it on a 440. + */ +_GLOBAL(_tlbivax_bcast) + mfspr r5,SPRN_MMUCR + mfmsr r10 + rlwimi r5,r4,0,16,31 + wrteei 0 + mtspr SPRN_MMUCR,r5 +/* tlbivax 0,r3 - use .long to avoid binutils deps */ + .long 0x7c000624 | (r3 << 11) + isync + eieio + tlbsync + sync + wrtee r10 + blr +#endif /* CONFIG_PPC_47x */ #elif defined(CONFIG_FSL_BOOKE) /* diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 7486bff..9365e530 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -1,3 +1,12 @@ +config PPC_47x + bool "Support for 47x variant" + depends on 44x + default n + select MPIC + help + This option enables support for the 47x family of processors and is + not currently compatible with other 44x or 46x varients + config BAMBOO bool "Bamboo" depends on 44x diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index a8aae0b..d361f81 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -43,7 +43,7 @@ config 40x select PPC_PCI_CHOICE config 44x - bool "AMCC 44x" + bool "AMCC 44x, 46x or 47x" select PPC_DCR_NATIVE select PPC_UDBG_16550 select 4xx_SOC @@ -294,7 +294,7 @@ config PPC_PERF_CTRS This enables the powerpc-specific perf_event back-end. config SMP - depends on PPC_BOOK3S || PPC_BOOK3E || FSL_BOOKE + depends on PPC_BOOK3S || PPC_BOOK3E || FSL_BOOKE || PPC_47x bool "Symmetric multi-processing support" ---help--- This enables support for systems with more than one CPU. If you have @@ -322,6 +322,7 @@ config NR_CPUS config NOT_COHERENT_CACHE bool depends on 4xx || 8xx || E200 || PPC_MPC512x || GAMECUBE_COMMON + default n if PPC_47x default y config CHECK_CACHE_COHERENCY -- cgit v0.10.2 From fc5e709731429bc2db27897630e7c0089f297680 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 5 Mar 2010 03:43:18 +0000 Subject: powerpc/476: add machine check handler for 47x core The 47x core's MCSR varies from 44x, so it needs it's own machine check handler. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 97ab508..e3cba4e 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -72,6 +72,7 @@ extern int machine_check_4xx(struct pt_regs *regs); extern int machine_check_440A(struct pt_regs *regs); extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); +extern int machine_check_47x(struct pt_regs *regs); /* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index a1d8458..ad6baf8 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1712,6 +1712,7 @@ static struct cpu_spec __initdata cpu_specs[] = { MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, .icache_bsize = 32, .dcache_bsize = 128, + .machine_check = machine_check_47x, .platform = "ppc470", }, { /* default match */ diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 29d128e..ca7ce85 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -380,6 +380,46 @@ int machine_check_440A(struct pt_regs *regs) } return 0; } + +int machine_check_47x(struct pt_regs *regs) +{ + unsigned long reason = get_mc_reason(regs); + u32 mcsr; + + printk(KERN_ERR "Machine check in kernel mode.\n"); + if (reason & ESR_IMCP) { + printk(KERN_ERR + "Instruction Synchronous Machine Check exception\n"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + return 0; + } + mcsr = mfspr(SPRN_MCSR); + if (mcsr & MCSR_IB) + printk(KERN_ERR "Instruction Read PLB Error\n"); + if (mcsr & MCSR_DRB) + printk(KERN_ERR "Data Read PLB Error\n"); + if (mcsr & MCSR_DWB) + printk(KERN_ERR "Data Write PLB Error\n"); + if (mcsr & MCSR_TLBP) + printk(KERN_ERR "TLB Parity Error\n"); + if (mcsr & MCSR_ICP) { + flush_instruction_cache(); + printk(KERN_ERR "I-Cache Parity Error\n"); + } + if (mcsr & MCSR_DCSP) + printk(KERN_ERR "D-Cache Search Parity Error\n"); + if (mcsr & PPC47x_MCSR_GPR) + printk(KERN_ERR "GPR Parity Error\n"); + if (mcsr & PPC47x_MCSR_FPR) + printk(KERN_ERR "FPR Parity Error\n"); + if (mcsr & PPC47x_MCSR_IPR) + printk(KERN_ERR "Machine Check exception is imprecise\n"); + + /* Clear MCSR */ + mtspr(SPRN_MCSR, mcsr); + + return 0; +} #elif defined(CONFIG_E500) int machine_check_e500(struct pt_regs *regs) { -- cgit v0.10.2 From 221c185d4e11b4061409da5d592779ced484614c Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 5 Mar 2010 10:43:24 +0000 Subject: powerpc/476: Add isync after loading mmu and debug spr's 476 requires an isync after loading MMU and debug related SPR's. Some of these are in performance-critical paths and may need to be optimized, but initially, we're playing it safe. Signed-off-by: Torez Smith Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index b36f074..c533525 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -114,6 +114,9 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) #ifdef CONFIG_PPC_ADV_DEBUG_REGS regs->msr &= ~MSR_CE; mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); +#ifdef CONFIG_PPC_47x + isync(); +#endif #endif /* diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e4d71ce..9d255b4 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -371,6 +371,9 @@ int set_dabr(unsigned long dabr) /* XXX should we have a CPU_FTR_HAS_DABR ? */ #ifdef CONFIG_PPC_ADV_DEBUG_REGS mtspr(SPRN_DAC1, dabr); +#ifdef CONFIG_PPC_47x + isync(); +#endif #elif defined(CONFIG_PPC_BOOK3S) mtspr(SPRN_DABR, dabr); #endif -- cgit v0.10.2 From b4e8c8dd8456c1d3685fb5b715c9795d250f500e Mon Sep 17 00:00:00 2001 From: Torez Smith Date: Fri, 5 Mar 2010 10:45:54 +0000 Subject: powerpc/4xx: Simple platform for the ISS 4xx simulator This is a trivial 4xx plaform that uses the new simple bsp from Josh and is handy to use in simulators such as ISS or even Mambo who don't properly implement most of the actual devices in the SoC but really only the core. Signed-off-by: Torez Smith Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 25e889c..ad0df7d 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -44,6 +44,7 @@ $(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405 $(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405 $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405 $(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405 +$(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405 $(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405 @@ -77,7 +78,7 @@ src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \ virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \ cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c \ - gamecube-head.S gamecube.c wii-head.S wii.c + gamecube-head.S gamecube.c wii-head.S wii.c treeboot-iss4xx.c src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(addprefix $(obj)/, $(src-boot)) @@ -206,6 +207,8 @@ image-$(CONFIG_TAISHAN) += cuImage.taishan image-$(CONFIG_KATMAI) += cuImage.katmai image-$(CONFIG_WARP) += cuImage.warp image-$(CONFIG_YOSEMITE) += cuImage.yosemite +image-$(CONFIG_ISS4xx) += treeImage.iss4xx \ + treeImage.iss4xx-mpic # Board ports in arch/powerpc/platform/8xx/Kconfig image-$(CONFIG_MPC86XADS) += cuImage.mpc866ads diff --git a/arch/powerpc/boot/dts/iss4xx-mpic.dts b/arch/powerpc/boot/dts/iss4xx-mpic.dts new file mode 100644 index 0000000..23e9d9b --- /dev/null +++ b/arch/powerpc/boot/dts/iss4xx-mpic.dts @@ -0,0 +1,155 @@ +/* + * Device Tree Source for IBM Embedded PPC 476 Platform + * + * Copyright 2010 Torez Smith, IBM Corporation. + * + * Based on earlier code: + * Copyright (c) 2006, 2007 IBM Corp. + * Josh Boyer , David Gibson + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +/memreserve/ 0x01f00000 0x00100000; + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "ibm,iss-4xx"; + compatible = "ibm,iss-4xx"; + dcr-parent = <&{/cpus/cpu@0}>; + + aliases { + serial0 = &UART0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,4xx"; // real CPU changed in sim + reg = <0>; + clock-frequency = <100000000>; // 100Mhz :-) + timebase-frequency = <100000000>; + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "ok"; + }; + cpu@1 { + device_type = "cpu"; + model = "PowerPC,4xx"; // real CPU changed in sim + reg = <1>; + clock-frequency = <100000000>; // 100Mhz :-) + timebase-frequency = <100000000>; + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "disabled"; + enable-method = "spin-table"; + cpu-release-addr = <0 0x01f00100>; + }; + cpu@2 { + device_type = "cpu"; + model = "PowerPC,4xx"; // real CPU changed in sim + reg = <2>; + clock-frequency = <100000000>; // 100Mhz :-) + timebase-frequency = <100000000>; + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "disabled"; + enable-method = "spin-table"; + cpu-release-addr = <0 0x01f00200>; + }; + cpu@3 { + device_type = "cpu"; + model = "PowerPC,4xx"; // real CPU changed in sim + reg = <3>; + clock-frequency = <100000000>; // 100Mhz :-) + timebase-frequency = <100000000>; + i-cache-line-size = <32>; + d-cache-line-size = <32>; + i-cache-size = <32768>; + d-cache-size = <32768>; + dcr-controller; + dcr-access-method = "native"; + status = "disabled"; + enable-method = "spin-table"; + cpu-release-addr = <0 0x01f00300>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x00000000 0x00000000>; // Filled in by zImage + + }; + + MPIC: interrupt-controller { + compatible = "chrp,open-pic"; + interrupt-controller; + dcr-reg = <0xffc00000 0x00030000>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + + }; + + plb { + compatible = "ibm,plb-4xx", "ibm,plb4"; /* Could be PLB6, doesn't matter */ + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; // Filled in by zImage + + POB0: opb { + compatible = "ibm,opb-4xx", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Wish there was a nicer way of specifying a full 32-bit + range */ + ranges = <0x00000000 0x00000001 0x00000000 0x80000000 + 0x80000000 0x00000001 0x80000000 0x80000000>; + clock-frequency = <0>; // Filled in by zImage + UART0: serial@40000200 { + device_type = "serial"; + compatible = "ns16550a"; + reg = <0x40000200 0x00000008>; + virtual-reg = <0xe0000200>; + clock-frequency = <11059200>; + current-speed = <115200>; + interrupt-parent = <&MPIC>; + interrupts = <0x0 0x2>; + }; + }; + }; + + nvrtc { + compatible = "ds1743-nvram", "ds1743", "rtc-ds1743"; + reg = <0 0xEF703000 0x2000>; + }; + iss-block { + compatible = "ibm,iss-sim-block-device"; + reg = <0 0xEF701000 0x1000>; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@40000200"; + }; +}; diff --git a/arch/powerpc/boot/dts/iss4xx.dts b/arch/powerpc/boot/dts/iss4xx.dts new file mode 100644 index 0000000..4ff6555 --- /dev/null +++ b/arch/powerpc/boot/dts/iss4xx.dts @@ -0,0 +1,116 @@ +/* + * Device Tree Source for IBM Embedded PPC 476 Platform + * + * Copyright 2010 Torez Smith, IBM Corporation. + * + * Based on earlier code: + * Copyright (c) 2006, 2007 IBM Corp. + * Josh Boyer , David Gibson + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "ibm,iss-4xx"; + compatible = "ibm,iss-4xx"; + dcr-parent = <&{/cpus/cpu@0}>; + + aliases { + serial0 = &UART0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,4xx"; // real CPU changed in sim + reg = <0x00000000>; + clock-frequency = <100000000>; // 100Mhz :-) + timebase-frequency = <100000000>; + i-cache-line-size = <32>; // may need fixup in sim + d-cache-line-size = <32>; // may need fixup in sim + i-cache-size = <32768>; /* may need fixup in sim */ + d-cache-size = <32768>; /* may need fixup in sim */ + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x00000000 0x00000000>; // Filled in by zImage + }; + + UIC0: interrupt-controller0 { + compatible = "ibm,uic-4xx", "ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0x0c0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + + }; + + UIC1: interrupt-controller1 { + compatible = "ibm,uic-4xx", "ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0x0d0 0x009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */ + interrupt-parent = <&UIC0>; + }; + + plb { + compatible = "ibm,plb-4xx", "ibm,plb4"; /* Could be PLB6, doesn't matter */ + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <0>; // Filled in by zImage + + POB0: opb { + compatible = "ibm,opb-4xx", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Wish there was a nicer way of specifying a full 32-bit + range */ + ranges = <0x00000000 0x00000001 0x00000000 0x80000000 + 0x80000000 0x00000001 0x80000000 0x80000000>; + clock-frequency = <0>; // Filled in by zImage + UART0: serial@40000200 { + device_type = "serial"; + compatible = "ns16550a"; + reg = <0x40000200 0x00000008>; + virtual-reg = <0xe0000200>; + clock-frequency = <11059200>; + current-speed = <115200>; + interrupt-parent = <&UIC0>; + interrupts = <0x0 0x4>; + }; + }; + }; + + nvrtc { + compatible = "ds1743-nvram", "ds1743", "rtc-ds1743"; + reg = <0 0xEF703000 0x2000>; + }; + iss-block { + compatible = "ibm,iss-sim-block-device"; + reg = <0 0xEF701000 0x1000>; + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@40000200"; + }; +}; diff --git a/arch/powerpc/boot/treeboot-iss4xx.c b/arch/powerpc/boot/treeboot-iss4xx.c new file mode 100644 index 0000000..fcc4495 --- /dev/null +++ b/arch/powerpc/boot/treeboot-iss4xx.c @@ -0,0 +1,56 @@ +/* + * Copyright 2010 Ben. Herrenschmidt, IBM Corporation. + * + * Based on earlier code: + * Copyright (C) Paul Mackerras 1997. + * + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * + * Copyright 2007 David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include "types.h" +#include "elf.h" +#include "string.h" +#include "stdio.h" +#include "page.h" +#include "ops.h" +#include "reg.h" +#include "io.h" +#include "dcr.h" +#include "4xx.h" +#include "44x.h" +#include "libfdt.h" + +BSS_STACK(4096); + +static void iss_4xx_fixups(void) +{ + ibm4xx_sdram_fixup_memsize(); +} + +#define SPRN_PIR 0x11E /* Processor Indentification Register */ +void platform_init(void) +{ + unsigned long end_of_ram = 0x08000000; + unsigned long avail_ram = end_of_ram - (unsigned long)_end; + u32 pir_reg; + + simple_alloc_init(_end, avail_ram, 128, 64); + platform_ops.fixups = iss_4xx_fixups; + platform_ops.exit = ibm44x_dbcr_reset; + pir_reg = mfspr(SPRN_PIR); + fdt_set_boot_cpuid_phys(_dtb_start, pir_reg); + fdt_init(_dtb_start); + serial_console_init(); +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 7160b3b..cb97e75 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -241,6 +241,9 @@ gamecube|wii) link_address='0x600000' platformo="$object/$platform-head.o $object/$platform.o" ;; +treeboot-iss4xx-mpic) + platformo="$object/treeboot-iss4xx.o" + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index b2d1ac6..b68f025 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -854,6 +854,9 @@ #define PVR_8245 0x80811014 #define PVR_8260 PVR_8240 +/* 476 Simulator seems to currently have the PVR of the 602... */ +#define PVR_476_ISS 0x00052000 + /* 64-bit processors */ /* XXX the prefix should be PVR_, we'll do a global sweep to fix it one day */ #define PV_NORTHSTAR 0x0033 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index ad6baf8..9556be9 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1715,6 +1715,21 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_47x, .platform = "ppc470", }, + { /* 476 iss */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00050000, + .cpu_name = "476", + .cpu_features = CPU_FTRS_47X, + .cpu_user_features = COMMON_USER_BOOKE | + PPC_FEATURE_HAS_FPU, + .cpu_user_features = COMMON_USER_BOOKE, + .mmu_features = MMU_FTR_TYPE_47x | + MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, + .icache_bsize = 32, + .dcache_bsize = 128, + .machine_check = machine_check_47x, + .platform = "ppc470", + }, { /* default match */ .pvr_mask = 0x00000000, .pvr_value = 0x00000000, diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 1acd175..5ab484e 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -715,6 +715,8 @@ _GLOBAL(init_cpu_state) srwi r3,r3,16 cmplwi cr0,r3,PVR_476@h beq head_start_47x + cmplwi cr0,r3,PVR_476_ISS@h + beq head_start_47x #endif /* CONFIG_PPC_47x */ /* diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 9365e530..eeba0a7 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -160,6 +160,17 @@ config YOSEMITE help This option enables support for the AMCC PPC440EP evaluation board. +config ISS4xx + bool "ISS 4xx Simulator" + depends on (44x || 40x) + default n + select 405GP if 40x + select 440GP if 44x && !PPC_47x + select PPC_FPU + select OF_RTC + help + This option enables support for the IBM ISS simulation environment + #config LUAN # bool "Luan" # depends on 44x diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index ee6185a..82ff326 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_SAM440EP) += sam440ep.o obj-$(CONFIG_WARP) += warp.o obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o +obj-$(CONFIG_ISS4xx) += iss4xx.o diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c new file mode 100644 index 0000000..aa46e9d --- /dev/null +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -0,0 +1,167 @@ +/* + * PPC476 board specific routines + * + * Copyright 2010 Torez Smith, IBM Corporation. + * + * Based on earlier code: + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003-2005 Zultys Technologies + * + * Rewritten and ported to the merged powerpc tree: + * Copyright 2007 David Gibson , IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static __initdata struct of_device_id iss4xx_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,plb6", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init iss4xx_device_probe(void) +{ + of_platform_bus_probe(NULL, iss4xx_of_bus, NULL); + of_instantiate_rtc(); + + return 0; +} +machine_device_initcall(iss4xx, iss4xx_device_probe); + +/* We can have either UICs or MPICs */ +static void __init iss4xx_init_irq(void) +{ + struct device_node *np; + + /* Find top level interrupt controller */ + for_each_node_with_property(np, "interrupt-controller") { + if (of_get_property(np, "interrupts", NULL) == NULL) + break; + } + if (np == NULL) + panic("Can't find top level interrupt controller"); + + /* Check type and do appropriate initialization */ + if (of_device_is_compatible(np, "ibm,uic")) { + uic_init_tree(); + ppc_md.get_irq = uic_get_irq; +#ifdef CONFIG_MPIC + } else if (of_device_is_compatible(np, "chrp,open-pic")) { + /* The MPIC driver will get everything it needs from the + * device-tree, just pass 0 to all arguments + */ + struct mpic *mpic = mpic_alloc(np, 0, MPIC_PRIMARY, 0, 0, + " MPIC "); + BUG_ON(mpic == NULL); + mpic_init(mpic); + ppc_md.get_irq = mpic_get_irq; +#endif + } else + panic("Unrecognized top level interrupt controller"); +} + +#ifdef CONFIG_SMP +static void __cpuinit smp_iss4xx_setup_cpu(int cpu) +{ + mpic_setup_this_cpu(); +} + +static void __cpuinit smp_iss4xx_kick_cpu(int cpu) +{ + struct device_node *cpunode = of_get_cpu_node(cpu, NULL); + const u64 *spin_table_addr_prop; + u32 *spin_table; + extern void start_secondary_47x(void); + + BUG_ON(cpunode == NULL); + + /* Assume spin table. We could test for the enable-method in + * the device-tree but currently there's little point as it's + * our only supported method + */ + spin_table_addr_prop = of_get_property(cpunode, "cpu-release-addr", + NULL); + if (spin_table_addr_prop == NULL) { + pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", cpu); + return; + } + + /* Assume it's mapped as part of the linear mapping. This is a bit + * fishy but will work fine for now + */ + spin_table = (u32 *)__va(*spin_table_addr_prop); + pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table); + + spin_table[3] = cpu; + smp_wmb(); + spin_table[1] = __pa(start_secondary_47x); + mb(); +} + +static struct smp_ops_t iss_smp_ops = { + .probe = smp_mpic_probe, + .message_pass = smp_mpic_message_pass, + .setup_cpu = smp_iss4xx_setup_cpu, + .kick_cpu = smp_iss4xx_kick_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, +}; + +static void __init iss4xx_smp_init(void) +{ + if (mmu_has_feature(MMU_FTR_TYPE_47x)) + smp_ops = &iss_smp_ops; +} + +#else /* CONFIG_SMP */ +static void __init iss4xx_smp_init(void) { } +#endif /* CONFIG_SMP */ + +static void __init iss4xx_setup_arch(void) +{ + iss4xx_smp_init(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init iss4xx_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,iss-4xx")) + return 0; + + return 1; +} + +define_machine(iss4xx) { + .name = "ISS-4xx", + .probe = iss4xx_probe, + .progress = udbg_progress, + .init_IRQ = iss4xx_init_irq, + .setup_arch = iss4xx_setup_arch, + .restart = ppc4xx_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; -- cgit v0.10.2 From 101c192e1163c1c7e8d29748108b582929975038 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Fri, 5 Mar 2010 10:43:35 +0000 Subject: powerpc/47x: defconfig for 476 on the iss 4xx simulator A defconfig for the IBM ISS 476 simulator Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig new file mode 100644 index 0000000..8683cbc --- /dev/null +++ b/arch/powerpc/configs/44x/iss476-smp_defconfig @@ -0,0 +1,1026 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.33 +# Thu Mar 4 11:50:12 2010 +# +# CONFIG_PPC64 is not set + +# +# Processor support +# +# CONFIG_PPC_BOOK3S_32 is not set +# CONFIG_PPC_85xx is not set +# CONFIG_PPC_8xx is not set +# CONFIG_40x is not set +CONFIG_44x=y +# CONFIG_E200 is not set +CONFIG_PPC_FPU=y +CONFIG_4xx=y +CONFIG_BOOKE=y +CONFIG_PTE_64BIT=y +CONFIG_PHYS_64BIT=y +CONFIG_PPC_MMU_NOHASH=y +CONFIG_PPC_MMU_NOHASH_32=y +# CONFIG_PPC_MM_SLICES is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +# CONFIG_NOT_COHERENT_CACHE is not set +CONFIG_PPC32=y +CONFIG_WORD_SIZE=32 +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set +# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set +CONFIG_IRQ_PER_CPU=y +CONFIG_NR_IRQS=512 +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_ARCH_HAS_ILOG2_U32=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_ARCH_NO_VIRT_TO_BUS is not set +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_PPC_OF=y +CONFIG_OF=y +CONFIG_PPC_UDBG_16550=y +CONFIG_GENERIC_TBSYNC=y +CONFIG_AUDIT_ARCH=y +CONFIG_GENERIC_BUG=y +CONFIG_DTC=y +# CONFIG_DEFAULT_UIMAGE is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_PPC_DCR_NATIVE=y +# CONFIG_PPC_DCR_MMIO is not set +CONFIG_PPC_DCR=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +# CONFIG_RCU_TRACE is not set +CONFIG_RCU_FANOUT=32 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_GROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_USER_SCHED=y +# CONFIG_CGROUP_SCHED is not set +# CONFIG_CGROUPS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_HAVE_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +CONFIG_EVENT_PROFILE=y +# CONFIG_PERF_COUNTERS is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +# CONFIG_SLOW_WORK is not set +# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_FREEZER is not set + +# +# Platform support +# +# CONFIG_PPC_CELL is not set +# CONFIG_PPC_CELL_NATIVE is not set +# CONFIG_PQ2ADS is not set +CONFIG_PPC_47x=y +# CONFIG_BAMBOO is not set +# CONFIG_EBONY is not set +# CONFIG_SAM440EP is not set +# CONFIG_SEQUOIA is not set +# CONFIG_TAISHAN is not set +# CONFIG_KATMAI is not set +# CONFIG_RAINIER is not set +# CONFIG_WARP is not set +# CONFIG_ARCHES is not set +# CONFIG_CANYONLANDS is not set +# CONFIG_GLACIER is not set +# CONFIG_REDWOOD is not set +# CONFIG_EIGER is not set +# CONFIG_YOSEMITE is not set +CONFIG_ISS4xx=y +# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set +# CONFIG_PPC44x_SIMPLE is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_IPIC is not set +CONFIG_MPIC=y +# CONFIG_MPIC_WEIRD is not set +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +# CONFIG_PPC_970_NAP is not set +# CONFIG_PPC_INDIRECT_IO is not set +# CONFIG_GENERIC_IOMAP is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_FSL_ULI1575 is not set +CONFIG_OF_RTC=y +# CONFIG_SIMPLE_GPIO is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=100 +# CONFIG_SCHED_HRTICK is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_MATH_EMULATION=y +# CONFIG_IOMMU_HELPER is not set +# CONFIG_SWIOTLB is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_HAS_WALK_MEMORY=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_IRQ_ALL_CPUS=y +CONFIG_SPARSE_IRQ=y +CONFIG_MAX_ACTIVE_REGIONS=32 +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_STDBINUTILS=y +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_PROC_DEVICETREE=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="root=/dev/issblk0" +CONFIG_EXTRA_TARGETS="" +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_ZONE_DMA=y +CONFIG_4xx_SOC=y +CONFIG_PPC_PCI_CHOICE=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set +# CONFIG_HAS_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_PAGE_OFFSET=0xc0000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_PHYSICAL_START=0x00000000 +CONFIG_TASK_SIZE=0xc0000000 +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +# CONFIG_MTD_UBI is not set +CONFIG_OF_DEVICE=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=35000 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_XILINX_SYSACE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_DMA is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_NETDEVICES is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_HVC_UDBG is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_SOUND is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set + +# +# TI VLYNQ +# +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set +# CONFIG_DLM is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_SYSCTL_SYSCALL_CHECK=y +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_BOOT_TRACER is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_PPC_DISABLE_WERROR is not set +CONFIG_PPC_WERROR=y +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_XMON is not set +# CONFIG_IRQSTACKS is not set +# CONFIG_VIRQ_DEBUG is not set +# CONFIG_BDI_SWITCH is not set +CONFIG_PPC_EARLY_DEBUG=y +# CONFIG_PPC_EARLY_DEBUG_LPAR is not set +# CONFIG_PPC_EARLY_DEBUG_G5 is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set +# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set +# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set +# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set +# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set +# CONFIG_PPC_EARLY_DEBUG_BEAT is not set +CONFIG_PPC_EARLY_DEBUG_44x=y +# CONFIG_PPC_EARLY_DEBUG_40x is not set +# CONFIG_PPC_EARLY_DEBUG_CPM is not set +# CONFIG_PPC_EARLY_DEBUG_USBGECKO is not set +CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x40000200 +CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x1 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +CONFIG_CRYPTO_PCBC=y +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_PPC_CLOCK is not set +# CONFIG_VIRTUALIZATION is not set -- cgit v0.10.2 From a32fe93daf9c6b6ffbab1d9b9e2a8e4c335bda5c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 27 Apr 2010 22:13:34 +0000 Subject: powerpc/4xx: Add optional "reset_type" property to control reboot via dts By setting "reset_type" to one of the following values, the default software reset mechanism may be overidden. Here the possible values of "reset_type": 1 - PPC4xx core reset 2 - PPC4xx chip reset 3 - PPC4xx system reset (default) This will be used by a new PPC440SPe board port, which needs a "chip reset" instead of the default "system reset" to be asserted. Signed-off-by: Stefan Roese Cc: Josh Boyer Cc: Benjamin Herrenschmidt Acked-by: Josh Boyer Signed-off-by: Josh Boyer diff --git a/Documentation/powerpc/dts-bindings/4xx/reboot.txt b/Documentation/powerpc/dts-bindings/4xx/reboot.txt new file mode 100644 index 0000000..d721726 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/4xx/reboot.txt @@ -0,0 +1,18 @@ +Reboot property to control system reboot on PPC4xx systems: + +By setting "reset_type" to one of the following values, the default +software reset mechanism may be overidden. Here the possible values of +"reset_type": + + 1 - PPC4xx core reset + 2 - PPC4xx chip reset + 3 - PPC4xx system reset (default) + +Example: + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,440SPe"; + ... + reset-type = <2>; /* Use chip-reset */ + }; diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c index 5c01435..d3d6ce3 100644 --- a/arch/powerpc/sysdev/ppc4xx_soc.c +++ b/arch/powerpc/sysdev/ppc4xx_soc.c @@ -191,11 +191,31 @@ static int __init ppc4xx_l2c_probe(void) arch_initcall(ppc4xx_l2c_probe); /* - * At present, this routine just applies a system reset. + * Apply a system reset. Alternatively a board specific value may be + * provided via the "reset-type" property in the cpu node. */ void ppc4xx_reset_system(char *cmd) { - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_RST_SYSTEM); + struct device_node *np; + u32 reset_type = DBCR0_RST_SYSTEM; + const u32 *prop; + + np = of_find_node_by_type(NULL, "cpu"); + if (np) { + prop = of_get_property(np, "reset-type", NULL); + + /* + * Check if property exists and if it is in range: + * 1 - PPC4xx core reset + * 2 - PPC4xx chip reset + * 3 - PPC4xx system reset (default) + */ + if ((prop) && ((prop[0] >= 1) && (prop[0] <= 3))) + reset_type = prop[0] << 28; + } + + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type); + while (1) ; /* Just in case the reset doesn't work */ } -- cgit v0.10.2 From f8b67691828321f5c85bb853283aa101ae673130 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 28 Apr 2010 13:39:41 +0000 Subject: powerpc/pseries: Make query_cpu_stopped callable outside hotplug cpu This moves query_cpu_stopped() out of the hotplug cpu code and into smp.c so it can called in other places and renames it to smp_query_cpu_stopped(). It also cleans up the return values by adding some #defines Cc: Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index a8e1d5d..b0760d7 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -154,30 +154,6 @@ static void pseries_mach_cpu_die(void) for(;;); } -static int qcss_tok; /* query-cpu-stopped-state token */ - -/* Get state of physical CPU. - * Return codes: - * 0 - The processor is in the RTAS stopped state - * 1 - stop-self is in progress - * 2 - The processor is not in the RTAS stopped state - * -1 - Hardware Error - * -2 - Hardware Busy, Try again later. - */ -static int query_cpu_stopped(unsigned int pcpu) -{ - int cpu_status, status; - - status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); - if (status != 0) { - printk(KERN_ERR - "RTAS query-cpu-stopped-state failed: %i\n", status); - return status; - } - - return cpu_status; -} - static int pseries_cpu_disable(void) { int cpu = smp_processor_id(); @@ -224,8 +200,9 @@ static void pseries_cpu_die(unsigned int cpu) } else if (get_preferred_offline_state(cpu) == CPU_STATE_OFFLINE) { for (tries = 0; tries < 25; tries++) { - cpu_status = query_cpu_stopped(pcpu); - if (cpu_status == 0 || cpu_status == -1) + cpu_status = smp_query_cpu_stopped(pcpu); + if (cpu_status == QCSS_STOPPED || + cpu_status == QCSS_HARDWARE_ERROR) break; cpu_relax(); } @@ -388,6 +365,7 @@ static int __init pseries_cpu_hotplug_init(void) struct device_node *np; const char *typep; int cpu; + int qcss_tok; for_each_node_by_name(np, "interrupt-controller") { typep = of_get_property(np, "compatible", NULL); diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index a05f8d4..6c4fd2c 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -4,6 +4,14 @@ #include #include +/* Get state of physical CPU from query_cpu_stopped */ +int smp_query_cpu_stopped(unsigned int pcpu); +#define QCSS_STOPPED 0 +#define QCSS_STOPPING 1 +#define QCSS_NOT_STOPPED 2 +#define QCSS_HARDWARE_ERROR -1 +#define QCSS_HARDWARE_BUSY -2 + static inline long poll_pending(void) { return plpar_hcall_norets(H_POLL_PENDING); diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 4e7f89a..20b6942 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -57,6 +57,28 @@ */ static cpumask_t of_spin_map; +/* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */ +int smp_query_cpu_stopped(unsigned int pcpu) +{ + int cpu_status, status; + int qcss_tok = rtas_token("query-cpu-stopped-state"); + + if (qcss_tok == RTAS_UNKNOWN_SERVICE) { + printk(KERN_INFO "Firmware doesn't support " + "query-cpu-stopped-state\n"); + return QCSS_HARDWARE_ERROR; + } + + status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); + if (status != 0) { + printk(KERN_ERR + "RTAS query-cpu-stopped-state failed: %i\n", status); + return status; + } + + return cpu_status; +} + /** * smp_startup_cpu() - start the given cpu * -- cgit v0.10.2 From aef40e87d866355ffd279ab21021de733242d0d5 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 28 Apr 2010 13:39:41 +0000 Subject: powerpc/pseries: Only call start-cpu when a CPU is stopped Currently we always call start-cpu irrespective of if the CPU is stopped or not. Unfortunatley on POWER7, firmware seems to not like start-cpu being called when a cpu already been started. This was not the case on POWER6 and earlier. This patch checks to see if the CPU is stopped or not via an query-cpu-stopped-state call, and only calls start-cpu on CPUs which are stopped. This fixes a bug with kexec on POWER7 on PHYP where only the primary thread would make it to the second kernel. Reported-by: Ankita Garg Cc: Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 20b6942..8979982 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -104,6 +104,12 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) pcpu = get_hard_smp_processor_id(lcpu); + /* Check to see if the CPU out of FW already for kexec */ + if (smp_query_cpu_stopped(pcpu) == QCSS_NOT_STOPPED){ + cpu_set(lcpu, of_spin_map); + return 1; + } + /* Fixup atomic count: it exited inside IRQ handler. */ task_thread_info(paca[lcpu].__current)->preempt_count = 0; -- cgit v0.10.2 From 75c1d539ea13117cbe95e2c343e52af67d735145 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 27 Apr 2010 21:22:55 +0000 Subject: powerpc: Fix CONFIG_DEBUG_PAGEALLOC on 603/e300 So we tried to speed things up a bit using flush_hash_pages() directly but that falls over on 603 of course meaning we fail to flush the TLB properly and we may even end up having it corrupt memory randomly by accessing a hash table that doesn't exist. This removes the "optimization" by always going through flush_tlb_page() for now at least. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 767b0cf..9fc02dc 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -393,11 +393,7 @@ static int __change_page_attr(struct page *page, pgprot_t prot) return -EINVAL; __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0); wmb(); -#ifdef CONFIG_PPC_STD_MMU - flush_hash_pages(0, address, pmd_val(*kpmd), 1); -#else flush_tlb_page(NULL, address); -#endif pte_unmap(kpte); return 0; -- cgit v0.10.2 From 7cad19784950f947bf8b332b92d83c75788f897a Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Mon, 26 Apr 2010 22:50:21 +0000 Subject: powerpc: Correct parport interrupt parsing Currently the parsing of the device tree in arch/powerpc/include/asm/parport.h assumes that the interrupt provided in the parallel port node is a valid virtual irq. The values for the interrupts provided in the device tree should have meaning in the context of the driver for the specific interrupt controller to which the interrupt is connected and irq_of_parse_and_map() should be used to determine the correct virtual irq. Signed-off-by: Martyn Welch Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/parport.h b/arch/powerpc/include/asm/parport.h index 94942d6..1ca1102 100644 --- a/arch/powerpc/include/asm/parport.h +++ b/arch/powerpc/include/asm/parport.h @@ -19,6 +19,8 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) u32 io1, io2; int propsize; int count = 0; + int virq; + for (np = NULL; (np = of_find_compatible_node(np, "parallel", "pnpPNP,400")) != NULL;) { @@ -26,10 +28,13 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) if (!prop || propsize > 6*sizeof(u32)) continue; io1 = prop[1]; io2 = prop[2]; - prop = of_get_property(np, "interrupts", NULL); - if (!prop) + + virq = irq_of_parse_and_map(np, 0); + if (virq == NO_IRQ) continue; - if (parport_pc_probe_port(io1, io2, prop[0], autodma, NULL, 0) != NULL) + + if (parport_pc_probe_port(io1, io2, virq, autodma, NULL, 0) + != NULL) count++; } return count; -- cgit v0.10.2 From 8f85c0af2388d575a598d2695319ccb7e1b5523c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 1 Apr 2010 14:16:59 +0000 Subject: i2c/mpc: Drop NO_IRQ Drop NO_IRQ as 0 is the preferred way to describe 'no irq' (http://lkml.org/lkml/2005/11/21/221). This change is safe, as the driver is only used on powerpc, where NO_IRQ is 0 anyhow. Signed-off-by: Wolfram Sang Acked-by: Grant Likely Cc: Ben Dooks Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f1321f7..e86cef3 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -118,7 +118,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) u32 x; int result = 0; - if (i2c->irq == NO_IRQ) { + if (!i2c->irq) { while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { schedule(); if (time_after(jiffies, orig_jiffies + timeout)) { @@ -568,7 +568,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op, } i2c->irq = irq_of_parse_and_map(op->node, 0); - if (i2c->irq != NO_IRQ) { /* i2c->irq = NO_IRQ implies polling */ + if (i2c->irq) { /* no i2c->irq implies polling */ result = request_irq(i2c->irq, mpc_i2c_isr, IRQF_SHARED, "i2c-mpc", i2c); if (result < 0) { @@ -627,7 +627,7 @@ static int __devexit fsl_i2c_remove(struct of_device *op) i2c_del_adapter(&i2c->adap); dev_set_drvdata(&op->dev, NULL); - if (i2c->irq != NO_IRQ) + if (i2c->irq) free_irq(i2c->irq, i2c); irq_dispose_mapping(i2c->irq); -- cgit v0.10.2 From 6889f959b35d79166f9fb65aaddca1badb809d8f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 1 Apr 2010 14:17:00 +0000 Subject: i2c/cpm: Drop NO_IRQ Drop NO_IRQ as 0 is the preferred way to describe 'no irq' (http://lkml.org/lkml/2005/11/21/221). This change is safe, as the driver is only used on powerpc, where NO_IRQ is 0 anyhow. Signed-off-by: Wolfram Sang Acked-by: Grant Likely Cc: Jochen Friedrich Cc: Ben Dooks Acked-by: Jochen Friedrich Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 9c2e100..16948db 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -441,7 +441,7 @@ static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm) init_waitqueue_head(&cpm->i2c_wait); cpm->irq = of_irq_to_resource(ofdev->node, 0, NULL); - if (cpm->irq == NO_IRQ) + if (!cpm->irq) return -EINVAL; /* Install interrupt handler. */ -- cgit v0.10.2 From 13bb5339966d49942878a46b0a7fda0639d7db5f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 1 Apr 2010 14:17:01 +0000 Subject: i2c/ibm-iic: Drop NO_IRQ Drop NO_IRQ as 0 is the preferred way to describe 'no irq' (http://lkml.org/lkml/2005/11/21/221). This change is safe, as the driver is only used on powerpc, where NO_IRQ is 0 anyhow. Signed-off-by: Wolfram Sang Acked-by: Grant Likely Cc: Sean MacLennan Cc: Ben Dooks Acked-by: Sean MacLennan Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index b1bc6e2..2bef534 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -668,12 +668,12 @@ static int __devinit iic_request_irq(struct of_device *ofdev, int irq; if (iic_force_poll) - return NO_IRQ; + return 0; irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n"); - return NO_IRQ; + return 0; } /* Disable interrupts until we finish initialization, assumes @@ -683,7 +683,7 @@ static int __devinit iic_request_irq(struct of_device *ofdev, if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) { dev_err(&ofdev->dev, "request_irq %d failed\n", irq); /* Fallback to the polling mode */ - return NO_IRQ; + return 0; } return irq; @@ -719,7 +719,7 @@ static int __devinit iic_probe(struct of_device *ofdev, init_waitqueue_head(&dev->wq); dev->irq = iic_request_irq(ofdev, dev); - if (dev->irq == NO_IRQ) + if (!dev->irq) dev_warn(&ofdev->dev, "using polling mode\n"); /* Board specific settings */ @@ -766,7 +766,7 @@ static int __devinit iic_probe(struct of_device *ofdev, return 0; error_cleanup: - if (dev->irq != NO_IRQ) { + if (dev->irq) { iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } @@ -790,7 +790,7 @@ static int __devexit iic_remove(struct of_device *ofdev) i2c_del_adapter(&dev->adap); - if (dev->irq != NO_IRQ) { + if (dev->irq) { iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } -- cgit v0.10.2 From 91eea67c6d8704396a98226508c56a8501e141e3 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 21 Apr 2010 16:21:03 +0000 Subject: powerpc/mm: Track backing pages allocated by vmemmap_populate() We need to keep track of the backing pages that get allocated by vmemmap_populate() so that when we use kdump, the dump-capture kernel knows where these pages are. We use a simple linked list of structures that contain the physical address of the backing page and corresponding virtual address to track the backing pages. To save space, we just use a pointer to the next struct vmemmap_backing. We can also do this because we never remove nodes. We call the pointer "list" to be compatible with changes made to the crash utility. vmemmap_populate() is called either at boot-time or on a memory hotplug operation. We don't have to worry about the boot-time calls because they will be inherently single-threaded, and for a memory hotplug operation vmemmap_populate() is called through: sparse_add_one_section() | V kmalloc_section_memmap() | V sparse_mem_map_populate() | V vmemmap_populate() and in sparse_add_one_section() we're protected by pgdat_resize_lock(). So, we don't need a spinlock to protect the vmemmap_list. We allocate space for the vmemmap_backing structs by allocating whole pages in vmemmap_list_alloc() and then handing out chunks of this to vmemmap_list_populate(). This means that we waste at most just under one page, but this keeps the code is simple. Signed-off-by: Mark Nelson Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h index 605f5c5..292725c 100644 --- a/arch/powerpc/include/asm/pgalloc-64.h +++ b/arch/powerpc/include/asm/pgalloc-64.h @@ -11,6 +11,12 @@ #include #include +struct vmemmap_backing { + struct vmemmap_backing *list; + unsigned long phys; + unsigned long virt_addr; +}; + /* * Functions that deal with pagetables that could be at any level of * the table need to be passed an "index_size" so they know how to diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index d7fa50b..e267f22 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -252,6 +252,47 @@ static void __meminit vmemmap_create_mapping(unsigned long start, } #endif /* CONFIG_PPC_BOOK3E */ +struct vmemmap_backing *vmemmap_list; + +static __meminit struct vmemmap_backing * vmemmap_list_alloc(int node) +{ + static struct vmemmap_backing *next; + static int num_left; + + /* allocate a page when required and hand out chunks */ + if (!next || !num_left) { + next = vmemmap_alloc_block(PAGE_SIZE, node); + if (unlikely(!next)) { + WARN_ON(1); + return NULL; + } + num_left = PAGE_SIZE / sizeof(struct vmemmap_backing); + } + + num_left--; + + return next++; +} + +static __meminit void vmemmap_list_populate(unsigned long phys, + unsigned long start, + int node) +{ + struct vmemmap_backing *vmem_back; + + vmem_back = vmemmap_list_alloc(node); + if (unlikely(!vmem_back)) { + WARN_ON(1); + return; + } + + vmem_back->phys = phys; + vmem_back->virt_addr = start; + vmem_back->list = vmemmap_list; + + vmemmap_list = vmem_back; +} + int __meminit vmemmap_populate(struct page *start_page, unsigned long nr_pages, int node) { @@ -276,6 +317,8 @@ int __meminit vmemmap_populate(struct page *start_page, if (!p) return -ENOMEM; + vmemmap_list_populate(__pa(p), start, node); + pr_debug(" * %016lx..%016lx allocated at %p\n", start, start + page_size, p); -- cgit v0.10.2 From e460c2c91af44374cbfa3f1c70f5ca9bbf099aa9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 6 May 2010 17:15:58 +1000 Subject: powerpc: Invoke oom-killer from page fault As explained in commit 1c0fe6e3bd, we want to call the architecture independent oom killer when getting an unexplained OOM from handle_mm_fault, rather than simply killing current. Cc: linuxppc-dev@ozlabs.org Cc: Benjamin Herrenschmidt Cc: linux-arch@vger.kernel.org Signed-off-by: Nick Piggin Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 83ac493..1bd712c 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -308,7 +308,6 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - survive: ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); if (unlikely(ret & VM_FAULT_ERROR)) { if (ret & VM_FAULT_OOM) @@ -360,15 +359,10 @@ bad_area_nosemaphore: */ out_of_memory: up_read(&mm->mmap_sem); - if (is_global_init(current)) { - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - printk("VM: killing process %s\n", current->comm); - if (user_mode(regs)) - do_group_exit(SIGKILL); - return SIGKILL; + if (!user_mode(regs)) + return SIGKILL; + pagefault_out_of_memory(); + return 0; do_sigbus: up_read(&mm->mmap_sem); -- cgit v0.10.2 From 1b095cf4029f43db363981c0e5f02216e495ac9f Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:32 +0000 Subject: powerpc/cpumask: Use cpu_online_mask Change &cpu_online_map to cpu_online_mask. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index d35e052..c16537b 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -213,7 +213,7 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("current astate is at %d\n",cur_astate); policy->cur = pas_freqs[cur_astate].frequency; - cpumask_copy(policy->cpus, &cpu_online_map); + cpumask_copy(policy->cpus, cpu_online_mask); ppc_proc_freq = policy->cur * 1000ul; diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 3ca09d3..9650c60 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -362,7 +362,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) /* secondary CPUs are tied to the primary one by the * cpufreq core if in the secondary policy we tell it that * it actually must be one policy together with all others. */ - cpumask_copy(policy->cpus, &cpu_online_map); + cpumask_copy(policy->cpus, cpu_online_mask); cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, -- cgit v0.10.2 From d5f86fe3457f48f27eecd40c605e7876d026af7c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:33 +0000 Subject: powerpc/cpumask: Convert rtasd to new cpumask API Use cpumask_first, cpumask_next in rtasd code. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index 4190eae..e907ca6 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -411,9 +411,9 @@ static void rtas_event_scan(struct work_struct *w) get_online_cpus(); - cpu = next_cpu(smp_processor_id(), cpu_online_map); - if (cpu == NR_CPUS) { - cpu = first_cpu(cpu_online_map); + cpu = cpumask_next(smp_processor_id(), cpu_online_mask); + if (cpu >= nr_cpu_ids) { + cpu = cpumask_first(cpu_online_mask); if (first_pass) { first_pass = 0; @@ -466,8 +466,8 @@ static void start_event_scan(void) /* Retreive errors from nvram if any */ retreive_nvram_error_log(); - schedule_delayed_work_on(first_cpu(cpu_online_map), &event_scan_work, - event_scan_delay); + schedule_delayed_work_on(cpumask_first(cpu_online_mask), + &event_scan_work, event_scan_delay); } static int __init rtas_init(void) -- cgit v0.10.2 From bfb9126defa80cbed6d91ed9685b238b0d7e81c4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:34 +0000 Subject: powerpc/cpumask: Convert smp_cpus_done to new cpumask API Use the new cpumask_* functions and dynamically allocate the cpumask in smp_cpus_done. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 3fe4de2..17523a0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -562,19 +562,22 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_cpus_done(unsigned int max_cpus) { - cpumask_t old_mask; + cpumask_var_t old_mask; /* We want the setup_cpu() here to be called from CPU 0, but our * init thread may have been "borrowed" by another CPU in the meantime * se we pin us down to CPU 0 for a short while */ - old_mask = current->cpus_allowed; + alloc_cpumask_var(&old_mask, GFP_NOWAIT); + cpumask_copy(old_mask, ¤t->cpus_allowed); set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid)); if (smp_ops && smp_ops->setup_cpu) smp_ops->setup_cpu(boot_cpuid); - set_cpus_allowed_ptr(current, &old_mask); + set_cpus_allowed_ptr(current, old_mask); + + free_cpumask_var(old_mask); snapshot_timebases(); -- cgit v0.10.2 From b6decb707952c678d110699abb5ed86d45ca6927 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:35 +0000 Subject: powerpc/cpumask: Convert fixup_irqs to new cpumask API Use new cpumask_* functions, and dynamically allocate cpumask in fixup_irqs. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 1d3b270..4d33229 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -40,7 +40,7 @@ extern void smp_message_recv(int); DECLARE_PER_CPU(unsigned int, cpu_pvr); #ifdef CONFIG_HOTPLUG_CPU -extern void fixup_irqs(cpumask_t map); +extern void fixup_irqs(const struct cpumask *map); int generic_cpu_disable(void); int generic_cpu_enable(unsigned int cpu); void generic_cpu_die(unsigned int cpu); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 64f6f20..250ee2e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -290,30 +290,33 @@ u64 arch_irq_stat_cpu(unsigned int cpu) } #ifdef CONFIG_HOTPLUG_CPU -void fixup_irqs(cpumask_t map) +void fixup_irqs(const struct cpumask *map) { struct irq_desc *desc; unsigned int irq; static int warned; + cpumask_var_t mask; - for_each_irq(irq) { - cpumask_t mask; + alloc_cpumask_var(&mask, GFP_KERNEL); + for_each_irq(irq) { desc = irq_to_desc(irq); if (desc && desc->status & IRQ_PER_CPU) continue; - cpumask_and(&mask, desc->affinity, &map); - if (any_online_cpu(mask) == NR_CPUS) { + cpumask_and(mask, desc->affinity, map); + if (cpumask_any(mask) >= nr_cpu_ids) { printk("Breaking affinity for irq %i\n", irq); - mask = map; + cpumask_copy(mask, map); } if (desc->chip->set_affinity) - desc->chip->set_affinity(irq, &mask); + desc->chip->set_affinity(irq, mask); else if (desc->action && !(warned++)) printk("Cannot set affinity for irq %i\n", irq); } + free_cpumask_var(mask); + local_irq_enable(); mdelay(1); local_irq_disable(); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 17523a0..62e82c2 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -313,7 +313,7 @@ int generic_cpu_disable(void) set_cpu_online(cpu, false); #ifdef CONFIG_PPC64 vdso_data->processorCount--; - fixup_irqs(cpu_online_map); + fixup_irqs(cpu_online_mask); #endif return 0; } @@ -333,7 +333,7 @@ int generic_cpu_enable(unsigned int cpu) cpu_relax(); #ifdef CONFIG_PPC64 - fixup_irqs(cpu_online_map); + fixup_irqs(cpu_online_mask); /* counter the irq disable in fixup_irqs */ local_irq_enable(); #endif -- cgit v0.10.2 From 115731312fb3207705023e3ff247d1b9d039838d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:36 +0000 Subject: powerpc/cpumask: Convert iseries SMP code to new cpumask API Use new cpumask functions in iseries SMP startup code. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 722335e..6590850 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -83,7 +83,7 @@ static void smp_iSeries_message_pass(int target, int msg) static int smp_iSeries_probe(void) { - return cpus_weight(cpu_possible_map); + return cpumask_weight(cpu_possible_mask); } static void smp_iSeries_kick_cpu(int nr) -- cgit v0.10.2 From af831e1e44619a7429eba8ece4eba8f977ee7c4f Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:37 +0000 Subject: powerpc/cpumask: Convert pseries SMP code to new cpumask API Use new cpumask functions in pseries SMP startup code. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 8979982..3b1bf61 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -55,7 +55,7 @@ * The Primary thread of each non-boot processor was started from the OF client * interface by prom_hold_cpus and is spinning on secondary_hold_spinloop. */ -static cpumask_t of_spin_map; +static cpumask_var_t of_spin_mask; /* Query where a cpu is now. Return codes #defined in plpar_wrappers.h */ int smp_query_cpu_stopped(unsigned int pcpu) @@ -98,7 +98,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned int pcpu; int start_cpu; - if (cpu_isset(lcpu, of_spin_map)) + if (cpumask_test_cpu(lcpu, of_spin_mask)) /* Already started by OF and sitting in spin loop */ return 1; @@ -106,7 +106,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) /* Check to see if the CPU out of FW already for kexec */ if (smp_query_cpu_stopped(pcpu) == QCSS_NOT_STOPPED){ - cpu_set(lcpu, of_spin_map); + cpumask_set_cpu(lcpu, of_spin_mask); return 1; } @@ -143,7 +143,7 @@ static void __devinit smp_xics_setup_cpu(int cpu) if (firmware_has_feature(FW_FEATURE_SPLPAR)) vpa_init(cpu); - cpu_clear(cpu, of_spin_map); + cpumask_clear_cpu(cpu, of_spin_mask); set_cpu_current_state(cpu, CPU_STATE_ONLINE); set_default_offline_state(cpu); @@ -214,17 +214,19 @@ static void __init smp_init_pseries(void) pr_debug(" -> smp_init_pSeries()\n"); + alloc_bootmem_cpumask_var(&of_spin_mask); + /* Mark threads which are still spinning in hold loops. */ if (cpu_has_feature(CPU_FTR_SMT)) { for_each_present_cpu(i) { if (cpu_thread_in_core(i) == 0) - cpu_set(i, of_spin_map); + cpumask_set_cpu(i, of_spin_mask); } } else { - of_spin_map = cpu_present_map; + cpumask_copy(of_spin_mask, cpu_present_mask); } - cpu_clear(boot_cpuid, of_spin_map); + cpumask_clear_cpu(boot_cpuid, of_spin_mask); /* Non-lpar has additional take/give timebase */ if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { -- cgit v0.10.2 From 64fe220c13440a12d0bd8e32ebdf679e869e3ce3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:38 +0000 Subject: powerpc/cpumask: Convert xics driver to new cpumask API Use the new cpumask API and add some comments to clarify how get_irq_server works. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 1bcedd8..f19d194 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -163,29 +163,37 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) /* Interface to generic irq subsystem */ #ifdef CONFIG_SMP -static int get_irq_server(unsigned int virq, cpumask_t cpumask, +/* + * For the moment we only implement delivery to all cpus or one cpu. + * + * If the requested affinity is cpu_all_mask, we set global affinity. + * If not we set it to the first cpu in the mask, even if multiple cpus + * are set. This is so things like irqbalance (which set core and package + * wide affinities) do the right thing. + */ +static int get_irq_server(unsigned int virq, const struct cpumask *cpumask, unsigned int strict_check) { - int server; - /* For the moment only implement delivery to all cpus or one cpu */ - cpumask_t tmp = CPU_MASK_NONE; if (!distribute_irqs) return default_server; - if (!cpus_equal(cpumask, CPU_MASK_ALL)) { - cpus_and(tmp, cpu_online_map, cpumask); - - server = first_cpu(tmp); + if (!cpumask_equal(cpumask, cpu_all_mask)) { + int server = cpumask_first_and(cpu_online_mask, cpumask); - if (server < NR_CPUS) + if (server < nr_cpu_ids) return get_hard_smp_processor_id(server); if (strict_check) return -1; } - if (cpus_equal(cpu_online_map, cpu_present_map)) + /* + * Workaround issue with some versions of JS20 firmware that + * deliver interrupts to cpus which haven't been started. This + * happens when using the maxcpus= boot option. + */ + if (cpumask_equal(cpu_online_mask, cpu_present_mask)) return default_distrib_server; return default_server; @@ -207,7 +215,7 @@ static void xics_unmask_irq(unsigned int virq) if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) return; - server = get_irq_server(virq, *(irq_to_desc(virq)->affinity), 0); + server = get_irq_server(virq, irq_to_desc(virq)->affinity, 0); call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); @@ -398,11 +406,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) return -1; } - /* - * For the moment only implement delivery to all cpus or one cpu. - * Get current irq_server for the given irq - */ - irq_server = get_irq_server(virq, *cpumask, 1); + irq_server = get_irq_server(virq, cpumask, 1); if (irq_server == -1) { char cpulist[128]; cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); @@ -611,7 +615,7 @@ int __init smp_xics_probe(void) { xics_request_ipi(); - return cpus_weight(cpu_possible_map); + return cpumask_weight(cpu_possible_mask); } #endif /* CONFIG_SMP */ -- cgit v0.10.2 From 2c2df038450cbf628426183c9efffc17cfea3406 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:39 +0000 Subject: powerpc/cpumask: Refactor /proc/cpuinfo code This separates the per cpu output from the summary output at the end of the file, making it easier to convert to the new cpumask API in a subsequent patch. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 48f0a00..58699a4 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -161,6 +161,38 @@ extern u32 cpu_temp_both(unsigned long cpu); DEFINE_PER_CPU(unsigned int, cpu_pvr); #endif +static void show_cpuinfo_summary(struct seq_file *m) +{ + struct device_node *root; + const char *model = NULL; +#if defined(CONFIG_SMP) && defined(CONFIG_PPC32) + unsigned long bogosum = 0; + int i; + for_each_online_cpu(i) + bogosum += loops_per_jiffy; + seq_printf(m, "total bogomips\t: %lu.%02lu\n", + bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); +#endif /* CONFIG_SMP && CONFIG_PPC32 */ + seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); + if (ppc_md.name) + seq_printf(m, "platform\t: %s\n", ppc_md.name); + root = of_find_node_by_path("/"); + if (root) + model = of_get_property(root, "model", NULL); + if (model) + seq_printf(m, "model\t\t: %s\n", model); + of_node_put(root); + + if (ppc_md.show_cpuinfo != NULL) + ppc_md.show_cpuinfo(m); + +#ifdef CONFIG_PPC32 + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", + (unsigned int)(total_memory / (1024 * 1024))); +#endif +} + static int show_cpuinfo(struct seq_file *m, void *v) { unsigned long cpu_id = (unsigned long)v - 1; @@ -169,35 +201,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) unsigned short min; if (cpu_id == NR_CPUS) { - struct device_node *root; - const char *model = NULL; -#if defined(CONFIG_SMP) && defined(CONFIG_PPC32) - unsigned long bogosum = 0; - int i; - for_each_online_cpu(i) - bogosum += loops_per_jiffy; - seq_printf(m, "total bogomips\t: %lu.%02lu\n", - bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); -#endif /* CONFIG_SMP && CONFIG_PPC32 */ - seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - if (ppc_md.name) - seq_printf(m, "platform\t: %s\n", ppc_md.name); - root = of_find_node_by_path("/"); - if (root) - model = of_get_property(root, "model", NULL); - if (model) - seq_printf(m, "model\t\t: %s\n", model); - of_node_put(root); - - if (ppc_md.show_cpuinfo != NULL) - ppc_md.show_cpuinfo(m); - -#ifdef CONFIG_PPC32 - /* Display the amount of memory */ - seq_printf(m, "Memory\t\t: %d MB\n", - (unsigned int)(total_memory / (1024 * 1024))); -#endif - + show_cpuinfo_summary(m); return 0; } -- cgit v0.10.2 From e6532c63cc3dbefc79936fc9c9c68a151004fe46 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:40 +0000 Subject: powerpc/cpumask: Convert /proc/cpuinfo to new cpumask API Use new cpumask API in /proc/cpuinfo code. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 58699a4..8dcec47 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -200,11 +200,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) unsigned short maj; unsigned short min; - if (cpu_id == NR_CPUS) { - show_cpuinfo_summary(m); - return 0; - } - /* We only show online cpus: disable preempt (overzealous, I * knew) to prevent cpu going down. */ preempt_disable(); @@ -312,19 +307,28 @@ static int show_cpuinfo(struct seq_file *m, void *v) #endif preempt_enable(); + + /* If this is the last cpu, print the summary */ + if (cpumask_next(cpu_id, cpu_online_mask) >= nr_cpu_ids) + show_cpuinfo_summary(m); + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) { - unsigned long i = *pos; - - return i <= NR_CPUS ? (void *)(i + 1) : NULL; + if (*pos == 0) /* just in case, cpu 0 is not the first */ + *pos = cpumask_first(cpu_online_mask); + else + *pos = cpumask_next(*pos - 1, cpu_online_mask); + if ((*pos) < nr_cpu_ids) + return (void *)(unsigned long)(*pos + 1); + return NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - ++*pos; + (*pos)++; return c_start(m, pos); } -- cgit v0.10.2 From cc1ba8ea6dde3f049b2b365d8fdc13976aee25cb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:41 +0000 Subject: powerpc/cpumask: Dynamically allocate cpu_sibling_map and cpu_core_map cpumasks Dynamically allocate cpu_sibling_map and cpu_core_map cpumasks. We don't need to set_cpu_online() the boot cpu in smp_prepare_boot_cpu, init/main.c does it for us. We also postpone setting of the boot cpu in cpu_sibling_map and cpu_core_map until when the memory allocator is available (smp_prepare_cpus), similar to x86. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 4d33229..66e237b 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -68,8 +68,19 @@ static inline void set_hard_smp_processor_id(int cpu, int phys) } #endif -DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); -DECLARE_PER_CPU(cpumask_t, cpu_core_map); +DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map); +DECLARE_PER_CPU(cpumask_var_t, cpu_core_map); + +static inline struct cpumask *cpu_sibling_mask(int cpu) +{ + return per_cpu(cpu_sibling_map, cpu); +} + +static inline struct cpumask *cpu_core_mask(int cpu) +{ + return per_cpu(cpu_core_map, cpu); +} + extern int cpu_to_core_id(int cpu); /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. @@ -93,7 +104,6 @@ void smp_init_pSeries(void); void smp_init_cell(void); void smp_init_celleb(void); void smp_setup_cpu_maps(void); -void smp_setup_cpu_sibling_map(void); extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index a7d7694..789599b 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -112,8 +112,8 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev, #ifdef CONFIG_PPC64 #include -#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu)) -#define topology_core_cpumask(cpu) (&per_cpu(cpu_core_map, cpu)) +#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu)) +#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu)) #define topology_core_id(cpu) (cpu_to_core_id(cpu)) #endif #endif diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 62e82c2..39babb1 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -59,8 +59,8 @@ struct thread_info *secondary_ti; -DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; -DEFINE_PER_CPU(cpumask_t, cpu_core_map) = CPU_MASK_NONE; +DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); +DEFINE_PER_CPU(cpumask_var_t, cpu_core_map); EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); EXPORT_PER_CPU_SYMBOL(cpu_core_map); @@ -271,6 +271,16 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp_store_cpu_info(boot_cpuid); cpu_callin_map[boot_cpuid] = 1; + for_each_possible_cpu(cpu) { + zalloc_cpumask_var_node(&per_cpu(cpu_sibling_map, cpu), + GFP_KERNEL, cpu_to_node(cpu)); + zalloc_cpumask_var_node(&per_cpu(cpu_core_map, cpu), + GFP_KERNEL, cpu_to_node(cpu)); + } + + cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid)); + cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid)); + if (smp_ops) if (smp_ops->probe) max_cpus = smp_ops->probe(); @@ -289,10 +299,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) void __devinit smp_prepare_boot_cpu(void) { BUG_ON(smp_processor_id() != boot_cpuid); - - set_cpu_online(boot_cpuid, true); - cpu_set(boot_cpuid, per_cpu(cpu_sibling_map, boot_cpuid)); - cpu_set(boot_cpuid, per_cpu(cpu_core_map, boot_cpuid)); #ifdef CONFIG_PPC64 paca[boot_cpuid].__current = current; #endif @@ -525,15 +531,15 @@ int __devinit start_secondary(void *unused) for (i = 0; i < threads_per_core; i++) { if (cpu_is_offline(base + i)) continue; - cpu_set(cpu, per_cpu(cpu_sibling_map, base + i)); - cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); + cpumask_set_cpu(cpu, cpu_sibling_mask(base + i)); + cpumask_set_cpu(base + i, cpu_sibling_mask(cpu)); /* cpu_core_map should be a superset of * cpu_sibling_map even if we don't have cache * information, so update the former here, too. */ - cpu_set(cpu, per_cpu(cpu_core_map, base +i)); - cpu_set(base + i, per_cpu(cpu_core_map, cpu)); + cpumask_set_cpu(cpu, cpu_core_mask(base + i)); + cpumask_set_cpu(base + i, cpu_core_mask(cpu)); } l2_cache = cpu_to_l2cache(cpu); for_each_online_cpu(i) { @@ -541,8 +547,8 @@ int __devinit start_secondary(void *unused) if (!np) continue; if (np == l2_cache) { - cpu_set(cpu, per_cpu(cpu_core_map, i)); - cpu_set(i, per_cpu(cpu_core_map, cpu)); + cpumask_set_cpu(cpu, cpu_core_mask(i)); + cpumask_set_cpu(i, cpu_core_mask(cpu)); } of_node_put(np); } @@ -602,10 +608,10 @@ int __cpu_disable(void) /* Update sibling maps */ base = cpu_first_thread_in_core(cpu); for (i = 0; i < threads_per_core; i++) { - cpu_clear(cpu, per_cpu(cpu_sibling_map, base + i)); - cpu_clear(base + i, per_cpu(cpu_sibling_map, cpu)); - cpu_clear(cpu, per_cpu(cpu_core_map, base +i)); - cpu_clear(base + i, per_cpu(cpu_core_map, cpu)); + cpumask_clear_cpu(cpu, cpu_sibling_mask(base + i)); + cpumask_clear_cpu(base + i, cpu_sibling_mask(cpu)); + cpumask_clear_cpu(cpu, cpu_core_mask(base + i)); + cpumask_clear_cpu(base + i, cpu_core_mask(cpu)); } l2_cache = cpu_to_l2cache(cpu); @@ -614,8 +620,8 @@ int __cpu_disable(void) if (!np) continue; if (np == l2_cache) { - cpu_clear(cpu, per_cpu(cpu_core_map, i)); - cpu_clear(i, per_cpu(cpu_core_map, cpu)); + cpumask_clear_cpu(cpu, cpu_core_mask(i)); + cpumask_clear_cpu(i, cpu_core_mask(cpu)); } of_node_put(np); } diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index e6506cd..bfa2c0c 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -118,7 +118,7 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = cbe_freqs[cur_pmode].frequency; #ifdef CONFIG_SMP - cpumask_copy(policy->cpus, &per_cpu(cpu_sibling_map, policy->cpu)); + cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); #endif cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); -- cgit v0.10.2 From 8729faaa5e87557876c02f1665d517e2b41299f1 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:42 +0000 Subject: powerpc/cpumask: Convert hotplug-cpu code to new cpumask API Convert hotplug-cpu code to new cpumask API. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index b0760d7..235f363 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -163,7 +163,7 @@ static int pseries_cpu_disable(void) /*fix boot_cpuid here*/ if (cpu == boot_cpuid) - boot_cpuid = any_online_cpu(cpu_online_map); + boot_cpuid = cpumask_any(cpu_online_mask); /* FIXME: abstract this to not be platform specific later on */ xics_migrate_irqs_away(); @@ -231,7 +231,7 @@ static void pseries_cpu_die(unsigned int cpu) static int pseries_add_processor(struct device_node *np) { unsigned int cpu; - cpumask_t candidate_map, tmp = CPU_MASK_NONE; + cpumask_var_t candidate_mask, tmp; int err = -ENOSPC, len, nthreads, i; const u32 *intserv; @@ -239,48 +239,53 @@ static int pseries_add_processor(struct device_node *np) if (!intserv) return 0; + zalloc_cpumask_var(&candidate_mask, GFP_KERNEL); + zalloc_cpumask_var(&tmp, GFP_KERNEL); + nthreads = len / sizeof(u32); for (i = 0; i < nthreads; i++) - cpu_set(i, tmp); + cpumask_set_cpu(i, tmp); cpu_maps_update_begin(); - BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map)); + BUG_ON(!cpumask_subset(cpu_present_mask, cpu_possible_mask)); /* Get a bitmap of unoccupied slots. */ - cpus_xor(candidate_map, cpu_possible_map, cpu_present_map); - if (cpus_empty(candidate_map)) { + cpumask_xor(candidate_mask, cpu_possible_mask, cpu_present_mask); + if (cpumask_empty(candidate_mask)) { /* If we get here, it most likely means that NR_CPUS is * less than the partition's max processors setting. */ printk(KERN_ERR "Cannot add cpu %s; this system configuration" " supports %d logical cpus.\n", np->full_name, - cpus_weight(cpu_possible_map)); + cpumask_weight(cpu_possible_mask)); goto out_unlock; } - while (!cpus_empty(tmp)) - if (cpus_subset(tmp, candidate_map)) + while (!cpumask_empty(tmp)) + if (cpumask_subset(tmp, candidate_mask)) /* Found a range where we can insert the new cpu(s) */ break; else - cpus_shift_left(tmp, tmp, nthreads); + cpumask_shift_left(tmp, tmp, nthreads); - if (cpus_empty(tmp)) { + if (cpumask_empty(tmp)) { printk(KERN_ERR "Unable to find space in cpu_present_map for" " processor %s with %d thread(s)\n", np->name, nthreads); goto out_unlock; } - for_each_cpu_mask(cpu, tmp) { - BUG_ON(cpu_isset(cpu, cpu_present_map)); + for_each_cpu(cpu, tmp) { + BUG_ON(cpumask_test_cpu(cpu, cpu_present_mask)); set_cpu_present(cpu, true); set_hard_smp_processor_id(cpu, *intserv++); } err = 0; out_unlock: cpu_maps_update_done(); + free_cpumask_var(candidate_mask); + free_cpumask_var(tmp); return err; } @@ -311,7 +316,7 @@ static void pseries_remove_processor(struct device_node *np) set_hard_smp_processor_id(cpu, -1); break; } - if (cpu == NR_CPUS) + if (cpu >= nr_cpu_ids) printk(KERN_WARNING "Could not find cpu to remove " "with physical id 0x%x\n", intserv[i]); } -- cgit v0.10.2 From 25863de07af9cb90e6365cc8216bdd17f2394515 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:43 +0000 Subject: powerpc/cpumask: Convert NUMA code to new cpumask API Convert NUMA code to new cpumask API. We shift the node to cpumask setup code until after we complete bootmem allocation so we can dynamically allocate the cpumasks. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h index 35acac9..aac87cb 100644 --- a/arch/powerpc/include/asm/mmzone.h +++ b/arch/powerpc/include/asm/mmzone.h @@ -30,7 +30,7 @@ extern struct pglist_data *node_data[]; */ extern int numa_cpu_lookup_table[]; -extern cpumask_t numa_cpumask_lookup_table[]; +extern cpumask_var_t node_to_cpumask_map[]; #ifdef CONFIG_MEMORY_HOTPLUG extern unsigned long max_pfn; #endif diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 789599b..84ad11f 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -29,7 +29,7 @@ static inline int cpu_to_node(int cpu) #define cpumask_of_node(node) ((node) == -1 ? \ cpu_all_mask : \ - &numa_cpumask_lookup_table[node]) + node_to_cpumask_map[node]) int of_node_to_nid(struct device_node *device); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 64c0022..d68491b 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -33,16 +33,41 @@ static int numa_debug; #define dbg(args...) if (numa_debug) { printk(KERN_INFO args); } int numa_cpu_lookup_table[NR_CPUS]; -cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; +cpumask_var_t node_to_cpumask_map[MAX_NUMNODES]; struct pglist_data *node_data[MAX_NUMNODES]; EXPORT_SYMBOL(numa_cpu_lookup_table); -EXPORT_SYMBOL(numa_cpumask_lookup_table); +EXPORT_SYMBOL(node_to_cpumask_map); EXPORT_SYMBOL(node_data); static int min_common_depth; static int n_mem_addr_cells, n_mem_size_cells; +/* + * Allocate node_to_cpumask_map based on number of available nodes + * Requires node_possible_map to be valid. + * + * Note: node_to_cpumask() is not valid until after this is done. + */ +static void __init setup_node_to_cpumask_map(void) +{ + unsigned int node, num = 0; + + /* setup nr_node_ids if not done yet */ + if (nr_node_ids == MAX_NUMNODES) { + for_each_node_mask(node, node_possible_map) + num = node; + nr_node_ids = num + 1; + } + + /* allocate the map */ + for (node = 0; node < nr_node_ids; node++) + alloc_bootmem_cpumask_var(&node_to_cpumask_map[node]); + + /* cpumask_of_node() will now work */ + dbg("Node to cpumask map for %d nodes\n", nr_node_ids); +} + static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn, unsigned int *nid) { @@ -138,8 +163,8 @@ static void __cpuinit map_cpu_to_node(int cpu, int node) dbg("adding cpu %d to node %d\n", cpu, node); - if (!(cpu_isset(cpu, numa_cpumask_lookup_table[node]))) - cpu_set(cpu, numa_cpumask_lookup_table[node]); + if (!(cpumask_test_cpu(cpu, node_to_cpumask_map[node]))) + cpumask_set_cpu(cpu, node_to_cpumask_map[node]); } #ifdef CONFIG_HOTPLUG_CPU @@ -149,8 +174,8 @@ static void unmap_cpu_from_node(unsigned long cpu) dbg("removing cpu %lu from node %d\n", cpu, node); - if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { - cpu_clear(cpu, numa_cpumask_lookup_table[node]); + if (cpumask_test_cpu(cpu, node_to_cpumask_map[node])) { + cpumask_set_cpu(cpu, node_to_cpumask_map[node]); } else { printk(KERN_ERR "WARNING: cpu %lu not found in node %d\n", cpu, node); @@ -737,8 +762,9 @@ void __init dump_numa_cpu_topology(void) * If we used a CPU iterator here we would miss printing * the holes in the cpumap. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (cpumask_test_cpu(cpu, + node_to_cpumask_map[node])) { if (count == 0) printk(" %u", cpu); ++count; @@ -750,7 +776,7 @@ void __init dump_numa_cpu_topology(void) } if (count > 1) - printk("-%u", NR_CPUS - 1); + printk("-%u", nr_cpu_ids - 1); printk("\n"); } } @@ -926,10 +952,6 @@ void __init do_init_bootmem(void) else dump_numa_memory_topology(); - register_cpu_notifier(&ppc64_numa_nb); - cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, - (void *)(unsigned long)boot_cpuid); - for_each_online_node(nid) { unsigned long start_pfn, end_pfn; void *bootmem_vaddr; @@ -983,6 +1005,16 @@ void __init do_init_bootmem(void) } init_bootmem_done = 1; + + /* + * Now bootmem is initialised we can create the node to cpumask + * lookup tables and setup the cpu callback to populate them. + */ + setup_node_to_cpumask_map(); + + register_cpu_notifier(&ppc64_numa_nb); + cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE, + (void *)(unsigned long)boot_cpuid); } void __init paging_init(void) -- cgit v0.10.2 From 828a69869ba266cabb486a6b59ea8643d56b33ce Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:44 +0000 Subject: powerpc/cpumask: Update some comments Since the *_map cpumask variants are deprecated, change the comments to instead refer to *_mask. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 8dcec47..5e4d852 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -394,14 +394,14 @@ static void __init cpu_init_thread_core_maps(int tpc) /** * setup_cpu_maps - initialize the following cpu maps: - * cpu_possible_map - * cpu_present_map + * cpu_possible_mask + * cpu_present_mask * * Having the possible map set up early allows us to restrict allocations * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. * * We do not initialize the online map here; cpus set their own bits in - * cpu_online_map as they come up. + * cpu_online_mask as they come up. * * This function is valid only for Open Firmware systems. finish_device_tree * must be called before using this. diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 39babb1..bf36616 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -468,7 +468,7 @@ out: return id; } -/* Must be called when no change can occur to cpu_present_map, +/* Must be called when no change can occur to cpu_present_mask, * i.e. during cpu online or offline. */ static struct device_node *cpu_to_l2cache(int cpu) diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 15c2241..47a2b44 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -480,7 +480,7 @@ static void __init pmac_init_early(void) #endif /* SMP Init has to be done early as we need to patch up - * cpu_possible_map before interrupt stacks are allocated + * cpu_possible_mask before interrupt stacks are allocated * or kaboom... */ #ifdef CONFIG_SMP diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 6898e82..02d0b8e 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -315,7 +315,7 @@ static int __init smp_psurge_probe(void) /* This is necessary because OF doesn't know about the * secondary cpu(s), and thus there aren't nodes in the * device tree for them, and smp_setup_cpu_maps hasn't - * set their bits in cpu_present_map. + * set their bits in cpu_present_mask. */ if (ncpus > NR_CPUS) ncpus = NR_CPUS; @@ -944,7 +944,7 @@ void __init pmac_setup_smp(void) } #ifdef CONFIG_PPC32 else { - /* We have to set bits in cpu_possible_map here since the + /* We have to set bits in cpu_possible_mask here since the * secondary CPU(s) aren't in the device tree. Various * things won't be initialized for CPUs not in the possible * map, so we really need to fix it up here. diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 235f363..8f85f39 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -222,7 +222,7 @@ static void pseries_cpu_die(unsigned int cpu) } /* - * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle + * Update cpu_present_mask and paca(s) for a new cpu node. The wrinkle * here is that a cpu device node may represent up to two logical cpus * in the SMT case. We must honor the assumption in other code that * the logical ids for sibling SMT threads x and y are adjacent, such @@ -270,7 +270,7 @@ static int pseries_add_processor(struct device_node *np) cpumask_shift_left(tmp, tmp, nthreads); if (cpumask_empty(tmp)) { - printk(KERN_ERR "Unable to find space in cpu_present_map for" + printk(KERN_ERR "Unable to find space in cpu_present_mask for" " processor %s with %d thread(s)\n", np->name, nthreads); goto out_unlock; -- cgit v0.10.2 From 2ef613cb94556ff69860f6bf004298f4e131c216 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 6 May 2010 18:01:46 +1000 Subject: powerpc/cpumask: Convert mpic driver to new cpumask API Convert to the new cpumask API. irq_choose_cpu can be simplified by using cpumask_next and cpumask_first. smp_mpic_message_pass was doing open coded cpumask manipulation and passing an int for a cpumask into mpic_send_ipi. Since mpic_send_ipi is only used locally, make it static and convert it to take a cpumask. This allows us to clean up the mess in smp_mpic_message_pass. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 61913d9..e000cce 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -463,9 +463,6 @@ extern void mpic_cpu_set_priority(int prio); /* Request IPIs on primary mpic */ extern void mpic_request_ipis(void); -/* Send an IPI (non offseted number 0..3) */ -extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); - /* Send a message (IPI) to a given target (cpu number or MSG_*) */ void smp_mpic_message_pass(int target, int msg); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 260295b..2102487 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -568,12 +568,12 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) #endif /* CONFIG_MPIC_U3_HT_IRQS */ #ifdef CONFIG_SMP -static int irq_choose_cpu(const cpumask_t *mask) +static int irq_choose_cpu(const struct cpumask *mask) { int cpuid; if (cpumask_equal(mask, cpu_all_mask)) { - static int irq_rover; + static int irq_rover = 0; static DEFINE_RAW_SPINLOCK(irq_rover_lock); unsigned long flags; @@ -581,15 +581,11 @@ static int irq_choose_cpu(const cpumask_t *mask) do_round_robin: raw_spin_lock_irqsave(&irq_rover_lock, flags); - while (!cpu_online(irq_rover)) { - if (++irq_rover >= NR_CPUS) - irq_rover = 0; - } + irq_rover = cpumask_next(irq_rover, cpu_online_mask); + if (irq_rover >= nr_cpu_ids) + irq_rover = cpumask_first(cpu_online_mask); + cpuid = irq_rover; - do { - if (++irq_rover >= NR_CPUS) - irq_rover = 0; - } while (!cpu_online(irq_rover)); raw_spin_unlock_irqrestore(&irq_rover_lock, flags); } else { @@ -601,7 +597,7 @@ static int irq_choose_cpu(const cpumask_t *mask) return get_hard_smp_processor_id(cpuid); } #else -static int irq_choose_cpu(const cpumask_t *mask) +static int irq_choose_cpu(const struct cpumask *mask) { return hard_smp_processor_id(); } @@ -814,12 +810,16 @@ int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask) mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); } else { - cpumask_t tmp; + cpumask_var_t tmp; - cpumask_and(&tmp, cpumask, cpu_online_mask); + alloc_cpumask_var(&tmp, GFP_KERNEL); + + cpumask_and(tmp, cpumask, cpu_online_mask); mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpus_addr(tmp)[0])); + mpic_physmask(cpumask_bits(tmp)[0])); + + free_cpumask_var(tmp); } return 0; @@ -1479,21 +1479,6 @@ void mpic_teardown_this_cpu(int secondary) } -void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - -#ifdef DEBUG_IPI - DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); -#endif - - mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + - ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), - mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); -} - static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) { u32 src; @@ -1589,8 +1574,25 @@ void mpic_request_ipis(void) } } +static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) +{ + struct mpic *mpic = mpic_primary; + + BUG_ON(mpic == NULL); + +#ifdef DEBUG_IPI + DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); +#endif + + mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + + ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), + mpic_physmask(cpumask_bits(cpu_mask)[0])); +} + void smp_mpic_message_pass(int target, int msg) { + cpumask_var_t tmp; + /* make sure we're sending something that translates to an IPI */ if ((unsigned int)msg > 3) { printk("SMP %d: smp_message_pass: unknown msg %d\n", @@ -1599,13 +1601,17 @@ void smp_mpic_message_pass(int target, int msg) } switch (target) { case MSG_ALL: - mpic_send_ipi(msg, 0xffffffff); + mpic_send_ipi(msg, cpu_online_mask); break; case MSG_ALL_BUT_SELF: - mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); + alloc_cpumask_var(&tmp, GFP_NOWAIT); + cpumask_andnot(tmp, cpu_online_mask, + cpumask_of(smp_processor_id())); + mpic_send_ipi(msg, tmp); + free_cpumask_var(tmp); break; default: - mpic_send_ipi(msg, 1 << target); + mpic_send_ipi(msg, cpumask_of(target)); break; } } @@ -1616,7 +1622,7 @@ int __init smp_mpic_probe(void) DBG("smp_mpic_probe()...\n"); - nr_cpus = cpus_weight(cpu_possible_map); + nr_cpus = cpumask_weight(cpu_possible_mask); DBG("nr_cpus: %d\n", nr_cpus); -- cgit v0.10.2 From ceba1abcb00b0ef0b1efcd715285f6e05523edef Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 26 Apr 2010 15:32:46 +0000 Subject: powerpc/cpumask: Add DEBUG_PER_CPU_MAPS option Enable the DEBUG_PER_CPU_MAPS option so we can look for problems with cpumasks . Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 5cdd7ed..53696da 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -44,6 +44,18 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. +config DEBUG_PER_CPU_MAPS + bool "Debug access to per_cpu maps" + depends on DEBUG_KERNEL + depends on SMP + default n + ---help--- + Say Y to verify that the per_cpu map being accessed has + been setup. Adds a fair amount of code to kernel memory + and decreases performance. + + Say N if unsure. + config HCALL_STATS bool "Hypervisor call instrumentation" depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS -- cgit v0.10.2 From 345e5c8a1cc30ebd527bcc122d9540538942f1ba Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 7 Jan 2010 17:57:46 +0100 Subject: powerpc: Add interrupt support to mpc8xxx_gpio Signed-off-by: Peter Korsgaard Acked-by: Anton Vorontsov Signed-off-by: Kumar Gala diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt index d015dce..b0019eb 100644 --- a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt +++ b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt @@ -11,7 +11,7 @@ Required properties: 83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx. - #gpio-cells : Should be two. The first cell is the pin number and the second cell is used to specify optional parameters (currently unused). - - interrupts : Interrupt mapping for GPIO IRQ (currently unused). + - interrupts : Interrupt mapping for GPIO IRQ. - interrupt-parent : Phandle for the interrupt controller that services interrupts for this device. - gpio-controller : Marks the port as GPIO controller. @@ -38,3 +38,23 @@ Example of gpio-controller nodes for a MPC8347 SoC: See booting-without-of.txt for details of how to specify GPIO information for devices. + +To use GPIO pins as interrupt sources for peripherals, specify the +GPIO controller as the interrupt parent and define GPIO number + +trigger mode using the interrupts property, which is defined like +this: + +interrupts = , where: + - number: GPIO pin (0..31) + - trigger: trigger mode: + 2 = trigger on falling edge + 3 = trigger on both edges + +Example of device using this is: + + funkyfpga@0 { + compatible = "funky-fpga"; + ... + interrupts = <4 3>; + interrupt-parent = <&gpio1>; + }; diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 6478eb1..83f5196 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -16,6 +16,7 @@ #include #include #include +#include #define MPC8XXX_GPIO_PINS 32 @@ -35,6 +36,7 @@ struct mpc8xxx_gpio_chip { * open drain mode safely */ u32 data; + struct irq_host *irq; }; static inline u32 mpc8xxx_gpio2mask(unsigned int gpio) @@ -128,12 +130,136 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return 0; } +static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); + + if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS) + return irq_create_mapping(mpc8xxx_gc->irq, offset); + else + return -ENXIO; +} + +static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_desc_data(desc); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned int mask; + + mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR); + if (mask) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, + 32 - ffs(mask))); +} + +static void mpc8xxx_irq_unmask(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_mask(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq))); + + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); +} + +static void mpc8xxx_irq_ack(unsigned int virq) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq))); +} + +static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq); + struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; + unsigned long flags; + + switch (flow_type) { + case IRQ_TYPE_EDGE_FALLING: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + setbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(virq_to_hw(virq))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + case IRQ_TYPE_EDGE_BOTH: + spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + clrbits32(mm->regs + GPIO_ICR, + mpc8xxx_gpio2mask(virq_to_hw(virq))); + spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static struct irq_chip mpc8xxx_irq_chip = { + .name = "mpc8xxx-gpio", + .unmask = mpc8xxx_irq_unmask, + .mask = mpc8xxx_irq_mask, + .ack = mpc8xxx_irq_ack, + .set_type = mpc8xxx_irq_set_type, +}; + +static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + set_irq_chip_data(virq, h->host_data); + set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_flags) + +{ + /* interrupt sense values coming from the device tree equal either + * EDGE_FALLING or EDGE_BOTH + */ + *out_hwirq = intspec[0]; + *out_flags = intspec[1]; + + return 0; +} + +static struct irq_host_ops mpc8xxx_gpio_irq_ops = { + .map = mpc8xxx_gpio_irq_map, + .xlate = mpc8xxx_gpio_irq_xlate, +}; + static void __init mpc8xxx_add_controller(struct device_node *np) { struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; struct of_gpio_chip *of_gc; struct gpio_chip *gc; + unsigned hwirq; int ret; mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); @@ -158,11 +284,32 @@ static void __init mpc8xxx_add_controller(struct device_node *np) else gc->get = mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; + gc->to_irq = mpc8xxx_gpio_to_irq; ret = of_mm_gpiochip_add(np, mm_gc); if (ret) goto err; + hwirq = irq_of_parse_and_map(np, 0); + if (hwirq == NO_IRQ) + goto skip_irq; + + mpc8xxx_gc->irq = + irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, + &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); + if (!mpc8xxx_gc->irq) + goto skip_irq; + + mpc8xxx_gc->irq->host_data = mpc8xxx_gc; + + /* ack and mask all irqs */ + out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); + out_be32(mm_gc->regs + GPIO_IMR, 0); + + set_irq_data(hwirq, mpc8xxx_gc); + set_irq_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); + +skip_irq: return; err: -- cgit v0.10.2 From 18f397c838e50bb2b8d581dcfc73f3d35ee5b1e2 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 22 Apr 2010 19:25:13 -0500 Subject: powerpc: remove tls_ssl_stream descriptor type capability in sec3.3 node Technically, whilst SEC v3.3 h/w honours the tls_ssl_stream descriptor type, it lacks the ARC4 algorithm execution unit required to be able to execute anything meaningful with it. Change the node to agree with the documentation that declares that the sec3.3 really doesn't have such a descriptor type. Reported-by: Haiying Wang Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 8a3a4f3..508b770 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -292,7 +292,7 @@ fsl,num-channels = <4>; fsl,channel-fifo-len = <24>; fsl,exec-units-mask = <0x97c>; - fsl,descriptor-types-mask = <0x3ab0abf>; + fsl,descriptor-types-mask = <0x3a30abf>; }; sata@18000 { -- cgit v0.10.2 From 7541ef78c3b83e906b580f005207000545cf770a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 15 Apr 2010 22:36:31 +0400 Subject: powerpc/85xx: Add eTSEC 2.0 support for P1020RDB boards This patch adds support for eTSEC 2.0 as found in P1020. The changes include introduction of the group nodes for the etsec nodes. Signed-off-by: Sandeep Gopalpet Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts index df52690..49848c5 100644 --- a/arch/powerpc/boot/dts/p1020rdb.dts +++ b/arch/powerpc/boot/dts/p1020rdb.dts @@ -19,6 +19,9 @@ aliases { serial0 = &serial0; serial1 = &serial1; + ethernet0 = &enet0; + ethernet1 = &enet1; + ethernet2 = &enet2; pci0 = &pci0; pci1 = &pci1; }; @@ -346,6 +349,122 @@ }; }; + mdio@24000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x24000 0x1000 0xb0030 0x4>; + + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + }; + + mdio@25000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-tbi"; + reg = <0x25000 0x1000 0xb1030 0x4>; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0000 0x1000>; + interrupts = <29 2 30 2 34 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb4000 0x1000>; + interrupts = <17 2 18 2 24 2>; + }; + }; + + enet1: ethernet@b1000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + phy-handle = <&phy0>; + tbi-handle = <&tbi0>; + phy-connection-type = "sgmii"; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb1000 0x1000>; + interrupts = <35 2 36 2 40 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb5000 0x1000>; + interrupts = <51 2 52 2 67 2>; + }; + }; + + enet2: ethernet@b2000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb2000 0x1000>; + interrupts = <31 2 32 2 33 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb6000 0x1000>; + interrupts = <25 2 26 2 27 2>; + }; + }; + usb@22000 { #address-cells = <1>; #size-cells = <0>; -- cgit v0.10.2 From 0aedc0085146131da5b04476aab21834b1403b31 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 22 Apr 2010 19:44:47 +0400 Subject: powerpc/85xx: Fix P1020RDB boot hang due USB2 Since USB2 is shared with local bus, either local bus or USB2 should be disabled. By default U-Boot enables local bus, so we have to disable USB2, otherwise kernel hangs: ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver fsl-ehci fsl-ehci.0: Freescale On-Chip EHCI Host Controller fsl-ehci fsl-ehci.0: new USB bus registered, assigned bus number 1 fsl-ehci fsl-ehci.0: irq 28, io base 0xffe22000 fsl-ehci fsl-ehci.0: USB 2.0 started, EHCI 1.00 hub 1-0:1.0: USB hub found hub 1-0:1.0: 1 port detected fsl-ehci fsl-ehci.1: Freescale On-Chip EHCI Host Controller fsl-ehci fsl-ehci.1: new USB bus registered, assigned bus number 2 Note that U-Boot doesn't clear 'status' property when it enables USB2, so we have to comment out the whole node. To enable USB2, one can issue 'setenv hwconfig usb2:dr_mode=' command at the U-Boot prompt. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts index 49848c5..22f64b6 100644 --- a/arch/powerpc/boot/dts/p1020rdb.dts +++ b/arch/powerpc/boot/dts/p1020rdb.dts @@ -475,6 +475,11 @@ phy_type = "ulpi"; }; + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. usb@23000 { #address-cells = <1>; #size-cells = <0>; @@ -484,6 +489,7 @@ interrupts = <46 0x2>; phy_type = "ulpi"; }; + */ sdhci@2e000 { compatible = "fsl,p1020-esdhc", "fsl,esdhc"; -- cgit v0.10.2 From 6971df4f5b0e5b6955c03e8d51bad5d50463f98f Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 2 May 2010 21:27:05 +0400 Subject: powerpc/83xx: Add MCU LEDs support for MPC837xRDB and MPC8315RDB boards There are two front-panel LEDs on MPC837xRDB and MPC8315RDB boards: PWR and HDD. After adding appropriate nodes we can program these LEDs from kernel and user space. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 508b770..4dd08c3 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -463,4 +463,18 @@ 0 0x00800000>; }; }; + + leds { + compatible = "gpio-leds"; + + pwr { + gpios = <&mcu_pio 0 0>; + default-state = "on"; + }; + + hdd { + gpios = <&mcu_pio 1 0>; + linux,default-trigger = "ide-disk"; + }; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts index 9e2264b..dbc1b98 100644 --- a/arch/powerpc/boot/dts/mpc8377_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts @@ -486,4 +486,18 @@ 0 0x00800000>; }; }; + + leds { + compatible = "gpio-leds"; + + pwr { + gpios = <&mcu_pio 0 0>; + default-state = "on"; + }; + + hdd { + gpios = <&mcu_pio 1 0>; + linux,default-trigger = "ide-disk"; + }; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts index 4e6a1a4..3447eb9 100644 --- a/arch/powerpc/boot/dts/mpc8378_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts @@ -470,4 +470,18 @@ 0 0x00800000>; }; }; + + leds { + compatible = "gpio-leds"; + + pwr { + gpios = <&mcu_pio 0 0>; + default-state = "on"; + }; + + hdd { + gpios = <&mcu_pio 1 0>; + linux,default-trigger = "ide-disk"; + }; + }; }; diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts index 72336d5..15560c6 100644 --- a/arch/powerpc/boot/dts/mpc8379_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts @@ -436,4 +436,18 @@ compatible = "fsl,mpc8349-pci"; device_type = "pci"; }; + + leds { + compatible = "gpio-leds"; + + pwr { + gpios = <&mcu_pio 0 0>; + default-state = "on"; + }; + + hdd { + gpios = <&mcu_pio 1 0>; + linux,default-trigger = "ide-disk"; + }; + }; }; diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index 0b4f883..ae525e4 100644 --- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c @@ -74,6 +74,7 @@ static int __init mpc831x_rdb_probe(void) static struct of_device_id __initdata of_bus_ids[] = { { .compatible = "simple-bus" }, { .compatible = "gianfar" }, + { .compatible = "gpio-leds", }, {}, }; diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index a1908d2..e00801c 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -72,6 +72,7 @@ static struct of_device_id mpc837x_ids[] = { { .compatible = "soc", }, { .compatible = "simple-bus", }, { .compatible = "gianfar", }, + { .compatible = "gpio-leds", }, {}, }; -- cgit v0.10.2 From 4c5ddd52695f7bac6362ad13fd3dc878212d1368 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 3 May 2010 16:54:15 -0500 Subject: powerpc/8610: add probing for individual DMA channels, not just DMA controllers A future version of the MPC8610 HPCD's ASoC DMA driver will probe on individual DMA channel nodes, so the DMA controller nodes' compatible string must be listed in mpc8610_ids[] for the probe to work. Also remove the "gianfar" compatible from mpc8610_ids[], since there is no gianfar (or any other networking device) on the 8610. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 5abe137..018cc67 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -83,7 +83,8 @@ static struct of_device_id __initdata mpc8610_ids[] = { { .compatible = "fsl,mpc8610-immr", }, { .compatible = "fsl,mpc8610-guts", }, { .compatible = "simple-bus", }, - { .compatible = "gianfar", }, + /* So that the DMA channel nodes can be probed individually: */ + { .compatible = "fsl,eloplus-dma", }, {} }; -- cgit v0.10.2 From 78e2e68a2b79f394b7cd61e07987a8a89af907f7 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 7 May 2010 16:38:34 +0800 Subject: powerpc/fsl-booke: Fix InstructionTLBError execute permission check In CONFIG_PTE_64BIT the PTE format has unique permission bits for user and supervisor execute. However on !CONFIG_PTE_64BIT we overload the supervisor bit to imply user execute with _PAGE_USER set. This allows us to use the same permission check mask for user or supervisor code on !CONFIG_PTE_64BIT. However, on CONFIG_PTE_64BIT we map _PAGE_EXEC to _PAGE_BAP_UX so we need a different permission mask based on the fault coming from a kernel address or user space. Without unique permission masks we see issues like the following with modules: Unable to handle kernel paging request for instruction fetch Faulting instruction address: 0xf938d040 Oops: Kernel access of bad area, sig: 11 [#1] Signed-off-by: Li Yang Signed-off-by: Jin Qing Signed-off-by: Kumar Gala diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 7255265..edd4a57 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -639,6 +639,13 @@ interrupt_base: rlwinm r12,r12,0,16,1 mtspr SPRN_MAS1,r12 + /* Make up the required permissions for kernel code */ +#ifdef CONFIG_PTE_64BIT + li r13,_PAGE_PRESENT | _PAGE_BAP_SX + oris r13,r13,_PAGE_ACCESSED@h +#else + li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC +#endif b 4f /* Get the PGD for the current thread */ @@ -646,15 +653,15 @@ interrupt_base: mfspr r11,SPRN_SPRG_THREAD lwz r11,PGDIR(r11) -4: - /* Make up the required permissions */ + /* Make up the required permissions for user code */ #ifdef CONFIG_PTE_64BIT - li r13,_PAGE_PRESENT | _PAGE_EXEC + li r13,_PAGE_PRESENT | _PAGE_BAP_UX oris r13,r13,_PAGE_ACCESSED@h #else li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC #endif +4: FIND_PTE andc. r13,r13,r11 /* Check permission */ -- cgit v0.10.2 From 78f622377f7d31d988db350a43c5689dd5f31876 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 13 May 2010 14:38:21 -0500 Subject: powerpc/fsl-booke: Move loadcam_entry back to asm code to fix SMP ftrace When we build with ftrace enabled its possible that loadcam_entry would have used the stack pointer (even though the code doesn't need it). We call loadcam_entry in __secondary_start before the stack is setup. To ensure that loadcam_entry doesn't use the stack pointer the easiest solution is to just have it in asm code. Signed-off-by: Kumar Gala diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 957ceb7..0271b58 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -448,6 +448,14 @@ int main(void) DEFINE(PGD_T_LOG2, PGD_T_LOG2); DEFINE(PTE_T_LOG2, PTE_T_LOG2); #endif +#ifdef CONFIG_FSL_BOOKE + DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam)); + DEFINE(TLBCAM_MAS0, offsetof(struct tlbcam, MAS0)); + DEFINE(TLBCAM_MAS1, offsetof(struct tlbcam, MAS1)); + DEFINE(TLBCAM_MAS2, offsetof(struct tlbcam, MAS2)); + DEFINE(TLBCAM_MAS3, offsetof(struct tlbcam, MAS3)); + DEFINE(TLBCAM_MAS7, offsetof(struct tlbcam, MAS7)); +#endif #ifdef CONFIG_KVM_EXIT_TIMING DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 1ed6b52..cdc7526 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -2,7 +2,7 @@ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support * E500 Book E processors. * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright 2004,2010 Freescale Semiconductor, Inc. * * This file contains the routines for initializing the MMU * on the 4xx series of chips. @@ -56,19 +56,13 @@ unsigned int tlbcam_index; -#define NUM_TLBCAMS (64) #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) #error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" #endif -struct tlbcam { - u32 MAS0; - u32 MAS1; - unsigned long MAS2; - u32 MAS3; - u32 MAS7; -} TLBCAM[NUM_TLBCAMS]; +#define NUM_TLBCAMS (64) +struct tlbcam TLBCAM[NUM_TLBCAMS]; struct tlbcamrange { unsigned long start; @@ -109,19 +103,6 @@ unsigned long p_mapped_by_tlbcam(phys_addr_t pa) return 0; } -void loadcam_entry(int idx) -{ - mtspr(SPRN_MAS0, TLBCAM[idx].MAS0); - mtspr(SPRN_MAS1, TLBCAM[idx].MAS1); - mtspr(SPRN_MAS2, TLBCAM[idx].MAS2); - mtspr(SPRN_MAS3, TLBCAM[idx].MAS3); - - if (mmu_has_feature(MMU_FTR_BIG_PHYS)) - mtspr(SPRN_MAS7, TLBCAM[idx].MAS7); - - asm volatile("isync;tlbwe;isync" : : : "memory"); -} - /* * Set up one of the I/D BAT (block address translation) register pairs. * The parameters are not checked; in particular size must be a power diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index eb11d5d..63b84a0 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -144,7 +144,15 @@ extern unsigned long mmu_mapin_ram(unsigned long top); extern void MMU_init_hw(void); extern unsigned long mmu_mapin_ram(unsigned long top); extern void adjust_total_lowmem(void); - +extern void loadcam_entry(unsigned int index); + +struct tlbcam { + u32 MAS0; + u32 MAS1; + unsigned long MAS2; + u32 MAS3; + u32 MAS7; +}; #elif defined(CONFIG_PPC32) /* anything 32-bit except 4xx or 8xx */ extern void MMU_init_hw(void); diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index e925cb5..cfa7682 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -365,3 +365,31 @@ _GLOBAL(set_context) #else #error Unsupported processor type ! #endif + +#if defined(CONFIG_FSL_BOOKE) +/* + * extern void loadcam_entry(unsigned int index) + * + * Load TLBCAM[index] entry in to the L2 CAM MMU + */ +_GLOBAL(loadcam_entry) + LOAD_REG_ADDR(r4, TLBCAM) + mulli r5,r3,TLBCAM_SIZE + add r3,r5,r4 + lwz r4,TLBCAM_MAS0(r3) + mtspr SPRN_MAS0,r4 + lwz r4,TLBCAM_MAS1(r3) + mtspr SPRN_MAS1,r4 + PPC_LL r4,TLBCAM_MAS2(r3) + mtspr SPRN_MAS2,r4 + lwz r4,TLBCAM_MAS3(r3) + mtspr SPRN_MAS3,r4 +BEGIN_MMU_FTR_SECTION + lwz r4,TLBCAM_MAS7(r3) + mtspr SPRN_MAS7,r4 +END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS) + isync + tlbwe + isync + blr +#endif -- cgit v0.10.2 From 7358650e9e9a81c854dc4582b4193eb5ea500bf6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 19 May 2010 02:12:32 +0000 Subject: powerpc/rtasd: Don't start event scan if scan rate is zero There appear to be Pegasos systems which have the rtas-event-scan RTAS tokens, but on which the event scan always fails. They also have an event-scan-rate property containing 0, which means call event scan 0 times per minute. So interpret a scan rate of 0 to mean don't scan at all. This fixes the problem on the Pegasos machines and makes sense as well. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index e907ca6..638883e 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -490,6 +490,12 @@ static int __init rtas_init(void) return -ENODEV; } + if (!rtas_event_scan_rate) { + /* Broken firmware: take a rate of zero to mean don't scan */ + printk(KERN_DEBUG "rtasd: scan rate is 0, not scanning\n"); + return 0; + } + /* Make room for the sequence number */ rtas_error_log_max = rtas_get_error_log_max(); rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); -- cgit v0.10.2 From ca5d0674c37840366f04a7bbfbf78e7b5f3ce0a4 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 18 May 2010 08:15:21 +0000 Subject: powerpc: Fix string library functions The powerpc strncmp implementation does not correctly handle a zero length, despite the claim in 0119536cd314ef95553604208c25bc35581f7f0a (Add hand-coded assembly strcmp). Additionally, all the length arguments are size_t, not int, so use PPC_LCMPI and eq instead of cmpwi and le throughout. Signed-off-by: Andreas Schwab Acked-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index 3ac0cd3..455881a 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -28,7 +28,7 @@ _GLOBAL(strcpy) /* This clears out any unused part of the destination buffer, just as the libc version does. -- paulus */ _GLOBAL(strncpy) - cmpwi 0,r5,0 + PPC_LCMPI 0,r5,0 beqlr mtctr r5 addi r6,r3,-1 @@ -39,7 +39,7 @@ _GLOBAL(strncpy) bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ bnelr /* if we didn't hit a null char, we're done */ mfctr r5 - cmpwi 0,r5,0 /* any space left in destination buffer? */ + PPC_LCMPI 0,r5,0 /* any space left in destination buffer? */ beqlr /* we know r0 == 0 here */ 2: stbu r0,1(r6) /* clear it out if so */ bdnz 2b @@ -70,8 +70,8 @@ _GLOBAL(strcmp) blr _GLOBAL(strncmp) - PPC_LCMPI r5,0 - ble- 2f + PPC_LCMPI 0,r5,0 + beq- 2f mtctr r5 addi r5,r3,-1 addi r4,r4,-1 @@ -94,8 +94,8 @@ _GLOBAL(strlen) blr _GLOBAL(memcmp) - cmpwi 0,r5,0 - ble- 2f + PPC_LCMPI 0,r5,0 + beq- 2f mtctr r5 addi r6,r3,-1 addi r4,r4,-1 @@ -108,8 +108,8 @@ _GLOBAL(memcmp) blr _GLOBAL(memchr) - cmpwi 0,r5,0 - ble- 2f + PPC_LCMPI 0,r5,0 + beq- 2f mtctr r5 addi r3,r3,-1 1: lbzu r0,1(r3) -- cgit v0.10.2 From abb17f9c3a92c5acf30e749efdf0419b7f50a5b8 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 19 May 2010 02:56:29 +0000 Subject: powerpc: Use common cpu_die (fixes SMP+SUSPEND build) Configuring a powerpc 32 bit kernel for both SMP and SUSPEND turns on CPU_HOTPLUG to enable disable_nonboot_cpus to be called by the common suspend code. Previously the definition of cpu_die for ppc32 was in the powermac platform code, causing it to be undefined if that platform as not selected. arch/powerpc/kernel/built-in.o: In function 'cpu_idle': arch/powerpc/kernel/idle.c:98: undefined reference to 'cpu_die' Move the code from setup_64 to smp.c and rename the power mac versions to their specific names. Note that this does not setup the cpu_die pointers in either smp_ops (request a given cpu die) or ppc_md (make this cpu die), for other platforms but there are generic versions in smp.c. Reported-by: Matt Sealey Reported-by: Kumar Gala Signed-off-by: Milton Miller Signed-off-by: Anton Vorontsov Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 9143891..cea6698 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -573,12 +573,6 @@ void ppc64_boot_msg(unsigned int src, const char *msg) printk("[boot]%04x %s\n", src, msg); } -void cpu_die(void) -{ - if (ppc_md.cpu_die) - ppc_md.cpu_die(); -} - #ifdef CONFIG_SMP #define PCPU_DYN_SIZE () diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index bf36616..5c196d1 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -648,4 +648,10 @@ void cpu_hotplug_driver_unlock() { mutex_unlock(&powerpc_cpu_hotplug_driver_mutex); } + +void cpu_die(void) +{ + if (ppc_md.cpu_die) + ppc_md.cpu_die(); +} #endif diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 3362e78..f0bc08f 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -33,6 +33,8 @@ extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); extern void pmac_setup_smp(void); +extern void pmac32_cpu_die(void); +extern void low_cpu_die(void) __attribute__((noreturn)); extern int pmac_nvram_init(void); extern void pmac_pic_init(void); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 47a2b44..f1d0132 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -646,7 +646,7 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) /* access per cpu vars from generic smp.c */ DECLARE_PER_CPU(int, cpu_state); -static void pmac_cpu_die(void) +static void pmac64_cpu_die(void) { /* * turn off as much as possible, we'll be @@ -717,8 +717,13 @@ define_machine(powermac) { .pcibios_after_init = pmac_pcibios_after_init, .phys_mem_access_prot = pci_phys_mem_access_prot, #endif -#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) - .cpu_die = pmac_cpu_die, +#ifdef CONFIG_HOTPLUG_CPU +#ifdef CONFIG_PPC64 + .cpu_die = pmac64_cpu_die, +#endif +#ifdef CONFIG_PPC32 + .cpu_die = pmac32_cpu_die, +#endif #endif #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32) .cpu_die = generic_mach_cpu_die, diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 02d0b8e..c95215f 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -53,6 +53,8 @@ #include #include +#include "pmac.h" + #undef DEBUG #ifdef DEBUG @@ -878,10 +880,9 @@ int smp_core99_cpu_disable(void) return 0; } -extern void low_cpu_die(void) __attribute__((noreturn)); /* in sleep.S */ static int cpu_dead[NR_CPUS]; -void cpu_die(void) +void pmac32_cpu_die(void) { local_irq_disable(); cpu_dead[smp_processor_id()] = 1; -- cgit v0.10.2 From e62cee42e66dcca83aae02748535f62e0f564a0c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 6 May 2010 19:46:50 +0000 Subject: powerpc: Avoid bad relocations in iSeries code Subrata Modak reported that building a CONFIG_RELOCATABLE kernel with CONFIG_ISERIES enabled gives the following warnings: WARNING: 4 bad relocations c00000000007216e R_PPC64_ADDR16_HIGHEST __ksymtab+0x00000000009dcec8 c000000000072172 R_PPC64_ADDR16_HIGHER __ksymtab+0x00000000009dcec8 c00000000007217a R_PPC64_ADDR16_HI __ksymtab+0x00000000009dcec8 c00000000007217e R_PPC64_ADDR16_LO __ksymtab+0x00000000009dcec8 The reason is that decrementer_iSeries_masked is using LOAD_REG_IMMEDIATE to get the address of a kernel symbol, which creates relocations that aren't handled by the kernel relocator code. Instead of reading the tb_ticks_per_jiffy variable, we can just set the decrementer to its maximum value (0x7fffffff) and that will work just as well. In fact timer_interrupt sets the decrementer to that value initially anyway, and we are sure to get into timer_interrupt once interrupts are reenabled because we store 1 to the decrementer interrupt flag in the lppaca (LPPACADECRINT(r12) here). Reported-by: Subrata Modak Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index fba5bf9..32a56c6 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -252,8 +252,8 @@ decrementer_iSeries_masked: li r11,1 ld r12,PACALPPACAPTR(r13) stb r11,LPPACADECRINT(r12) - LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy) - lwz r12,0(r12) + li r12,-1 + clrldi r12,r12,33 /* set DEC to 0x7fffffff */ mtspr SPRN_DEC,r12 /* fall through */ -- cgit v0.10.2 From a1263c71448aa70afb6097fdedf93c3dff5a7a15 Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 14 May 2010 12:04:41 +0000 Subject: powerpc/vio: Switch VIO Bus PM to use generic helpers Switch to use the generic power management helpers. Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index b8e311d..9ce7b62 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -1381,29 +1381,6 @@ static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env) return 0; } -static int vio_pm_suspend(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm && pm->suspend) - return pm->suspend(dev); - return 0; -} - -static int vio_pm_resume(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm && pm->resume) - return pm->resume(dev); - return 0; -} - -const struct dev_pm_ops vio_dev_pm_ops = { - .suspend = vio_pm_suspend, - .resume = vio_pm_resume, -}; - static struct bus_type vio_bus_type = { .name = "vio", .dev_attrs = vio_dev_attrs, @@ -1411,7 +1388,7 @@ static struct bus_type vio_bus_type = { .match = vio_bus_match, .probe = vio_bus_probe, .remove = vio_bus_remove, - .pm = &vio_dev_pm_ops, + .pm = GENERIC_SUBSYS_PM_OPS, }; /** -- cgit v0.10.2 From 5b339bdf164d8aee394609768f7e2e4415b0252a Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Mon, 10 May 2010 15:13:41 +0000 Subject: powerpc/pci: Check devices status property when scanning OF tree We ran into an issue where it looks like we're not properly ignoring a pci device with a non-good status property when we walk the device tree and instanciate the Linux side PCI devices. However, the EEH init code does look for the property and disables EEH on these devices. This leaves us in an inconsistent where we are poking at a supposedly bad piece of hardware and RTAS will block our config cycles because EEH isn't enabled anyway. Signed-of-by: Sonny Rao Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index cd11d5c..6ddb795f 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -310,6 +310,8 @@ static void __devinit __of_scan_bus(struct device_node *node, /* Scan direct children */ for_each_child_of_node(node, child) { pr_debug(" * %s\n", child->full_name); + if (!of_device_is_available(child)) + continue; reg = of_get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; -- cgit v0.10.2 From ce47c1c45b2b17ad07af82c775f27cc5196080f8 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 10 May 2010 15:38:56 +0000 Subject: powerpc/eeh: Fix oops when probing in early boot If we take an EEH error early enough, we oops: Call Trace: [c000000010483770] [c000000000013ee4] .show_stack+0xd8/0x218 (unreliable) [c000000010483850] [c000000000658940] .dump_stack+0x28/0x3c [c0000000104838d0] [c000000000057a68] .eeh_dn_check_failure+0x2b8/0x304 [c000000010483990] [c0000000000259c8] .rtas_read_config+0x120/0x168 [c000000010483a40] [c000000000025af4] .rtas_pci_read_config+0xe4/0x124 [c000000010483af0] [c00000000037af18] .pci_bus_read_config_word+0xac/0x104 [c000000010483bc0] [c0000000008fec98] .pcibios_allocate_resources+0x7c/0x220 [c000000010483c90] [c0000000008feed8] .pcibios_resource_survey+0x9c/0x418 [c000000010483d80] [c0000000008fea10] .pcibios_init+0xbc/0xf4 [c000000010483e20] [c000000000009844] .do_one_initcall+0x98/0x1d8 [c000000010483ed0] [c0000000008f0560] .kernel_init+0x228/0x2e8 [c000000010483f90] [c000000000031a08] .kernel_thread+0x54/0x70 EEH: Detected PCI bus error on device EEH: This PCI device has failed 1 times in the last hour: EEH: location=U78A5.001.WIH8464-P1 driver= pci addr=0001:00:01.0 EEH: of node=/pci@800000020000209/usb@1 EEH: PCI device/vendor: 00351033 EEH: PCI cmd/status register: 12100146 Unable to handle kernel paging request for data at address 0x00000468 Oops: Kernel access of bad area, sig: 11 [#1] .... NIP [c000000000057610] .rtas_set_slot_reset+0x38/0x10c LR [c000000000058724] .eeh_reset_device+0x5c/0x124 Call Trace: [c00000000bc6bd00] [c00000000005a0e0] .pcibios_remove_pci_devices+0x7c/0xb0 (unreliable) [c00000000bc6bd90] [c000000000058724] .eeh_reset_device+0x5c/0x124 [c00000000bc6be40] [c0000000000589c0] .handle_eeh_events+0x1d4/0x39c [c00000000bc6bf00] [c000000000059124] .eeh_event_handler+0xf0/0x188 [c00000000bc6bf90] [c000000000031a08] .kernel_thread+0x54/0x70 We called rtas_set_slot_reset while scanning the bus and before the pci_dn to pcidev mapping has been created. Since we only need the pcidev to work out the type of reset and that only gets set after the module for the device loads, lets just do a hot reset if the pcidev is NULL. Signed-off-by: Anton Blanchard Acked-by: Linas Vepstas Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 7df7fbb..34b7dc1 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -749,7 +749,7 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn) /* Determine type of EEH reset required by device, * default hot reset or fundamental reset */ - if (dev->needs_freset) + if (dev && dev->needs_freset) rtas_pci_slot_reset(pdn, 3); else rtas_pci_slot_reset(pdn, 1); -- cgit v0.10.2 From 426b6cb478e60352a463a0d1ec75c1c9fab30b13 Mon Sep 17 00:00:00 2001 From: Maxim Uvarov Date: Tue, 11 May 2010 05:41:08 +0000 Subject: powerpc/crashdump: Do not fail on NULL pointer dereferencing Signed-off-by: Maxim Uvarov Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 6f4613d..341d8af 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -375,6 +375,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs) for_each_irq(i) { struct irq_desc *desc = irq_to_desc(i); + if (!desc || !desc->chip || !desc->chip->eoi) + continue; + if (desc->status & IRQ_INPROGRESS) desc->chip->eoi(i); -- cgit v0.10.2 From 0644079410065567e3bb31fcb8e6441f2b7685a9 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 10 May 2010 16:25:51 +0000 Subject: powerpc/kdump: CPUs assume the context of the oopsing CPU We wrap the crash_shutdown_handles[] calls with longjmp/setjmp, so if any of them fault we can recover. The problem is we add a hook to the debugger fault handler hook which calls longjmp unconditionally. This first part of kdump is run before we marshall the other CPUs, so there is a very good chance some CPU on the box is going to page fault. And when it does it hits the longjmp code and assumes the context of the oopsing CPU. The machine gets very confused when it has 10 CPUs all with the same stack, all thinking they have the same CPU id. I get even more confused trying to debug it. The patch below adds crash_shutdown_cpu and uses it to specify which cpu is in the protected region. Since it can only be -1 or the oopsing CPU, we don't need to use memory barriers since it is only valid on the local CPU - no other CPU will ever see a value that matches it's local CPU id. Eventually we should switch the order and marshall all CPUs before doing the crash_shutdown_handles[] calls, but that is a bigger fix. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 341d8af..7ced58d 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -347,10 +347,12 @@ int crash_shutdown_unregister(crash_shutdown_t handler) EXPORT_SYMBOL(crash_shutdown_unregister); static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; +static int crash_shutdown_cpu = -1; static int handle_fault(struct pt_regs *regs) { - longjmp(crash_shutdown_buf, 1); + if (crash_shutdown_cpu == smp_processor_id()) + longjmp(crash_shutdown_buf, 1); return 0; } @@ -391,6 +393,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ old_handler = __debugger_fault_handler; __debugger_fault_handler = handle_fault; + crash_shutdown_cpu = smp_processor_id(); for (i = 0; crash_shutdown_handles[i]; i++) { if (setjmp(crash_shutdown_buf) == 0) { /* @@ -404,6 +407,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) asm volatile("sync; isync"); } } + crash_shutdown_cpu = -1; __debugger_fault_handler = old_handler; /* -- cgit v0.10.2 From 5d7a87217de48b234b3c8ff8a73059947d822e07 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 10 May 2010 16:27:38 +0000 Subject: powerpc/kdump: Use chip->shutdown to disable IRQs I saw this in a kdump kernel: IOMMU table initialized, virtual merging enabled Interrupt 155954 (real) is invalid, disabling it. Interrupt 155953 (real) is invalid, disabling it. ie we took some spurious interrupts. default_machine_crash_shutdown tries to disable all interrupt sources but uses chip->disable which maps to the default action of: static void default_disable(unsigned int irq) { } If we use chip->shutdown, then we actually mask the IRQ: static void default_shutdown(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); desc->chip->mask(irq); desc->status |= IRQ_MASKED; } Not sure why we don't implement a ->disable action for xics.c, or why default_disable doesn't mask the interrupt. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 7ced58d..cca7c8f 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -384,7 +384,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(i); + desc->chip->shutdown(i); } /* -- cgit v0.10.2 From 095c7965f4dc870ed2b65143b1e2610de653416c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 10 May 2010 18:59:18 +0000 Subject: powerpc: Use more accurate limit for first segment memory allocations Author: Milton Miller On large machines we are running out of room below 256MB. In some cases we only need to ensure the allocation is in the first segment, which may be 256MB or 1TB. Add slb0_limit and use it to specify the upper limit for the irqstack and emergency stacks. On a large ppc64 box, this fixes a panic at boot when the crashkernel= option is specified (previously we would run out of memory below 256MB). Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index cea6698..f3fb5a7 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -424,9 +424,18 @@ void __init setup_system(void) DBG(" <- setup_system()\n"); } +static u64 slb0_limit(void) +{ + if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { + return 1UL << SID_SHIFT_1T; + } + return 1UL << SID_SHIFT; +} + #ifdef CONFIG_IRQSTACKS static void __init irqstack_early_init(void) { + u64 limit = slb0_limit(); unsigned int i; /* @@ -436,10 +445,10 @@ static void __init irqstack_early_init(void) for_each_possible_cpu(i) { softirq_ctx[i] = (struct thread_info *) __va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); + THREAD_SIZE, limit)); hardirq_ctx[i] = (struct thread_info *) __va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); + THREAD_SIZE, limit)); } } #else @@ -470,7 +479,7 @@ static void __init exc_lvl_early_init(void) */ static void __init emergency_stack_init(void) { - unsigned long limit; + u64 limit; unsigned int i; /* @@ -482,7 +491,7 @@ static void __init emergency_stack_init(void) * bringup, we need to get at them in real mode. This means they * must also be within the RMO region. */ - limit = min(0x10000000ULL, lmb.rmo_size); + limit = min(slb0_limit(), lmb.rmo_size); for_each_possible_cpu(i) { unsigned long sp; -- cgit v0.10.2 From f90ece28c1f5b3ec13fe481406857fe92f4bc7d1 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 10 May 2010 20:28:26 +0000 Subject: powerpc/pseries: Add hcall to read 4 ptes at a time in real mode This adds plpar_pte_read_4_raw() which can be used read 4 PTEs from PHYP at a time, while in real mode. It also creates a new hcall9 which can be used in real mode. It's the same as plpar_hcall9 but minus the tracing hcall statistics which may require variables outside the RMO. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index ebe7493..5119b7d 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -282,6 +282,7 @@ long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...); */ #define PLPAR_HCALL9_BUFSIZE 9 long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...); +long plpar_hcall9_raw(unsigned long opcode, unsigned long *retbuf, ...); /* For hcall instrumentation. One structure per-hcall, per-CPU */ struct hcall_stats { diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index 383a5d0..48d2057 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -228,3 +228,41 @@ _GLOBAL(plpar_hcall9) mtcrf 0xff,r0 blr /* return r3 = status */ + +/* See plpar_hcall_raw to see why this is needed */ +_GLOBAL(plpar_hcall9_raw) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + std r4,STK_PARM(r4)(r1) /* Save ret buffer */ + + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + mr r9,r10 + ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */ + ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */ + ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */ + + HVSC /* invoke the hypervisor */ + + mr r0,r12 + ld r12,STK_PARM(r4)(r1) + std r4, 0(r12) + std r5, 8(r12) + std r6, 16(r12) + std r7, 24(r12) + std r8, 32(r12) + std r9, 40(r12) + std r10,48(r12) + std r11,56(r12) + std r0, 64(r12) + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 6c4fd2c..d980111 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -191,6 +191,24 @@ static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, return rc; } +/* + * plpar_pte_read_4_raw can be called in real mode. + * ptes must be 8*sizeof(unsigned long) + */ +static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex, + unsigned long *ptes) + +{ + long rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; + + rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex); + + memcpy(ptes, retbuf, 8*sizeof(unsigned long)); + + return rc; +} + static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, unsigned long avpn) { -- cgit v0.10.2 From d504bed676caad29a3dba3d3727298c560628f5c Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 10 May 2010 20:28:26 +0000 Subject: powerpc/kexec: Speedup kexec hash PTE tear down Currently for kexec the PTE tear down on 1TB segment systems normally requires 3 hcalls for each PTE removal. On a machine with 32GB of memory it can take around a minute to remove all the PTEs. This optimises the path so that we only remove PTEs that are valid. It also uses the read 4 PTEs at once HCALL. For the common case where a PTEs is invalid in a 1TB segment, this turns the 3 HCALLs per PTE down to 1 HCALL per 4 PTEs. This gives an > 10x speedup in kexec times on PHYP, taking a 32GB machine from around 1 minute down to a few seconds. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 0707653..cf79b46 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -367,21 +367,28 @@ static void pSeries_lpar_hptab_clear(void) { unsigned long size_bytes = 1UL << ppc64_pft_size; unsigned long hpte_count = size_bytes >> 4; - unsigned long dummy1, dummy2, dword0; + struct { + unsigned long pteh; + unsigned long ptel; + } ptes[4]; long lpar_rc; - int i; + int i, j; - /* TODO: Use bulk call */ - for (i = 0; i < hpte_count; i++) { - /* dont remove HPTEs with VRMA mappings */ - lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG, - &dummy1, &dummy2); - if (lpar_rc == H_NOT_FOUND) { - lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1); - if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK) - != HPTE_V_VRMA_MASK)) - /* Can be hpte for 1TB Seg. So remove it */ - plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2); + /* Read in batches of 4, + * invalidate only valid entries not in the VRMA + * hpte_count will be a multiple of 4 + */ + for (i = 0; i < hpte_count; i += 4) { + lpar_rc = plpar_pte_read_4_raw(0, i, (void *)ptes); + if (lpar_rc != H_SUCCESS) + continue; + for (j = 0; j < 4; j++){ + if ((ptes[j].pteh & HPTE_V_VRMA_MASK) == + HPTE_V_VRMA_MASK) + continue; + if (ptes[j].pteh & HPTE_V_VALID) + plpar_pte_remove_raw(0, i + j, 0, + &(ptes[j].pteh), &(ptes[j].ptel)); } } } -- cgit v0.10.2 From 1fc711f7ffb01089efc58042cfdbac8573d1b59a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 13 May 2010 19:40:11 +0000 Subject: powerpc/kexec: Fix race in kexec shutdown In kexec_prepare_cpus, the primary CPU IPIs the secondary CPUs to kexec_smp_down(). kexec_smp_down() calls kexec_smp_wait() which sets the hw_cpu_id() to -1. The primary does this while leaving IRQs on which means the primary can take a timer interrupt which can lead to the IPIing one of the secondary CPUs (say, for a scheduler re-balance) but since the secondary CPU now has a hw_cpu_id = -1, we IPI CPU -1... Kaboom! We are hitting this case regularly on POWER7 machines. There is also a second race, where the primary will tear down the MMU mappings before knowing the secondaries have entered real mode. Also, the secondaries are clearing out any pending IPIs before guaranteeing that no more will be received. This changes kexec_prepare_cpus() so that we turn off IRQs in the primary CPU much earlier. It adds a paca flag to say that the secondaries have entered the kexec_smp_down() IPI and turned off IRQs, rather than overloading hw_cpu_id with -1. This new paca flag is again used to in indicate when the secondaries has entered real mode. It also ensures that all CPUs have their IRQs off before we clear out any pending IPI requests (in kexec_cpu_down()) to ensure there are no trailing IPIs left unacknowledged. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 7e06b43..a6ca6da 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -31,6 +31,10 @@ #define KEXEC_ARCH KEXEC_ARCH_PPC #endif +#define KEXEC_STATE_NONE 0 +#define KEXEC_STATE_IRQS_OFF 1 +#define KEXEC_STATE_REAL_MODE 2 + #ifndef __ASSEMBLY__ #include #include diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index a011603..971dfa4 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -82,6 +82,7 @@ struct paca_struct { s16 hw_cpu_id; /* Physical processor number */ u8 cpu_start; /* At startup, processor spins until */ /* this becomes non-zero. */ + u8 kexec_state; /* set when kexec down has irqs off */ #ifdef CONFIG_PPC_STD_MMU_64 struct slb_shadow *slb_shadow_ptr; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0271b58..1b784ff9 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -184,6 +184,7 @@ int main(void) #endif /* CONFIG_PPC_STD_MMU_64 */ DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); + DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state)); DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr)); DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr)); DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time)); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 040bd1d..26f9900 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -155,33 +155,38 @@ void kexec_copy_flush(struct kimage *image) #ifdef CONFIG_SMP -/* FIXME: we should schedule this function to be called on all cpus based - * on calling the interrupts, but we would like to call it off irq level - * so that the interrupt controller is clean. - */ +static int kexec_all_irq_disabled = 0; + static void kexec_smp_down(void *arg) { + local_irq_disable(); + mb(); /* make sure our irqs are disabled before we say they are */ + get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF; + while(kexec_all_irq_disabled == 0) + cpu_relax(); + mb(); /* make sure all irqs are disabled before this */ + /* + * Now every CPU has IRQs off, we can clear out any pending + * IPIs and be sure that no more will come in after this. + */ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 1); - local_irq_disable(); kexec_smp_wait(); /* NOTREACHED */ } -static void kexec_prepare_cpus(void) +static void kexec_prepare_cpus_wait(int wait_state) { int my_cpu, i, notified=-1; - smp_call_function(kexec_smp_down, NULL, /* wait */0); my_cpu = get_cpu(); - - /* check the others cpus are now down (via paca hw cpu id == -1) */ + /* Make sure each CPU has atleast made it to the state we need */ for (i=0; i < NR_CPUS; i++) { if (i == my_cpu) continue; - while (paca[i].hw_cpu_id != -1) { + while (paca[i].kexec_state < wait_state) { barrier(); if (!cpu_possible(i)) { printk("kexec: cpu %d hw_cpu_id %d is not" @@ -201,20 +206,35 @@ static void kexec_prepare_cpus(void) } if (i != notified) { printk( "kexec: waiting for cpu %d (physical" - " %d) to go down\n", - i, paca[i].hw_cpu_id); + " %d) to enter %i state\n", + i, paca[i].hw_cpu_id, wait_state); notified = i; } } } + mb(); +} + +static void kexec_prepare_cpus(void) +{ + + smp_call_function(kexec_smp_down, NULL, /* wait */0); + local_irq_disable(); + mb(); /* make sure IRQs are disabled before we say they are */ + get_paca()->kexec_state = KEXEC_STATE_IRQS_OFF; + + kexec_prepare_cpus_wait(KEXEC_STATE_IRQS_OFF); + /* we are sure every CPU has IRQs off at this point */ + kexec_all_irq_disabled = 1; /* after we tell the others to go down */ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); - put_cpu(); + /* Before removing MMU mapings make sure all CPUs have entered real mode */ + kexec_prepare_cpus_wait(KEXEC_STATE_REAL_MODE); - local_irq_disable(); + put_cpu(); } #else /* ! SMP */ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index a5cf9c1..a2b18df 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -24,6 +24,7 @@ #include #include #include +#include .text @@ -471,6 +472,10 @@ _GLOBAL(kexec_wait) 1: mflr r5 addi r5,r5,kexec_flag-1b + li r4,KEXEC_STATE_REAL_MODE + stb r4,PACAKEXECSTATE(r13) + SYNC + 99: HMT_LOW #ifdef CONFIG_KEXEC /* use no memory without kexec */ lwz r4,0(r5) @@ -494,14 +499,11 @@ kexec_flag: * note: this is a terminal routine, it does not save lr * * get phys id from paca - * set paca id to -1 to say we got here * switch to real mode * join other cpus in kexec_wait(phys_id) */ _GLOBAL(kexec_smp_wait) lhz r3,PACAHWCPUID(r13) - li r4,-1 - sth r4,PACAHWCPUID(r13) /* let others know we left */ bl real_mode b .kexec_wait diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 0c40c6f..f88acf0 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -18,6 +18,7 @@ #include #include #include +#include /* This symbol is provided by the linker - let it fill in the paca * field correctly */ @@ -97,6 +98,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) new_paca->kernelbase = (unsigned long) _stext; new_paca->kernel_msr = MSR_KERNEL; new_paca->hw_cpu_id = 0xffff; + new_paca->kexec_state = KEXEC_STATE_NONE; new_paca->__current = &init_task; #ifdef CONFIG_PPC_STD_MMU_64 new_paca->slb_shadow_ptr = &slb_shadow[cpu]; -- cgit v0.10.2 From 60adec6226bbcf061d4c2d10944fced209d1847d Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 13 May 2010 19:40:11 +0000 Subject: powerpc/kdump: Fix race in kdump shutdown When we are crashing, the crashing/primary CPU IPIs the secondaries to turn off IRQs, go into real mode and wait in kexec_wait. While this is happening, the primary tears down all the MMU maps. Unfortunately the primary doesn't check to make sure the secondaries have entered real mode before doing this. On PHYP machines, the secondaries can take a long time shutting down the IRQ controller as RTAS calls are need. These RTAS calls need to be serialised which resilts in the secondaries contending in lock_rtas() and hence taking a long time to shut down. We've hit this on large POWER7 machines, where some secondaries are still waiting in lock_rtas(), when the primary tears down the HPTEs. This patch makes sure all secondaries are in real mode before the primary tears down the MMU. It uses the new kexec_state entry in the paca. It times out if the secondaries don't reach real mode after 10sec. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index cca7c8f..8c066d6 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -162,6 +162,32 @@ static void crash_kexec_prepare_cpus(int cpu) /* Leave the IPI callback set */ } +/* wait for all the CPUs to hit real mode but timeout if they don't come in */ +static void crash_kexec_wait_realmode(int cpu) +{ + unsigned int msecs; + int i; + + msecs = 10000; + for (i=0; i < NR_CPUS && msecs > 0; i++) { + if (i == cpu) + continue; + + while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { + barrier(); + if (!cpu_possible(i)) { + break; + } + if (!cpu_online(i)) { + break; + } + msecs--; + mdelay(1); + } + } + mb(); +} + /* * This function will be called by secondary cpus or by kexec cpu * if soft-reset is activated to stop some CPUs. @@ -419,6 +445,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crash_kexec_prepare_cpus(crashing_cpu); cpu_set(crashing_cpu, cpus_in_crash); crash_kexec_stop_spus(); + crash_kexec_wait_realmode(crashing_cpu); if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); } -- cgit v0.10.2 From dd04c63c96425af9b6741f3abf0ad25d6b1c0e8d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 16 May 2010 20:01:28 +0000 Subject: powerpc: Remove check of ibm,smt-snooze-delay OF property I'm not sure why we have code for parsing an ibm,smt-snooze-delay OF property. Since we have a smt-snooze-delay= boot option and we can also set it at runtime via sysfs, it should be safe to get rid of this code. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index e235e52..158fb73 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -67,33 +67,6 @@ static ssize_t show_smt_snooze_delay(struct sys_device *dev, static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, store_smt_snooze_delay); -/* Only parse OF options if the matching cmdline option was not specified */ -static int smt_snooze_cmdline; - -static int __init smt_setup(void) -{ - struct device_node *options; - const unsigned int *val; - unsigned int cpu; - - if (!cpu_has_feature(CPU_FTR_SMT)) - return -ENODEV; - - options = of_find_node_by_path("/options"); - if (!options) - return -ENODEV; - - val = of_get_property(options, "ibm,smt-snooze-delay", NULL); - if (!smt_snooze_cmdline && val) { - for_each_possible_cpu(cpu) - per_cpu(smt_snooze_delay, cpu) = *val; - } - - of_node_put(options); - return 0; -} -__initcall(smt_setup); - static int __init setup_smt_snooze_delay(char *str) { unsigned int cpu; @@ -102,8 +75,6 @@ static int __init setup_smt_snooze_delay(char *str) if (!cpu_has_feature(CPU_FTR_SMT)) return 1; - smt_snooze_cmdline = 1; - if (get_option(&str, &snooze)) { for_each_possible_cpu(cpu) per_cpu(smt_snooze_delay, cpu) = snooze; -- cgit v0.10.2 From b878dc00595440586874952dd85ce9b803360b87 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 16 May 2010 20:02:39 +0000 Subject: powerpc: Use smt_snooze_delay=-1 to always busy loop Right now if we want to busy loop and not give up any time to the hypervisor we put a very large value into smt_snooze_delay. This is sometimes useful when running a single partition and you want to avoid any latencies due to the hypervisor or CPU power state transitions. While this works, it's a bit ugly - how big a number is enough now we have NO_HZ and can be idle for a very long time. The patch below makes smt_snooze_delay signed, and a negative value means loop forever: echo -1 > /sys/devices/system/cpu/cpu0/smt_snooze_delay This change shouldn't affect the existing userspace tools (eg ppc64_cpu), but I'm cc-ing Nathan just to be sure. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 158fb73..c0d8c20 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -35,7 +35,7 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); #ifdef CONFIG_PPC64 /* Time in microseconds we delay before sleeping in the idle loop */ -DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 }; +DEFINE_PER_CPU(long, smt_snooze_delay) = { 100 }; static ssize_t store_smt_snooze_delay(struct sys_device *dev, struct sysdev_attribute *attr, @@ -44,9 +44,9 @@ static ssize_t store_smt_snooze_delay(struct sys_device *dev, { struct cpu *cpu = container_of(dev, struct cpu, sysdev); ssize_t ret; - unsigned long snooze; + long snooze; - ret = sscanf(buf, "%lu", &snooze); + ret = sscanf(buf, "%ld", &snooze); if (ret != 1) return -EINVAL; @@ -61,7 +61,7 @@ static ssize_t show_smt_snooze_delay(struct sys_device *dev, { struct cpu *cpu = container_of(dev, struct cpu, sysdev); - return sprintf(buf, "%lu\n", per_cpu(smt_snooze_delay, cpu->sysdev.id)); + return sprintf(buf, "%ld\n", per_cpu(smt_snooze_delay, cpu->sysdev.id)); } static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, @@ -70,15 +70,14 @@ static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, static int __init setup_smt_snooze_delay(char *str) { unsigned int cpu; - int snooze; + long snooze; if (!cpu_has_feature(CPU_FTR_SMT)) return 1; - if (get_option(&str, &snooze)) { - for_each_possible_cpu(cpu) - per_cpu(smt_snooze_delay, cpu) = snooze; - } + snooze = simple_strtol(str, NULL, 10); + for_each_possible_cpu(cpu) + per_cpu(smt_snooze_delay, cpu) = snooze; return 1; } diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 6710761..a6d19e3 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -496,13 +496,14 @@ static int __init pSeries_probe(void) } -DECLARE_PER_CPU(unsigned long, smt_snooze_delay); +DECLARE_PER_CPU(long, smt_snooze_delay); static void pseries_dedicated_idle_sleep(void) { unsigned int cpu = smp_processor_id(); unsigned long start_snooze; unsigned long in_purr, out_purr; + long snooze = __get_cpu_var(smt_snooze_delay); /* * Indicate to the HV that we are idle. Now would be @@ -517,13 +518,12 @@ static void pseries_dedicated_idle_sleep(void) * has been checked recently. If we should poll for a little * while, do so. */ - if (__get_cpu_var(smt_snooze_delay)) { - start_snooze = get_tb() + - __get_cpu_var(smt_snooze_delay) * tb_ticks_per_usec; + if (snooze) { + start_snooze = get_tb() + snooze * tb_ticks_per_usec; local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - while (get_tb() < start_snooze) { + while ((snooze < 0) || (get_tb() < start_snooze)) { if (need_resched() || cpu_is_offline(cpu)) goto out; ppc64_runlatch_off(); -- cgit v0.10.2 From 56608209d34b8add40af54031d4e420afbcde9f6 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 16 May 2010 20:19:56 +0000 Subject: powerpc/numa: Set a smaller value for RECLAIM_DISTANCE to enable zone reclaim I noticed /proc/sys/vm/zone_reclaim_mode was 0 on a ppc64 NUMA box. It gets enabled via this: /* * If another node is sufficiently far away then it is better * to reclaim pages in a zone before going off node. */ if (distance > RECLAIM_DISTANCE) zone_reclaim_mode = 1; Since we use the default value of 20 for REMOTE_DISTANCE and 20 for RECLAIM_DISTANCE it never kicks in. The local to remote bandwidth ratios can be quite large on System p machines so it makes sense for us to reclaim clean pagecache locally before going off node. The patch below sets a smaller value for RECLAIM_DISTANCE and thus enables zone reclaim. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 84ad11f..32adf72 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -18,6 +18,16 @@ struct device_node; */ #define RECLAIM_DISTANCE 10 +/* + * Before going off node we want the VM to try and reclaim from the local + * node. It does this if the remote distance is larger than RECLAIM_DISTANCE. + * With the default REMOTE_DISTANCE of 20 and the default RECLAIM_DISTANCE of + * 20, we never reclaim and go off node straight away. + * + * To fix this we choose a smaller value of RECLAIM_DISTANCE. + */ +#define RECLAIM_DISTANCE 10 + #include static inline int cpu_to_node(int cpu) -- cgit v0.10.2 From bc8449cc57898bc9cf1ffc4619d026f77bf327c1 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 16 May 2010 20:28:35 +0000 Subject: powerpc/numa: Use ibm,architecture-vec-5 to detect form 1 affinity I've been told that the architected way to determine we are in form 1 affinity mode is by reading the ibm,architecture-vec-5 property which mirrors the layout of the fifth vector of the ibm,client-architecture structure. Eventually we may want to parse the ibm,architecture-vec-5 and create FW_FEATURE_* bits. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index aace5e5..80d1106 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -271,7 +271,8 @@ static int __init find_min_common_depth(void) const unsigned int *ref_points; struct device_node *rtas_root; unsigned int len; - struct device_node *options; + struct device_node *chosen; + const char *vec5; rtas_root = of_find_node_by_path("/rtas"); @@ -289,14 +290,17 @@ static int __init find_min_common_depth(void) "ibm,associativity-reference-points", &len); /* - * For type 1 affinity information we want the first field + * For form 1 affinity information we want the first field */ - options = of_find_node_by_path("/options"); - if (options) { - const char *str; - str = of_get_property(options, "ibm,associativity-form", NULL); - if (str && !strcmp(str, "1")) - index = 0; +#define VEC5_AFFINITY_BYTE 5 +#define VEC5_AFFINITY 0x80 + chosen = of_find_node_by_path("/chosen"); + if (chosen) { + vec5 = of_get_property(chosen, "ibm,architecture-vec-5", NULL); + if (vec5 && (vec5[VEC5_AFFINITY_BYTE] & VEC5_AFFINITY)) { + dbg("Using form 1 affinity\n"); + index = 0; + } } if ((len >= 2 * sizeof(unsigned int)) && ref_points) { -- cgit v0.10.2 From 32c96f7765b881ab1f6ab8ff04b733e4cf157239 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Tue, 18 May 2010 22:51:00 +0000 Subject: powerpc/pseries: Make request_ras_irqs() available to other pseries code At the moment only the RAS code uses event-sources interrupts (for EPOW events and internal errors) so request_ras_irqs() (which actually requests the event-sources interrupts) is found in ras.c and is static. We want to be able to use event-sources interrupts in other pseries code, so let's rename request_ras_irqs() to request_event_sources_irqs() and move it to event_sources.c. This will be used in an upcoming patch that adds support for IO Event interrupts that come through as event sources. Signed-off-by: Mark Nelson Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 0ff5174..3dbef30 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -7,7 +7,7 @@ EXTRA_CFLAGS += -DDEBUG endif obj-y := lpar.o hvCall.o nvram.o reconfig.o \ - setup.o iommu.o ras.o \ + setup.o iommu.o event_sources.o ras.o \ firmware.o power.o dlpar.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c new file mode 100644 index 0000000..e889c9d --- /dev/null +++ b/arch/powerpc/platforms/pseries/event_sources.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2001 Dave Engebretsen IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "pseries.h" + +void request_event_sources_irqs(struct device_node *np, + irq_handler_t handler, + const char *name) +{ + int i, index, count = 0; + struct of_irq oirq; + const u32 *opicprop; + unsigned int opicplen; + unsigned int virqs[16]; + + /* Check for obsolete "open-pic-interrupt" property. If present, then + * map those interrupts using the default interrupt host and default + * trigger + */ + opicprop = of_get_property(np, "open-pic-interrupt", &opicplen); + if (opicprop) { + opicplen /= sizeof(u32); + for (i = 0; i < opicplen; i++) { + if (count > 15) + break; + virqs[count] = irq_create_mapping(NULL, *(opicprop++)); + if (virqs[count] == NO_IRQ) + printk(KERN_ERR "Unable to allocate interrupt " + "number for %s\n", np->full_name); + else + count++; + + } + } + /* Else use normal interrupt tree parsing */ + else { + /* First try to do a proper OF tree parsing */ + for (index = 0; of_irq_map_one(np, index, &oirq) == 0; + index++) { + if (count > 15) + break; + virqs[count] = irq_create_of_mapping(oirq.controller, + oirq.specifier, + oirq.size); + if (virqs[count] == NO_IRQ) + printk(KERN_ERR "Unable to allocate interrupt " + "number for %s\n", np->full_name); + else + count++; + } + } + + /* Now request them */ + for (i = 0; i < count; i++) { + if (request_irq(virqs[i], handler, 0, name, NULL)) { + printk(KERN_ERR "Unable to request interrupt %d for " + "%s\n", virqs[i], np->full_name); + return; + } + } +} + diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 9e17c0d..40c93ca 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -10,6 +10,13 @@ #ifndef _PSERIES_PSERIES_H #define _PSERIES_PSERIES_H +#include + +struct device_node; + +extern void request_event_sources_irqs(struct device_node *np, + irq_handler_t handler, const char *name); + extern void __init fw_feature_init(const char *hypertas, unsigned long len); struct pt_regs; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index db940d2..41a3e9a 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -67,63 +67,6 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); static irqreturn_t ras_error_interrupt(int irq, void *dev_id); -static void request_ras_irqs(struct device_node *np, - irq_handler_t handler, - const char *name) -{ - int i, index, count = 0; - struct of_irq oirq; - const u32 *opicprop; - unsigned int opicplen; - unsigned int virqs[16]; - - /* Check for obsolete "open-pic-interrupt" property. If present, then - * map those interrupts using the default interrupt host and default - * trigger - */ - opicprop = of_get_property(np, "open-pic-interrupt", &opicplen); - if (opicprop) { - opicplen /= sizeof(u32); - for (i = 0; i < opicplen; i++) { - if (count > 15) - break; - virqs[count] = irq_create_mapping(NULL, *(opicprop++)); - if (virqs[count] == NO_IRQ) - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", np->full_name); - else - count++; - - } - } - /* Else use normal interrupt tree parsing */ - else { - /* First try to do a proper OF tree parsing */ - for (index = 0; of_irq_map_one(np, index, &oirq) == 0; - index++) { - if (count > 15) - break; - virqs[count] = irq_create_of_mapping(oirq.controller, - oirq.specifier, - oirq.size); - if (virqs[count] == NO_IRQ) - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", np->full_name); - else - count++; - } - } - - /* Now request them */ - for (i = 0; i < count; i++) { - if (request_irq(virqs[i], handler, 0, name, NULL)) { - printk(KERN_ERR "Unable to request interrupt %d for " - "%s\n", virqs[i], np->full_name); - return; - } - } -} - /* * Initialize handlers for the set of interrupts caused by hardware errors * and power system events. @@ -138,14 +81,15 @@ static int __init init_ras_IRQ(void) /* Internal Errors */ np = of_find_node_by_path("/event-sources/internal-errors"); if (np != NULL) { - request_ras_irqs(np, ras_error_interrupt, "RAS_ERROR"); + request_event_sources_irqs(np, ras_error_interrupt, + "RAS_ERROR"); of_node_put(np); } /* EPOW Events */ np = of_find_node_by_path("/event-sources/epow-events"); if (np != NULL) { - request_ras_irqs(np, ras_epow_interrupt, "RAS_EPOW"); + request_event_sources_irqs(np, ras_epow_interrupt, "RAS_EPOW"); of_node_put(np); } -- cgit v0.10.2 From 40a5a4435f37b172dec09852ad2036865f9ca3c8 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Sun, 18 Apr 2010 20:05:41 +0000 Subject: powerpc: Build-in e1000e for pseries & ppc64_defconfig The e1000e device is becoming more common these days, so let's just build it in for pseries & ppc64_defconfig. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 12980d5..dad617e 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -988,7 +988,7 @@ CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y # CONFIG_DL2K is not set CONFIG_E1000=y -CONFIG_E1000E=m +CONFIG_E1000E=y # CONFIG_IP1000 is not set # CONFIG_IGB is not set # CONFIG_NS83820 is not set diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 41de3dd..16a1458 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -804,7 +804,7 @@ CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y # CONFIG_DL2K is not set CONFIG_E1000=y -CONFIG_E1000E=m +CONFIG_E1000E=y # CONFIG_IP1000 is not set # CONFIG_IGB is not set # CONFIG_NS83820 is not set -- cgit v0.10.2 From 99ec28f183daa450faa7bdad6f932364ae325648 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sun, 9 May 2010 17:39:05 +0000 Subject: powerpc: Remove unused 'protect4gb' boot parameter 'protect4gb' boot parameter was introduced to avoid allocating dma space acrossing 4GB boundary in 2007 (the commit 569975591c5530fdc9c7a3c45122e5e46f075a74). In 2008, the IOMMU was fixed to use the boundary_mask parameter per device properly. So 'protect4gb' workaround was removed (the 383af9525bb27f927511874f6306247ec13f1c28). But somehow I messed the 'protect4gb' boot parameter that was used to enable the workaround. Signed-off-by: FUJITA Tomonori Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index ec94f90..d583917 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -43,20 +43,9 @@ #define DBG(...) static int novmerge; -static int protect4gb = 1; static void __iommu_free(struct iommu_table *, dma_addr_t, unsigned int); -static int __init setup_protect4gb(char *str) -{ - if (strcmp(str, "on") == 0) - protect4gb = 1; - else if (strcmp(str, "off") == 0) - protect4gb = 0; - - return 1; -} - static int __init setup_iommu(char *str) { if (!strcmp(str, "novmerge")) @@ -66,7 +55,6 @@ static int __init setup_iommu(char *str) return 1; } -__setup("protect4gb=", setup_protect4gb); __setup("iommu=", setup_iommu); static unsigned long iommu_range_alloc(struct device *dev, -- cgit v0.10.2