aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig4
-rw-r--r--arch/powerpc/Makefile2
-rw-r--r--arch/powerpc/boot/Makefile7
-rw-r--r--arch/powerpc/boot/dts/obs600.dts314
-rwxr-xr-xarch/powerpc/boot/wrapper22
-rw-r--r--arch/powerpc/configs/40x/obs600_defconfig83
-rw-r--r--arch/powerpc/configs/ppc64_defconfig5
-rw-r--r--arch/powerpc/configs/ps3_defconfig39
-rw-r--r--arch/powerpc/configs/pseries_defconfig5
-rw-r--r--arch/powerpc/include/asm/lv1call.h10
-rw-r--r--arch/powerpc/include/asm/paca.h1
-rw-r--r--arch/powerpc/include/asm/processor.h3
-rw-r--r--arch/powerpc/include/asm/rtas.h12
-rw-r--r--arch/powerpc/include/asm/system.h9
-rw-r--r--arch/powerpc/kernel/asm-offsets.c1
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S2
-rw-r--r--arch/powerpc/kernel/idle.c27
-rw-r--r--arch/powerpc/kernel/idle_power7.S4
-rw-r--r--arch/powerpc/kernel/irq.c4
-rw-r--r--arch/powerpc/kernel/prom_init.c2
-rw-r--r--arch/powerpc/kernel/sysfs.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S3
-rw-r--r--arch/powerpc/mm/mem.c3
-rw-r--r--arch/powerpc/platforms/40x/Kconfig10
-rw-r--r--arch/powerpc/platforms/40x/ppc40x_simple.c3
-rw-r--r--arch/powerpc/platforms/Kconfig6
-rw-r--r--arch/powerpc/platforms/powernv/smp.c2
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c103
-rw-r--r--arch/powerpc/platforms/ps3/repository.c137
-rw-r--r--arch/powerpc/platforms/ps3/setup.c4
-rw-r--r--arch/powerpc/platforms/ps3/smp.c2
-rw-r--r--arch/powerpc/platforms/ps3/spu.c2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig9
-rw-r--r--arch/powerpc/platforms/pseries/Makefile1
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c7
-rw-r--r--arch/powerpc/platforms/pseries/processor_idle.c329
-rw-r--r--arch/powerpc/platforms/pseries/pseries.h3
-rw-r--r--arch/powerpc/platforms/pseries/setup.c104
-rw-r--r--arch/powerpc/platforms/pseries/smp.c1
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c4
-rw-r--r--drivers/tty/serial/pmac_zilog.c102
-rw-r--r--include/linux/cpuidle.h2
42 files changed, 1101 insertions, 294 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7c93c7eb0e5..d66a47fde80 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -87,6 +87,10 @@ config ARCH_HAS_ILOG2_U64
bool
default y if 64BIT
+config ARCH_HAS_CPU_IDLE_WAIT
+ bool
+ default y
+
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 59f462b796b..ffe4d88f5a8 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -165,7 +165,7 @@ all: zImage
# With make 3.82 we cannot mix normal and wildcard targets
BOOT_TARGETS1 := zImage zImage.initrd uImage
-BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.%
+BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% uImage.%
PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 72ee8c1fba4..80c133c8856 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -199,6 +199,7 @@ image-$(CONFIG_EP405) += dtbImage.ep405
image-$(CONFIG_HOTFOOT) += cuImage.hotfoot
image-$(CONFIG_WALNUT) += treeImage.walnut
image-$(CONFIG_ACADIA) += cuImage.acadia
+image-$(CONFIG_OBS600) += uImage.obs600
# Board ports in arch/powerpc/platform/44x/Kconfig
image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
@@ -316,6 +317,12 @@ $(obj)/zImage.iseries: vmlinux
$(obj)/uImage: vmlinux $(wrapperbits)
$(call if_changed,wrap,uboot)
+$(obj)/uImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits)
+ $(call if_changed,wrap,uboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz)
+
+$(obj)/uImage.%: vmlinux $(obj)/%.dtb $(wrapperbits)
+ $(call if_changed,wrap,uboot-$*,,$(obj)/$*.dtb)
+
$(obj)/cuImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits)
$(call if_changed,wrap,cuboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz)
diff --git a/arch/powerpc/boot/dts/obs600.dts b/arch/powerpc/boot/dts/obs600.dts
new file mode 100644
index 00000000000..18e7d79ee4c
--- /dev/null
+++ b/arch/powerpc/boot/dts/obs600.dts
@@ -0,0 +1,314 @@
+/*
+ * Device Tree Source for PlatHome OpenBlockS 600 (405EX)
+ *
+ * Copyright 2011 Ben Herrenschmidt, IBM Corp.
+ *
+ * Based on Kilauea by:
+ *
+ * Copyright 2007-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * 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 = <1>;
+ #size-cells = <1>;
+ model = "PlatHome,OpenBlockS 600";
+ compatible = "plathome,obs600";
+ dcr-parent = <&{/cpus/cpu@0}>;
+
+ aliases {
+ ethernet0 = &EMAC0;
+ ethernet1 = &EMAC1;
+ serial0 = &UART0;
+ serial1 = &UART1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,405EX";
+ reg = <0x00000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <16384>; /* 16 kB */
+ d-cache-size = <16384>; /* 16 kB */
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000>; /* Filled in by U-Boot */
+ };
+
+ UIC0: interrupt-controller {
+ compatible = "ibm,uic-405ex", "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-405ex","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>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-405ex","ibm,uic";
+ interrupt-controller;
+ cell-index = <2>;
+ dcr-reg = <0x0e0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x1c 0x4 0x1d 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ CPM0: cpm {
+ compatible = "ibm,cpm";
+ dcr-access-method = "native";
+ dcr-reg = <0x0b0 0x003>;
+ unused-units = <0x00000000>;
+ idle-doze = <0x02000000>;
+ standby = <0xe3e74800>;
+ };
+
+ plb {
+ compatible = "ibm,plb-405ex", "ibm,plb4";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ SDRAM0: memory-controller {
+ compatible = "ibm,sdram-405ex", "ibm,sdram-4xx-ddr2";
+ dcr-reg = <0x010 0x002>;
+ interrupt-parent = <&UIC2>;
+ interrupts = <0x5 0x4 /* ECC DED Error */
+ 0x6 0x4>; /* ECC SEC Error */
+ };
+
+ CRYPTO: crypto@ef700000 {
+ compatible = "amcc,ppc405ex-crypto", "amcc,ppc4xx-crypto";
+ reg = <0xef700000 0x80400>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x17 0x2>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-405ex", "ibm,mcmal2";
+ dcr-reg = <0x180 0x062>;
+ num-tx-chans = <2>;
+ num-rx-chans = <2>;
+ interrupt-parent = <&MAL0>;
+ interrupts = <0x0 0x1 0x2 0x3 0x4>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*TXEOB*/ 0x0 &UIC0 0xa 0x4
+ /*RXEOB*/ 0x1 &UIC0 0xb 0x4
+ /*SERR*/ 0x2 &UIC1 0x0 0x4
+ /*TXDE*/ 0x3 &UIC1 0x1 0x4
+ /*RXDE*/ 0x4 &UIC1 0x2 0x4>;
+ interrupt-map-mask = <0xffffffff>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-405ex", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x80000000 0x80000000 0x10000000
+ 0xef600000 0xef600000 0x00a00000
+ 0xf0000000 0xf0000000 0x10000000>;
+ dcr-reg = <0x0a0 0x005>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-405ex", "ibm,ebc";
+ dcr-reg = <0x012 0x002>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
+ interrupts = <0x5 0x1>;
+ interrupt-parent = <&UIC1>;
+
+ nor_flash@0,0 {
+ compatible = "amd,s29gl512n", "cfi-flash";
+ bank-width = <2>;
+ reg = <0x00000000 0x00000000 0x08000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "kernel + initrd";
+ reg = <0x00000000 0x03de0000>;
+ };
+ partition@3de0000 {
+ label = "user config area";
+ reg = <0x03de0000 0x00080000>;
+ };
+ partition@3e60000 {
+ label = "user program area";
+ reg = <0x03e60000 0x04000000>;
+ };
+ partition@7e60000 {
+ label = "flat device tree";
+ reg = <0x07e60000 0x00080000>;
+ };
+ partition@7ee0000 {
+ label = "test program";
+ reg = <0x07ee0000 0x00080000>;
+ };
+ partition@7f60000 {
+ label = "u-boot env";
+ reg = <0x07f60000 0x00040000>;
+ };
+ partition@7fa0000 {
+ label = "u-boot";
+ reg = <0x07fa0000 0x00060000>;
+ };
+ };
+ };
+
+ UART0: serial@ef600200 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600200 0x00000008>;
+ virtual-reg = <0xef600200>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1a 0x4>;
+ };
+
+ UART1: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600300 0x00000008>;
+ virtual-reg = <0xef600300>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1 0x4>;
+ };
+
+ IIC0: i2c@ef600400 {
+ compatible = "ibm,iic-405ex", "ibm,iic";
+ reg = <0xef600400 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x2 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@68 {
+ compatible = "dallas,ds1340";
+ reg = <0x68>;
+ };
+ };
+
+ IIC1: i2c@ef600500 {
+ compatible = "ibm,iic-405ex", "ibm,iic";
+ reg = <0xef600500 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x7 0x4>;
+ };
+
+ RGMII0: emac-rgmii@ef600b00 {
+ compatible = "ibm,rgmii-405ex", "ibm,rgmii";
+ reg = <0xef600b00 0x00000104>;
+ has-mdio;
+ };
+
+ EMAC0: ethernet@ef600900 {
+ linux,network-index = <0x0>;
+ device_type = "network";
+ compatible = "ibm,emac-405ex", "ibm,emac4sync";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC0 0x18 0x4
+ /*Wake*/ 0x1 &UIC1 0x1d 0x4>;
+ reg = <0xef600900 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ rx-fifo-size-gige = <16384>;
+ tx-fifo-size-gige = <16384>;
+ phy-mode = "rgmii";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC1: ethernet@ef600a00 {
+ linux,network-index = <0x1>;
+ device_type = "network";
+ compatible = "ibm,emac-405ex", "ibm,emac4sync";
+ interrupt-parent = <&EMAC1>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC0 0x19 0x4
+ /*Wake*/ 0x1 &UIC1 0x1f 0x4>;
+ reg = <0xef600a00 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <1>;
+ cell-index = <1>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ rx-fifo-size-gige = <16384>;
+ tx-fifo-size-gige = <16384>;
+ phy-mode = "rgmii";
+ phy-map = <0x00000000>;
+ rgmii-device = <&RGMII0>;
+ rgmii-channel = <1>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ GPIO: gpio@ef600800 {
+ device_type = "gpio";
+ compatible = "ibm,gpio-405ex", "ibm,ppc4xx-gpio";
+ reg = <0xef600800 0x50>;
+ };
+ };
+ };
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@ef600200";
+ };
+};
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index c74531af72c..14cd4bca8b8 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -163,7 +163,7 @@ coff)
link_address='0x500000'
pie=
;;
-miboot|uboot)
+miboot|uboot*)
# miboot and U-boot want just the bare bits, not an ELF binary
ext=bin
objflags="-O binary"
@@ -291,6 +291,26 @@ uboot)
fi
exit 0
;;
+uboot-obs600)
+ rm -f "$ofile"
+ # obs600 wants a multi image with an initrd, so we need to put a fake
+ # one in even when building a "normal" image.
+ if [ -n "$initrd" ]; then
+ real_rd="$initrd"
+ else
+ real_rd=`mktemp`
+ echo "\0" >>"$real_rd"
+ fi
+ ${MKIMAGE} -A ppc -O linux -T multi -C gzip -a $membase -e $membase \
+ $uboot_version -d "$vmz":"$real_rd":"$dtb" "$ofile"
+ if [ -z "$initrd" ]; then
+ rm -f "$real_rd"
+ fi
+ if [ -z "$cacheit" ]; then
+ rm -f "$vmz"
+ fi
+ exit 0
+ ;;
esac
addsec() {
diff --git a/arch/powerpc/configs/40x/obs600_defconfig b/arch/powerpc/configs/40x/obs600_defconfig
new file mode 100644
index 00000000000..91c110dad2d
--- /dev/null
+++ b/arch/powerpc/configs/40x/obs600_defconfig
@@ -0,0 +1,83 @@
+CONFIG_40x=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_WALNUT is not set
+CONFIG_OBS600=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_MATH_EMULATION=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# 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_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_NDFC=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=35000
+CONFIG_NETDEVICES=y
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=256
+CONFIG_IBM_EMAC_TXB=256
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_IBM_IIC=y
+CONFIG_SENSORS_LM75=y
+CONFIG_THERMAL=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_EXT2_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 535711fcb13..2156e077859 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -390,6 +390,11 @@ CONFIG_HUGETLBFS=y
CONFIG_HFS_FS=m
CONFIG_HFSPLUS_FS=m
CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 185c292b0f1..ded867871e9 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -6,10 +6,10 @@ CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
-CONFIG_NAMESPACES=y
+CONFIG_SPARSE_IRQ=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
# CONFIG_PERF_EVENTS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
@@ -17,6 +17,7 @@ CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
+# CONFIG_PPC_POWERNV is not set
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_PMAC is not set
CONFIG_PPC_PS3=y
@@ -27,14 +28,14 @@ CONFIG_PS3_VRAM=m
CONFIG_PS3_LPM=m
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=y
CONFIG_KEXEC=y
-CONFIG_SPARSE_IRQ=y
# CONFIG_SPARSEMEM_VMEMMAP is not set
CONFIG_SCHED_SMT=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
-CONFIG_PM=y
+CONFIG_PM_RUNTIME=y
CONFIG_PM_DEBUG=y
# CONFIG_SECCOMP is not set
# CONFIG_PCI is not set
@@ -81,20 +82,23 @@ CONFIG_SCSI_MULTI_LUN=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=m
CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_GELIC_NET=y
CONFIG_GELIC_WIRELESS=y
-# CONFIG_NETDEV_10000 is not set
+# CONFIG_NET_VENDOR_XILINX is not set
CONFIG_USB_USBNET=m
# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_NCM is not set
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
-CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPPOE=m
CONFIG_INPUT_FF_MEMLESS=m
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_JOYDEV=m
@@ -135,22 +139,21 @@ CONFIG_USB=m
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=m
CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_EHCI_TT_NEWSCHED=y
# CONFIG_USB_EHCI_HCD_PPC_OF is not set
CONFIG_USB_OHCI_HCD=m
CONFIG_USB_STORAGE=m
CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_PS3=m
+CONFIG_RTC_DRV_PS3=y
+# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=m
CONFIG_EXT3_FS=m
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
-CONFIG_INOTIFY=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
-CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
@@ -167,19 +170,17 @@ CONFIG_CIFS=m
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
+CONFIG_CRC_CCITT=m
CONFIG_CRC_T10DIF=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_LOCKDEP=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_WRITECOUNT=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_FTRACE is not set
CONFIG_DEBUG_STACKOVERFLOW=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index a72f2415a64..30e7d0d20e4 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -304,6 +304,11 @@ CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
diff --git a/arch/powerpc/include/asm/lv1call.h b/arch/powerpc/include/asm/lv1call.h
index f77c708c67a..233f9ecae76 100644
--- a/arch/powerpc/include/asm/lv1call.h
+++ b/arch/powerpc/include/asm/lv1call.h
@@ -231,7 +231,7 @@ LV1_CALL(allocate_memory, 4, 2, 0 )
LV1_CALL(write_htab_entry, 4, 0, 1 )
LV1_CALL(construct_virtual_address_space, 3, 2, 2 )
LV1_CALL(invalidate_htab_entries, 5, 0, 3 )
-LV1_CALL(get_virtual_address_space_id_of_ppe, 1, 1, 4 )
+LV1_CALL(get_virtual_address_space_id_of_ppe, 0, 1, 4 )
LV1_CALL(query_logical_partition_address_region_info, 1, 5, 6 )
LV1_CALL(select_virtual_address_space, 1, 0, 7 )
LV1_CALL(pause, 1, 0, 9 )
@@ -264,7 +264,7 @@ LV1_CALL(configure_execution_time_variable, 1, 0, 77 )
LV1_CALL(get_spe_irq_outlet, 2, 1, 78 )
LV1_CALL(set_spe_privilege_state_area_1_register, 3, 0, 79 )
LV1_CALL(create_repository_node, 6, 0, 90 )
-LV1_CALL(get_repository_node_value, 5, 2, 91 )
+LV1_CALL(read_repository_node, 5, 2, 91 )
LV1_CALL(modify_repository_node_value, 6, 0, 92 )
LV1_CALL(remove_repository_node, 4, 0, 93 )
LV1_CALL(read_htab_entries, 2, 5, 95 )
@@ -276,7 +276,7 @@ LV1_CALL(construct_io_irq_outlet, 1, 1, 120 )
LV1_CALL(destruct_io_irq_outlet, 1, 0, 121 )
LV1_CALL(map_htab, 1, 1, 122 )
LV1_CALL(unmap_htab, 1, 0, 123 )
-LV1_CALL(get_version_info, 0, 1, 127 )
+LV1_CALL(get_version_info, 0, 2, 127 )
LV1_CALL(insert_htab_entry, 6, 3, 158 )
LV1_CALL(read_virtual_uart, 3, 1, 162 )
LV1_CALL(write_virtual_uart, 3, 1, 163 )
@@ -294,9 +294,9 @@ LV1_CALL(unmap_device_dma_region, 4, 0, 177 )
LV1_CALL(net_add_multicast_address, 4, 0, 185 )
LV1_CALL(net_remove_multicast_address, 4, 0, 186 )
LV1_CALL(net_start_tx_dma, 4, 0, 187 )
-LV1_CALL(net_stop_tx_dma, 3, 0, 188 )
+LV1_CALL(net_stop_tx_dma, 2, 0, 188 )
LV1_CALL(net_start_rx_dma, 4, 0, 189 )
-LV1_CALL(net_stop_rx_dma, 3, 0, 190 )
+LV1_CALL(net_stop_rx_dma, 2, 0, 190 )
LV1_CALL(net_set_interrupt_status_indicator, 4, 0, 191 )
LV1_CALL(net_set_interrupt_mask, 4, 0, 193 )
LV1_CALL(net_control, 6, 2, 194 )
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 17722c73ba2..269c05a36d9 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -135,6 +135,7 @@ struct paca_struct {
u8 hard_enabled; /* set if irqs are enabled in MSR */
u8 io_sync; /* writel() needs spin_unlock sync */
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
+ u8 nap_state_lost; /* NV GPR values lost in power7_idle */
#ifdef CONFIG_PPC_POWERNV
/* Pointer to OPAL machine check event structure set by the
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index eb11a446720..b585bff1a02 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -382,6 +382,9 @@ static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
}
#endif
+extern unsigned long cpuidle_disable;
+enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PROCESSOR_H */
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 1646b76bd3d..01c143bb77a 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -313,5 +313,17 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg)
extern void __cpuinit rtas_give_timebase(void);
extern void __cpuinit rtas_take_timebase(void);
+#ifdef CONFIG_PPC_RTAS
+static inline int page_is_rtas_user_buf(unsigned long pfn)
+{
+ unsigned long paddr = (pfn << PAGE_SHIFT);
+ if (paddr >= rtas_rmo_buf && paddr < (rtas_rmo_buf + RTAS_RMOBUF_MAX))
+ return 1;
+ return 0;
+}
+#else
+static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;}
+#endif
+
#endif /* __KERNEL__ */
#endif /* _POWERPC_RTAS_H */
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index d51c2c20dd2..c377457d1b8 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -221,6 +221,15 @@ extern unsigned long klimit;
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
extern int powersave_nap; /* set if nap mode can be used in idle loop */
+void cpu_idle_wait(void);
+
+#ifdef CONFIG_PSERIES_IDLE
+extern void update_smt_snooze_delay(int snooze);
+extern int pseries_notify_cpuidle_add_cpu(int cpu);
+#else
+static inline void update_smt_snooze_delay(int snooze) {}
+static inline int pseries_notify_cpuidle_add_cpu(int cpu) { return 0; }
+#endif
/*
* Atomic exchange
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 7c5324f1ec9..04caee7d9bc 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -208,6 +208,7 @@ int main(void)
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
+ DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost));
#endif /* CONFIG_PPC64 */
/* RTAS */
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index cf9c69b9189..d4be7bb3dbd 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -65,7 +65,7 @@ BEGIN_FTR_SECTION
lbz r0,PACAPROCSTART(r13)
cmpwi r0,0x80
bne 1f
- li r0,0
+ li r0,1
stb r0,PACAPROCSTART(r13)
b kvm_start_guest
1:
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 39a2baa6ad5..8574b0e81ff 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -39,9 +39,13 @@
#define cpu_should_die() 0
#endif
+unsigned long cpuidle_disable = IDLE_NO_OVERRIDE;
+EXPORT_SYMBOL(cpuidle_disable);
+
static int __init powersave_off(char *arg)
{
ppc_md.power_save = NULL;
+ cpuidle_disable = IDLE_POWERSAVE_OFF;
return 0;
}
__setup("powersave=off", powersave_off);
@@ -102,6 +106,29 @@ void cpu_idle(void)
}
}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs come out of the old
+ * idle loop and start using the new idle loop.
+ * Required while changing idle handler on SMP systems.
+ * Caller must have changed idle handler to the new value before the call.
+ * This window may be larger on shared systems.
+ */
+void cpu_idle_wait(void)
+{
+ int cpu;
+ smp_mb();
+
+ /* kick all the CPUs so that they exit out of old idle routine */
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id())
+ smp_send_reschedule(cpu);
+ }
+ put_online_cpus();
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
int powersave_nap;
#ifdef CONFIG_SYSCTL
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 3a70845a51c..fcdff198da4 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -54,6 +54,7 @@ _GLOBAL(power7_idle)
li r0,0
stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
stb r0,PACAHARDIRQEN(r13)
+ stb r0,PACA_NAPSTATELOST(r13)
/* Continue saving state */
SAVE_GPR(2, r1)
@@ -86,6 +87,9 @@ _GLOBAL(power7_wakeup_loss)
rfid
_GLOBAL(power7_wakeup_noloss)
+ lbz r0,PACA_NAPSTATELOST(r13)
+ cmpwi r0,0
+ bne .power7_wakeup_loss
ld r1,PACAR1(r13)
ld r4,_MSR(r1)
ld r5,_NIP(r1)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 2ff4f5e5962..701d4aceb4f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -186,8 +186,8 @@ notrace void arch_local_irq_restore(unsigned long en)
* Any HV call will have this side effect.
*/
if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
- u64 tmp;
- lv1_get_version_info(&tmp);
+ u64 tmp, tmp2;
+ lv1_get_version_info(&tmp, &tmp2);
}
__hard_irq_enable();
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index f4f9f2f1432..df47316f1ae 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -742,7 +742,7 @@ static unsigned char ibm_architecture_vec[] = {
W(0xffffffff), /* virt_base */
W(0xffffffff), /* virt_size */
W(0xffffffff), /* load_base */
- W(64), /* 64MB min RMA */
+ W(256), /* 256MB min RMA */
W(0xffffffff), /* full client load */
0, /* min RMA percentage of total RAM */
48, /* max log_2(hash table size) */
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index f579be55209..6fdf5ffe8c4 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -18,6 +18,7 @@
#include <asm/machdep.h>
#include <asm/smp.h>
#include <asm/pmc.h>
+#include <asm/system.h>
#include "cacheinfo.h"
@@ -51,6 +52,7 @@ static ssize_t store_smt_snooze_delay(struct sys_device *dev,
return -EINVAL;
per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze;
+ update_smt_snooze_delay(snooze);
return count;
}
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 44d8829334a..5c8b26183f5 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -112,6 +112,9 @@ kvm_start_guest:
stbcix r0, r5, r6 /* clear it */
stwcix r8, r5, r7 /* EOI it */
+ /* NV GPR values from power7_idle() will no longer be valid */
+ stb r0, PACA_NAPSTATELOST(r13)
+
.global kvmppc_hv_entry
kvmppc_hv_entry:
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 83d819f3086..395f42d5f78 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -51,6 +51,7 @@
#include <asm/vdso.h>
#include <asm/fixmap.h>
#include <asm/swiotlb.h>
+#include <asm/rtas.h>
#include "mmu_decl.h"
@@ -600,6 +601,8 @@ int devmem_is_allowed(unsigned long pfn)
return 0;
if (!page_is_ram(pfn))
return 1;
+ if (page_is_rtas_user_buf(pfn))
+ return 1;
return 0;
}
#endif /* CONFIG_STRICT_DEVMEM */
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index 153022971da..bac24a09131 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -100,6 +100,16 @@ config XILINX_VIRTEX_GENERIC_BOARD
Most Virtex designs should use this unless it needs to do some
special configuration at board probe time.
+config OBS600
+ bool "OpenBlockS 600"
+ depends on 40x
+ default n
+ select 405EX
+ select PPC40x_SIMPLE
+ help
+ This option enables support for PlatHome OpenBlockS 600 server
+
+
config PPC40x_SIMPLE
bool "Simple PowerPC 40x board support"
depends on 40x
diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c
index e8dd5c5df7d..ecac237827e 100644
--- a/arch/powerpc/platforms/40x/ppc40x_simple.c
+++ b/arch/powerpc/platforms/40x/ppc40x_simple.c
@@ -55,7 +55,8 @@ static const char *board[] __initdata = {
"amcc,haleakala",
"amcc,kilauea",
"amcc,makalu",
- "est,hotfoot"
+ "est,hotfoot",
+ "plathome,obs600"
};
static int __init ppc40x_probe(void)
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 3fe6d927ad7..31e1adeaa92 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -211,6 +211,12 @@ config PPC_PASEMI_CPUFREQ
endmenu
+menu "CPUIdle driver"
+
+source "drivers/cpuidle/Kconfig"
+
+endmenu
+
config PPC601_SYNC_FIX
bool "Workarounds for PPC601 bugs"
depends on 6xx && (PPC_PREP || PPC_PMAC)
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index e8773668524..17210c526c5 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -75,7 +75,7 @@ int __devinit pnv_smp_kick_cpu(int nr)
/* On OPAL v2 the CPU are still spinning inside OPAL itself,
* get them back now
*/
- if (firmware_has_feature(FW_FEATURE_OPALv2)) {
+ if (!paca[nr].cpu_start && firmware_has_feature(FW_FEATURE_OPALv2)) {
pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu);
rc = opal_start_cpu(pcpu, start_here);
if (rc != OPAL_SUCCESS)
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 1d6f4f478fe..617efa12a3a 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -31,18 +31,18 @@
#if defined(DEBUG)
#define DBG udbg_printf
+#define FAIL udbg_printf
#else
-#define DBG pr_debug
+#define DBG pr_devel
+#define FAIL pr_debug
#endif
/**
* struct ps3_bmp - a per cpu irq status and mask bitmap structure
* @status: 256 bit status bitmap indexed by plug
- * @unused_1:
+ * @unused_1: Alignment
* @mask: 256 bit mask bitmap indexed by plug
- * @unused_2:
- * @lock:
- * @ipi_debug_brk_mask:
+ * @unused_2: Alignment
*
* The HV maintains per SMT thread mappings of HV outlet to HV plug on
* behalf of the guest. These mappings are implemented as 256 bit guest
@@ -73,21 +73,24 @@ struct ps3_bmp {
unsigned long mask;
u64 unused_2[3];
};
- u64 ipi_debug_brk_mask;
- spinlock_t lock;
};
/**
* struct ps3_private - a per cpu data structure
* @bmp: ps3_bmp structure
+ * @bmp_lock: Syncronize access to bmp.
+ * @ipi_debug_brk_mask: Mask for debug break IPIs
* @ppe_id: HV logical_ppe_id
* @thread_id: HV thread_id
+ * @ipi_mask: Mask of IPI virqs
*/
struct ps3_private {
struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
+ spinlock_t bmp_lock;
u64 ppe_id;
u64 thread_id;
+ unsigned long ipi_debug_brk_mask;
unsigned long ipi_mask;
};
@@ -105,7 +108,7 @@ static void ps3_chip_mask(struct irq_data *d)
struct ps3_private *pd = irq_data_get_irq_chip_data(d);
unsigned long flags;
- pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
+ DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
pd->thread_id, d->irq);
local_irq_save(flags);
@@ -126,7 +129,7 @@ static void ps3_chip_unmask(struct irq_data *d)
struct ps3_private *pd = irq_data_get_irq_chip_data(d);
unsigned long flags;
- pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
+ DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
pd->thread_id, d->irq);
local_irq_save(flags);
@@ -190,19 +193,19 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
*virq = irq_create_mapping(NULL, outlet);
if (*virq == NO_IRQ) {
- pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
+ FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n",
__func__, __LINE__, outlet);
result = -ENOMEM;
goto fail_create;
}
- pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
+ DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
outlet, cpu, *virq);
result = irq_set_chip_data(*virq, pd);
if (result) {
- pr_debug("%s:%d: irq_set_chip_data failed\n",
+ FAIL("%s:%d: irq_set_chip_data failed\n",
__func__, __LINE__);
goto fail_set;
}
@@ -228,13 +231,13 @@ static int ps3_virq_destroy(unsigned int virq)
{
const struct ps3_private *pd = irq_get_chip_data(virq);
- pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
+ DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
__LINE__, pd->ppe_id, pd->thread_id, virq);
irq_set_chip_data(virq, NULL);
irq_dispose_mapping(virq);
- pr_debug("%s:%d <-\n", __func__, __LINE__);
+ DBG("%s:%d <-\n", __func__, __LINE__);
return 0;
}
@@ -257,7 +260,7 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
result = ps3_virq_setup(cpu, outlet, virq);
if (result) {
- pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
+ FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
goto fail_setup;
}
@@ -269,7 +272,7 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
outlet, 0);
if (result) {
- pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+ FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
__func__, __LINE__, ps3_result(result));
result = -EPERM;
goto fail_connect;
@@ -298,7 +301,7 @@ int ps3_irq_plug_destroy(unsigned int virq)
int result;
const struct ps3_private *pd = irq_get_chip_data(virq);
- pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
+ DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
__LINE__, pd->ppe_id, pd->thread_id, virq);
ps3_chip_mask(irq_get_irq_data(virq));
@@ -306,7 +309,7 @@ int ps3_irq_plug_destroy(unsigned int virq)
result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
if (result)
- pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+ FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
__func__, __LINE__, ps3_result(result));
ps3_virq_destroy(virq);
@@ -334,7 +337,7 @@ int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
result = lv1_construct_event_receive_port(&outlet);
if (result) {
- pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n",
+ FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
*virq = NO_IRQ;
return result;
@@ -360,14 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq)
{
int result;
- pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
+ DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
ps3_chip_mask(irq_get_irq_data(virq));
result = lv1_destruct_event_receive_port(virq_to_hw(virq));
if (result)
- pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
+ FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
/*
@@ -375,7 +378,7 @@ int ps3_event_receive_port_destroy(unsigned int virq)
* calls from interrupt context (smp_call_function) when kexecing.
*/
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ DBG(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -411,7 +414,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
if (result) {
- pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
+ FAIL("%s:%d: lv1_connect_interrupt_event_receive_port"
" failed: %s\n", __func__, __LINE__,
ps3_result(result));
ps3_event_receive_port_destroy(*virq);
@@ -419,7 +422,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
return result;
}
- pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
+ DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
dev->interrupt_id, *virq);
return 0;
@@ -433,14 +436,14 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
int result;
- pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
+ DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
dev->interrupt_id, virq);
result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,
dev->dev_id, virq_to_hw(virq), dev->interrupt_id);
if (result)
- pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port"
+ FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port"
" failed: %s\n", __func__, __LINE__,
ps3_result(result));
@@ -455,7 +458,7 @@ int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
result = ps3_virq_destroy(virq);
BUG_ON(result);
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ DBG(" <- %s:%d\n", __func__, __LINE__);
return result;
}
EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
@@ -480,7 +483,7 @@ int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
if (result) {
- pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
+ FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
@@ -510,7 +513,7 @@ int ps3_io_irq_destroy(unsigned int virq)
result = lv1_destruct_io_irq_outlet(outlet);
if (result)
- pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+ FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
@@ -542,7 +545,7 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet);
if (result) {
- pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
+ FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
@@ -562,7 +565,7 @@ int ps3_vuart_irq_destroy(unsigned int virq)
result = lv1_deconfigure_virtual_uart_irq();
if (result) {
- pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
+ FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
@@ -595,7 +598,7 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
result = lv1_get_spe_irq_outlet(spe_id, class, &outlet);
if (result) {
- pr_debug("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",
+ FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",
__func__, __LINE__, ps3_result(result));
return result;
}
@@ -626,7 +629,7 @@ int ps3_spe_irq_destroy(unsigned int virq)
static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
const char* func, int line)
{
- pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
+ pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n",
func, line, header, cpu,
*p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff,
*p & 0xffff);
@@ -635,7 +638,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
static void __maybe_unused _dump_256_bmp(const char *header,
const u64 *p, unsigned cpu, const char* func, int line)
{
- pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
+ pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n",
func, line, header, cpu, p[0], p[1], p[2], p[3]);
}
@@ -644,10 +647,10 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
{
unsigned long flags;
- spin_lock_irqsave(&pd->bmp.lock, flags);
+ spin_lock_irqsave(&pd->bmp_lock, flags);
_dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line);
- _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
- spin_unlock_irqrestore(&pd->bmp.lock, flags);
+ _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line);
+ spin_unlock_irqrestore(&pd->bmp_lock, flags);
}
#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
@@ -656,9 +659,9 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
{
unsigned long flags;
- spin_lock_irqsave(&pd->bmp.lock, flags);
- _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
- spin_unlock_irqrestore(&pd->bmp.lock, flags);
+ spin_lock_irqsave(&pd->bmp_lock, flags);
+ _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line);
+ spin_unlock_irqrestore(&pd->bmp_lock, flags);
}
#else
static void dump_bmp(struct ps3_private* pd) {};
@@ -667,7 +670,7 @@ static void dump_bmp(struct ps3_private* pd) {};
static int ps3_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hwirq)
{
- pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
+ DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
virq);
irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
@@ -690,10 +693,10 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
{
struct ps3_private *pd = &per_cpu(ps3_private, cpu);
- pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
+ set_bit(63 - virq, &pd->ipi_debug_brk_mask);
- pr_debug("%s:%d: cpu %u, virq %u, mask %llxh\n", __func__, __LINE__,
- cpu, virq, pd->bmp.ipi_debug_brk_mask);
+ DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__,
+ cpu, virq, pd->ipi_debug_brk_mask);
}
void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq)
@@ -714,14 +717,14 @@ static unsigned int ps3_get_irq(void)
/* check for ipi break first to stop this cpu ASAP */
- if (x & pd->bmp.ipi_debug_brk_mask)
- x &= pd->bmp.ipi_debug_brk_mask;
+ if (x & pd->ipi_debug_brk_mask)
+ x &= pd->ipi_debug_brk_mask;
asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
plug &= 0x3f;
if (unlikely(plug == NO_IRQ)) {
- pr_debug("%s:%d: no plug found: thread_id %llu\n", __func__,
+ DBG("%s:%d: no plug found: thread_id %llu\n", __func__,
__LINE__, pd->thread_id);
dump_bmp(&per_cpu(ps3_private, 0));
dump_bmp(&per_cpu(ps3_private, 1));
@@ -760,9 +763,9 @@ void __init ps3_init_IRQ(void)
lv1_get_logical_ppe_id(&pd->ppe_id);
pd->thread_id = get_hard_smp_processor_id(cpu);
- spin_lock_init(&pd->bmp.lock);
+ spin_lock_init(&pd->bmp_lock);
- pr_debug("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n",
+ DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n",
__func__, __LINE__, pd->ppe_id, pd->thread_id,
ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
@@ -770,7 +773,7 @@ void __init ps3_init_IRQ(void)
pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
if (result)
- pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
+ FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:"
" %s\n", __func__, __LINE__,
ps3_result(result));
}
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index ca40f6afd35..7bdfea336f5 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -44,7 +44,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line)
s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.';
s[i] = 0;
- pr_debug("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s);
+ pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s);
#endif
}
@@ -53,7 +53,7 @@ static void _dump_field(const char *hdr, u64 n, const char *func, int line)
static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,
u64 n4, const char *func, int line)
{
- pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id);
+ pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
_dump_field("n1: ", n1, func, line);
_dump_field("n2: ", n2, func, line);
_dump_field("n3: ", n3, func, line);
@@ -65,13 +65,13 @@ static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,
static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
u64 v1, u64 v2, const char *func, int line)
{
- pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id);
+ pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
_dump_field("n1: ", n1, func, line);
_dump_field("n2: ", n2, func, line);
_dump_field("n3: ", n3, func, line);
_dump_field("n4: ", n4, func, line);
- pr_debug("%s:%d: v1: %016llx\n", func, line, v1);
- pr_debug("%s:%d: v2: %016llx\n", func, line, v2);
+ pr_devel("%s:%d: v1: %016llx\n", func, line, v1);
+ pr_devel("%s:%d: v2: %016llx\n", func, line, v2);
}
/**
@@ -131,11 +131,11 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
lpar_id = id;
}
- result = lv1_get_repository_node_value(lpar_id, n1, n2, n3, n4, &v1,
+ result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1,
&v2);
if (result) {
- pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n",
+ pr_warn("%s:%d: lv1_read_repository_node failed: %s\n",
__func__, __LINE__, ps3_result(result));
dump_node_name(lpar_id, n1, n2, n3, n4);
return -ENOENT;
@@ -149,10 +149,10 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
*_v2 = v2;
if (v1 && !_v1)
- pr_debug("%s:%d: warning: discarding non-zero v1: %016llx\n",
+ pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n",
__func__, __LINE__, v1);
if (v2 && !_v2)
- pr_debug("%s:%d: warning: discarding non-zero v2: %016llx\n",
+ pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n",
__func__, __LINE__, v2);
return 0;
@@ -323,16 +323,16 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)
result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
if (result) {
- pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);
+ pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);
return result;
}
- pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n",
+ pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n",
__func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id,
num_dev);
if (tmp.dev_index >= num_dev) {
- pr_debug("%s:%d: no device found\n", __func__, __LINE__);
+ pr_devel("%s:%d: no device found\n", __func__, __LINE__);
return -ENODEV;
}
@@ -340,7 +340,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)
&tmp.dev_type);
if (result) {
- pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__);
+ pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__);
return result;
}
@@ -348,12 +348,12 @@ int ps3_repository_find_device(struct ps3_repository_device *repo)
&tmp.dev_id);
if (result) {
- pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__,
+ pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__,
__LINE__);
return result;
}
- pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n",
+ pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n",
__func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id);
*repo = tmp;
@@ -367,14 +367,14 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,
struct ps3_repository_device tmp;
unsigned int num_dev;
- pr_debug(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__,
+ pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__,
bus_id, dev_id);
for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) {
result = ps3_repository_read_bus_id(tmp.bus_index,
&tmp.bus_id);
if (result) {
- pr_debug("%s:%u read_bus_id(%u) failed\n", __func__,
+ pr_devel("%s:%u read_bus_id(%u) failed\n", __func__,
__LINE__, tmp.bus_index);
return result;
}
@@ -382,23 +382,23 @@ int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,
if (tmp.bus_id == bus_id)
goto found_bus;
- pr_debug("%s:%u: skip, bus_id %llu\n", __func__, __LINE__,
+ pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__,
tmp.bus_id);
}
- pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__);
+ pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
return result;
found_bus:
result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type);
if (result) {
- pr_debug("%s:%u read_bus_type(%u) failed\n", __func__,
+ pr_devel("%s:%u read_bus_type(%u) failed\n", __func__,
__LINE__, tmp.bus_index);
return result;
}
result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
if (result) {
- pr_debug("%s:%u read_bus_num_dev failed\n", __func__,
+ pr_devel("%s:%u read_bus_num_dev failed\n", __func__,
__LINE__);
return result;
}
@@ -408,7 +408,7 @@ found_bus:
tmp.dev_index,
&tmp.dev_id);
if (result) {
- pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__,
+ pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__,
__LINE__, tmp.bus_index, tmp.dev_index);
return result;
}
@@ -416,21 +416,21 @@ found_bus:
if (tmp.dev_id == dev_id)
goto found_dev;
- pr_debug("%s:%u: skip, dev_id %llu\n", __func__, __LINE__,
+ pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__,
tmp.dev_id);
}
- pr_debug(" <- %s:%u: dev not found\n", __func__, __LINE__);
+ pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__);
return result;
found_dev:
result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
&tmp.dev_type);
if (result) {
- pr_debug("%s:%u read_dev_type failed\n", __func__, __LINE__);
+ pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__);
return result;
}
- pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n",
+ pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n",
__func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index,
tmp.dev_index, tmp.bus_id, tmp.dev_id);
*repo = tmp;
@@ -443,18 +443,18 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,
int result = 0;
struct ps3_repository_device repo;
- pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);
+ pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);
repo.bus_type = bus_type;
result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);
if (result) {
- pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__);
+ pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
return result;
}
result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);
if (result) {
- pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__,
+ pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__,
repo.bus_index);
return result;
}
@@ -469,13 +469,13 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,
result = callback(&repo);
if (result) {
- pr_debug("%s:%d: abort at callback\n", __func__,
+ pr_devel("%s:%d: abort at callback\n", __func__,
__LINE__);
break;
}
}
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -489,7 +489,7 @@ int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
for (i = from; i < 10; i++) {
error = ps3_repository_read_bus_type(i, &type);
if (error) {
- pr_debug("%s:%d read_bus_type failed\n",
+ pr_devel("%s:%d read_bus_type failed\n",
__func__, __LINE__);
*bus_index = UINT_MAX;
return error;
@@ -509,7 +509,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
int result = 0;
unsigned int res_index;
- pr_debug("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);
+ pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);
*interrupt_id = UINT_MAX;
@@ -521,7 +521,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
repo->dev_index, res_index, &t, &id);
if (result) {
- pr_debug("%s:%d read_dev_intr failed\n",
+ pr_devel("%s:%d read_dev_intr failed\n",
__func__, __LINE__);
return result;
}
@@ -535,7 +535,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
if (res_index == 10)
return -ENODEV;
- pr_debug("%s:%d: found intr_type %u at res_index %u\n",
+ pr_devel("%s:%d: found intr_type %u at res_index %u\n",
__func__, __LINE__, intr_type, res_index);
return result;
@@ -547,7 +547,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,
int result = 0;
unsigned int res_index;
- pr_debug("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);
+ pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);
*bus_addr = *len = 0;
@@ -560,7 +560,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,
repo->dev_index, res_index, &t, &a, &l);
if (result) {
- pr_debug("%s:%d read_dev_reg failed\n",
+ pr_devel("%s:%d read_dev_reg failed\n",
__func__, __LINE__);
return result;
}
@@ -575,7 +575,7 @@ int ps3_repository_find_reg(const struct ps3_repository_device *repo,
if (res_index == 10)
return -ENODEV;
- pr_debug("%s:%d: found reg_type %u at res_index %u\n",
+ pr_devel("%s:%d: found reg_type %u at res_index %u\n",
__func__, __LINE__, reg_type, res_index);
return result;
@@ -1009,7 +1009,7 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
int result = 0;
unsigned int res_index;
- pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
for (res_index = 0; res_index < 10; res_index++) {
@@ -1021,13 +1021,13 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
if (result) {
if (result != LV1_NO_ENTRY)
- pr_debug("%s:%d ps3_repository_read_dev_intr"
+ pr_devel("%s:%d ps3_repository_read_dev_intr"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
- pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
+ pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
intr_type, interrupt_id);
}
@@ -1042,18 +1042,18 @@ int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
if (result) {
if (result != LV1_NO_ENTRY)
- pr_debug("%s:%d ps3_repository_read_dev_reg"
+ pr_devel("%s:%d ps3_repository_read_dev_reg"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
- pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n",
+ pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
reg_type, bus_addr, len);
}
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -1063,22 +1063,22 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo)
unsigned int num_regions, region_index;
u64 port, blk_size, num_blocks;
- pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
result = ps3_repository_read_stor_dev_info(repo->bus_index,
repo->dev_index, &port, &blk_size, &num_blocks, &num_regions);
if (result) {
- pr_debug("%s:%d ps3_repository_read_stor_dev_info"
+ pr_devel("%s:%d ps3_repository_read_stor_dev_info"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
goto out;
}
- pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
- "%lu, num_regions %u\n",
- __func__, __LINE__, repo->bus_index, repo->dev_index, port,
- blk_size, num_blocks, num_regions);
+ pr_devel("%s:%d (%u:%u): port %llu, blk_size %llu, num_blocks "
+ "%llu, num_regions %u\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index,
+ port, blk_size, num_blocks, num_regions);
for (region_index = 0; region_index < num_regions; region_index++) {
unsigned int region_id;
@@ -1088,19 +1088,20 @@ static int dump_stor_dev_info(struct ps3_repository_device *repo)
repo->dev_index, region_index, &region_id,
&region_start, &region_size);
if (result) {
- pr_debug("%s:%d ps3_repository_read_stor_dev_region"
+ pr_devel("%s:%d ps3_repository_read_stor_dev_region"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
}
- pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
+ pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
__func__, __LINE__, repo->bus_index, repo->dev_index,
- region_id, region_start, region_size);
+ region_id, (unsigned long)region_start,
+ (unsigned long)region_size);
}
out:
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -1109,7 +1110,7 @@ static int dump_device_info(struct ps3_repository_device *repo,
{
int result = 0;
- pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);
+ pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);
for (repo->dev_index = 0; repo->dev_index < num_dev;
repo->dev_index++) {
@@ -1118,7 +1119,7 @@ static int dump_device_info(struct ps3_repository_device *repo,
repo->dev_index, &repo->dev_type);
if (result) {
- pr_debug("%s:%d ps3_repository_read_dev_type"
+ pr_devel("%s:%d ps3_repository_read_dev_type"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
break;
@@ -1128,15 +1129,15 @@ static int dump_device_info(struct ps3_repository_device *repo,
repo->dev_index, &repo->dev_id);
if (result) {
- pr_debug("%s:%d ps3_repository_read_dev_id"
+ pr_devel("%s:%d ps3_repository_read_dev_id"
" (%u:%u) failed\n", __func__, __LINE__,
repo->bus_index, repo->dev_index);
continue;
}
- pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__,
+ pr_devel("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__,
__LINE__, repo->bus_index, repo->dev_index,
- repo->dev_type, repo->dev_id);
+ repo->dev_type, (unsigned long)repo->dev_id);
ps3_repository_dump_resource_info(repo);
@@ -1144,7 +1145,7 @@ static int dump_device_info(struct ps3_repository_device *repo,
dump_stor_dev_info(repo);
}
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -1153,7 +1154,7 @@ int ps3_repository_dump_bus_info(void)
int result = 0;
struct ps3_repository_device repo;
- pr_debug(" -> %s:%d\n", __func__, __LINE__);
+ pr_devel(" -> %s:%d\n", __func__, __LINE__);
memset(&repo, 0, sizeof(repo));
@@ -1164,7 +1165,7 @@ int ps3_repository_dump_bus_info(void)
&repo.bus_type);
if (result) {
- pr_debug("%s:%d read_bus_type(%u) failed\n",
+ pr_devel("%s:%d read_bus_type(%u) failed\n",
__func__, __LINE__, repo.bus_index);
break;
}
@@ -1173,32 +1174,32 @@ int ps3_repository_dump_bus_info(void)
&repo.bus_id);
if (result) {
- pr_debug("%s:%d read_bus_id(%u) failed\n",
+ pr_devel("%s:%d read_bus_id(%u) failed\n",
__func__, __LINE__, repo.bus_index);
continue;
}
if (repo.bus_index != repo.bus_id)
- pr_debug("%s:%d bus_index != bus_id\n",
+ pr_devel("%s:%d bus_index != bus_id\n",
__func__, __LINE__);
result = ps3_repository_read_bus_num_dev(repo.bus_index,
&num_dev);
if (result) {
- pr_debug("%s:%d read_bus_num_dev(%u) failed\n",
+ pr_devel("%s:%d read_bus_num_dev(%u) failed\n",
__func__, __LINE__, repo.bus_index);
continue;
}
- pr_debug("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n",
+ pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n",
__func__, __LINE__, repo.bus_index, repo.bus_type,
- repo.bus_id, num_dev);
+ (unsigned long)repo.bus_id, num_dev);
dump_device_info(&repo, num_dev);
}
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ pr_devel(" <- %s:%d\n", __func__, __LINE__);
return result;
}
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index e8ec1b2bfff..2d664c5a83b 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -193,10 +193,12 @@ static int ps3_set_dabr(unsigned long dabr)
static void __init ps3_setup_arch(void)
{
+ u64 tmp;
DBG(" -> %s:%d\n", __func__, __LINE__);
- lv1_get_version_info(&ps3_firmware_version.raw);
+ lv1_get_version_info(&ps3_firmware_version.raw, &tmp);
+
printk(KERN_INFO "PS3 firmware version %u.%u.%u\n",
ps3_firmware_version.major, ps3_firmware_version.minor,
ps3_firmware_version.rev);
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index efc1cd8c034..4b35166229f 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -57,7 +57,7 @@ static void ps3_smp_message_pass(int cpu, int msg)
" (%d)\n", __func__, __LINE__, cpu, msg, result);
}
-static int ps3_smp_probe(void)
+static int __init ps3_smp_probe(void)
{
int cpu;
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 451fad1c92a..e17fa1432d8 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -154,7 +154,7 @@ static unsigned long get_vas_id(void)
u64 id;
lv1_get_logical_ppe_id(&id);
- lv1_get_virtual_address_space_id_of_ppe(id, &id);
+ lv1_get_virtual_address_space_id_of_ppe(&id);
return id;
}
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index c81f6bb9c10..ae7b6d41fed 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -120,3 +120,12 @@ config DTL
which are accessible through a debugfs file.
Say N if you are unsure.
+
+config PSERIES_IDLE
+ tristate "Cpuidle driver for pSeries platforms"
+ depends on CPU_IDLE
+ depends on PPC_PSERIES
+ default y
+ help
+ Select this option to enable processor idle state management
+ through cpuidle subsystem.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 3556e402cbf..236db46b407 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
+obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o
ifeq ($(CONFIG_PPC_PSERIES),y)
obj-$(CONFIG_SUSPEND) += suspend.o
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index a76b22844d1..330a57b7c17 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -625,6 +625,8 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
{
static unsigned int oops_count = 0;
static bool panicking = false;
+ static DEFINE_SPINLOCK(lock);
+ unsigned long flags;
size_t text_len;
unsigned int err_type = ERR_TYPE_KERNEL_PANIC_GZ;
int rc = -1;
@@ -655,6 +657,9 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
if (clobbering_unread_rtas_event())
return;
+ if (!spin_trylock_irqsave(&lock, flags))
+ return;
+
if (big_oops_buf) {
text_len = capture_last_msgs(old_msgs, old_len,
new_msgs, new_len, big_oops_buf, big_oops_buf_sz);
@@ -670,4 +675,6 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
(void) nvram_write_os_partition(&oops_log_partition, oops_buf,
(int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count);
+
+ spin_unlock_irqrestore(&lock, flags);
}
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
new file mode 100644
index 00000000000..085fd3f45ad
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -0,0 +1,329 @@
+/*
+ * processor_idle - idle state cpuidle driver.
+ * Adapted from drivers/idle/intel_idle.c and
+ * drivers/acpi/processor_idle.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+
+#include <asm/paca.h>
+#include <asm/reg.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+
+#include "plpar_wrappers.h"
+#include "pseries.h"
+
+struct cpuidle_driver pseries_idle_driver = {
+ .name = "pseries_idle",
+ .owner = THIS_MODULE,
+};
+
+#define MAX_IDLE_STATE_COUNT 2
+
+static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static struct cpuidle_device __percpu *pseries_cpuidle_devices;
+static struct cpuidle_state *cpuidle_state_table;
+
+void update_smt_snooze_delay(int snooze)
+{
+ struct cpuidle_driver *drv = cpuidle_get_driver();
+ if (drv)
+ drv->states[0].target_residency = snooze;
+}
+
+static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before)
+{
+
+ *kt_before = ktime_get_real();
+ *in_purr = mfspr(SPRN_PURR);
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ get_lppaca()->idle = 1;
+}
+
+static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before)
+{
+ get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
+ get_lppaca()->idle = 0;
+
+ return ktime_to_us(ktime_sub(ktime_get_real(), kt_before));
+}
+
+static int snooze_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+ ktime_t kt_before;
+ unsigned long start_snooze;
+ long snooze = drv->states[0].target_residency;
+
+ idle_loop_prolog(&in_purr, &kt_before);
+
+ if (snooze) {
+ start_snooze = get_tb() + snooze * tb_ticks_per_usec;
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ while ((snooze < 0) || (get_tb() < start_snooze)) {
+ if (need_resched() || cpu_is_offline(dev->cpu))
+ goto out;
+ ppc64_runlatch_off();
+ HMT_low();
+ HMT_very_low();
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb();
+ local_irq_disable();
+ }
+
+out:
+ HMT_medium();
+ dev->last_residency =
+ (int)idle_loop_epilog(in_purr, kt_before);
+ return index;
+}
+
+static int dedicated_cede_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+ ktime_t kt_before;
+
+ idle_loop_prolog(&in_purr, &kt_before);
+ get_lppaca()->donate_dedicated_cpu = 1;
+
+ ppc64_runlatch_off();
+ HMT_medium();
+ cede_processor();
+
+ get_lppaca()->donate_dedicated_cpu = 0;
+ dev->last_residency =
+ (int)idle_loop_epilog(in_purr, kt_before);
+ return index;
+}
+
+static int shared_cede_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+ ktime_t kt_before;
+
+ idle_loop_prolog(&in_purr, &kt_before);
+
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ */
+ cede_processor();
+
+ dev->last_residency =
+ (int)idle_loop_epilog(in_purr, kt_before);
+ return index;
+}
+
+/*
+ * States for dedicated partition case.
+ */
+static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+ { /* Snooze */
+ .name = "snooze",
+ .desc = "snooze",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 0,
+ .target_residency = 0,
+ .enter = &snooze_loop },
+ { /* CEDE */
+ .name = "CEDE",
+ .desc = "CEDE",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 1,
+ .target_residency = 10,
+ .enter = &dedicated_cede_loop },
+};
+
+/*
+ * States for shared partition case.
+ */
+static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+ { /* Shared Cede */
+ .name = "Shared Cede",
+ .desc = "Shared Cede",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 0,
+ .target_residency = 0,
+ .enter = &shared_cede_loop },
+};
+
+int pseries_notify_cpuidle_add_cpu(int cpu)
+{
+ struct cpuidle_device *dev =
+ per_cpu_ptr(pseries_cpuidle_devices, cpu);
+ if (dev && cpuidle_get_driver()) {
+ cpuidle_disable_device(dev);
+ cpuidle_enable_device(dev);
+ }
+ return 0;
+}
+
+/*
+ * pseries_cpuidle_driver_init()
+ */
+static int pseries_cpuidle_driver_init(void)
+{
+ int idle_state;
+ struct cpuidle_driver *drv = &pseries_idle_driver;
+
+ drv->state_count = 0;
+
+ for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
+
+ if (idle_state > max_idle_state)
+ break;
+
+ /* is the state not enabled? */
+ if (cpuidle_state_table[idle_state].enter == NULL)
+ continue;
+
+ drv->states[drv->state_count] = /* structure copy */
+ cpuidle_state_table[idle_state];
+
+ if (cpuidle_state_table == dedicated_states)
+ drv->states[drv->state_count].target_residency =
+ __get_cpu_var(smt_snooze_delay);
+
+ drv->state_count += 1;
+ }
+
+ return 0;
+}
+
+/* pseries_idle_devices_uninit(void)
+ * unregister cpuidle devices and de-allocate memory
+ */
+static void pseries_idle_devices_uninit(void)
+{
+ int i;
+ struct cpuidle_device *dev;
+
+ for_each_possible_cpu(i) {
+ dev = per_cpu_ptr(pseries_cpuidle_devices, i);
+ cpuidle_unregister_device(dev);
+ }
+
+ free_percpu(pseries_cpuidle_devices);
+ return;
+}
+
+/* pseries_idle_devices_init()
+ * allocate, initialize and register cpuidle device
+ */
+static int pseries_idle_devices_init(void)
+{
+ int i;
+ struct cpuidle_driver *drv = &pseries_idle_driver;
+ struct cpuidle_device *dev;
+
+ pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+ if (pseries_cpuidle_devices == NULL)
+ return -ENOMEM;
+
+ for_each_possible_cpu(i) {
+ dev = per_cpu_ptr(pseries_cpuidle_devices, i);
+ dev->state_count = drv->state_count;
+ dev->cpu = i;
+ if (cpuidle_register_device(dev)) {
+ printk(KERN_DEBUG \
+ "cpuidle_register_device %d failed!\n", i);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * pseries_idle_probe()
+ * Choose state table for shared versus dedicated partition
+ */
+static int pseries_idle_probe(void)
+{
+
+ if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+ return -ENODEV;
+
+ if (cpuidle_disable != IDLE_NO_OVERRIDE)
+ return -ENODEV;
+
+ if (max_idle_state == 0) {
+ printk(KERN_DEBUG "pseries processor idle disabled.\n");
+ return -EPERM;
+ }
+
+ if (get_lppaca()->shared_proc)
+ cpuidle_state_table = shared_states;
+ else
+ cpuidle_state_table = dedicated_states;
+
+ return 0;
+}
+
+static int __init pseries_processor_idle_init(void)
+{
+ int retval;
+
+ retval = pseries_idle_probe();
+ if (retval)
+ return retval;
+
+ pseries_cpuidle_driver_init();
+ retval = cpuidle_register_driver(&pseries_idle_driver);
+ if (retval) {
+ printk(KERN_DEBUG "Registration of pseries driver failed.\n");
+ return retval;
+ }
+
+ retval = pseries_idle_devices_init();
+ if (retval) {
+ pseries_idle_devices_uninit();
+ cpuidle_unregister_driver(&pseries_idle_driver);
+ return retval;
+ }
+
+ printk(KERN_DEBUG "pseries_idle_driver registered\n");
+
+ return 0;
+}
+
+static void __exit pseries_processor_idle_exit(void)
+{
+
+ pseries_idle_devices_uninit();
+ cpuidle_unregister_driver(&pseries_idle_driver);
+
+ return;
+}
+
+module_init(pseries_processor_idle_init);
+module_exit(pseries_processor_idle_exit);
+
+MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Cpuidle driver for POWER");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 24c7162f11d..9a3dda07566 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -57,4 +57,7 @@ extern struct device_node *dlpar_configure_connector(u32);
extern int dlpar_attach_node(struct device_node *);
extern int dlpar_detach_node(struct device_node *);
+/* Snooze Delay, pseries_idle */
+DECLARE_PER_CPU(long, smt_snooze_delay);
+
#endif /* _PSERIES_PSERIES_H */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 992d797e07d..f79f1278dfc 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -39,6 +39,7 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
+#include <linux/cpuidle.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -74,9 +75,6 @@ EXPORT_SYMBOL(CMO_PageSize);
int fwnmi_active; /* TRUE if an FWNMI handler is present */
-static void pseries_shared_idle_sleep(void);
-static void pseries_dedicated_idle_sleep(void);
-
static struct device_node *pSeries_mpic_node;
static void pSeries_show_cpuinfo(struct seq_file *m)
@@ -351,6 +349,21 @@ static int alloc_dispatch_log_kmem_cache(void)
}
early_initcall(alloc_dispatch_log_kmem_cache);
+static void pSeries_idle(void)
+{
+ /* This would call on the cpuidle framework, and the back-end pseries
+ * driver to go to idle states
+ */
+ if (cpuidle_idle_call()) {
+ /* On error, execute default handler
+ * to go into low thread priority and possibly
+ * low power mode.
+ */
+ HMT_low();
+ HMT_very_low();
+ }
+}
+
static void __init pSeries_setup_arch(void)
{
panic_timeout = 10;
@@ -375,18 +388,9 @@ static void __init pSeries_setup_arch(void)
pSeries_nvram_init();
- /* Choose an idle loop */
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
vpa_init(boot_cpuid);
- if (get_lppaca()->shared_proc) {
- printk(KERN_DEBUG "Using shared processor idle loop\n");
- ppc_md.power_save = pseries_shared_idle_sleep;
- } else {
- printk(KERN_DEBUG "Using dedicated idle loop\n");
- ppc_md.power_save = pseries_dedicated_idle_sleep;
- }
- } else {
- printk(KERN_DEBUG "Using default idle loop\n");
+ ppc_md.power_save = pSeries_idle;
}
if (firmware_has_feature(FW_FEATURE_LPAR))
@@ -587,80 +591,6 @@ static int __init pSeries_probe(void)
return 1;
}
-
-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
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
- get_lppaca()->donate_dedicated_cpu = 1;
- in_purr = mfspr(SPRN_PURR);
-
- /*
- * We come in with interrupts disabled, and need_resched()
- * has been checked recently. If we should poll for a little
- * while, do so.
- */
- if (snooze) {
- start_snooze = get_tb() + snooze * tb_ticks_per_usec;
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while ((snooze < 0) || (get_tb() < start_snooze)) {
- if (need_resched() || cpu_is_offline(cpu))
- goto out;
- ppc64_runlatch_off();
- HMT_low();
- HMT_very_low();
- }
-
- HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb();
- local_irq_disable();
- if (need_resched() || cpu_is_offline(cpu))
- goto out;
- }
-
- cede_processor();
-
-out:
- HMT_medium();
- out_purr = mfspr(SPRN_PURR);
- get_lppaca()->wait_state_cycles += out_purr - in_purr;
- get_lppaca()->donate_dedicated_cpu = 0;
- get_lppaca()->idle = 0;
-}
-
-static void pseries_shared_idle_sleep(void)
-{
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
-
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- */
- cede_processor();
-
- get_lppaca()->idle = 0;
-}
-
static int pSeries_pci_probe_mode(struct pci_bus *bus)
{
if (firmware_has_feature(FW_FEATURE_LPAR))
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 26e93fd4c62..bbc3c42f673 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -148,6 +148,7 @@ static void __devinit smp_xics_setup_cpu(int cpu)
set_cpu_current_state(cpu, CPU_STATE_ONLINE);
set_default_offline_state(cpu);
#endif
+ pseries_notify_cpuidle_add_cpu(cpu);
}
static int __devinit smp_pSeries_kick_cpu(int nr)
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index 7bf1e201578..5ee82a77723 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -640,7 +640,7 @@ static inline void gelic_card_disable_rxdmac(struct gelic_card *card)
int status;
/* this hvc blocks until the DMA in progress really stopped */
- status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0);
+ status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card));
if (status)
dev_err(ctodev(card),
"lv1_net_stop_rx_dma failed, %d\n", status);
@@ -658,7 +658,7 @@ static inline void gelic_card_disable_txdmac(struct gelic_card *card)
int status;
/* this hvc blocks until the DMA in progress really stopped */
- status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0);
+ status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card));
if (status)
dev_err(ctodev(card),
"lv1_net_stop_tx_dma failed, status=%d\n", status);
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 5acd24a27d0..51941f02e93 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
}
}
+static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
+{
+ if (enable) {
+ uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
+ if (!ZS_IS_EXTCLK(uap))
+ uap->curregs[1] |= EXT_INT_ENAB;
+ } else {
+ uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+ }
+ write_zsreg(uap, R1, uap->curregs[1]);
+}
+
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_struct *tty = NULL;
@@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
return tty;
flood:
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
- zssync(uap);
+ pmz_interrupt_control(uap, 0);
pmz_error("pmz: rx irq flood !\n");
return tty;
}
@@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port *port)
if (ZS_IS_IRDA(uap))
pmz_irda_reset(uap);
- /* Enable interrupts emission from the chip */
+ /* Enable interrupt requests for the channel */
spin_lock_irqsave(&port->lock, flags);
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
+ pmz_interrupt_control(uap, 1);
spin_unlock_irqrestore(&port->lock, flags);
pmz_debug("pmz: startup() done.\n");
@@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_port *port)
mutex_lock(&pmz_irq_mutex);
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (!ZS_IS_ASLEEP(uap)) {
+ /* Disable interrupt requests for the channel */
+ pmz_interrupt_control(uap, 0);
+
+ if (!ZS_IS_CONS(uap)) {
+ /* Disable receiver and transmitter */
+ uap->curregs[R3] &= ~RxENABLE;
+ uap->curregs[R5] &= ~TxENABLE;
+
+ /* Disable break assertion */
+ uap->curregs[R5] &= ~SND_BRK;
+ pmz_maybe_update_regs(uap);
+ }
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
/* Release interrupt handler */
free_irq(uap->port.irq, uap);
@@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_port *port)
if (!ZS_IS_OPEN(uap->mate))
pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
- /* Disable interrupts */
- if (!ZS_IS_ASLEEP(uap)) {
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
- zssync(uap);
- }
-
- if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
- spin_unlock_irqrestore(&port->lock, flags);
- mutex_unlock(&pmz_irq_mutex);
- return;
- }
-
- /* Disable receiver and transmitter. */
- uap->curregs[R3] &= ~RxENABLE;
- uap->curregs[R5] &= ~TxENABLE;
-
- /* Disable all interrupts and BRK assertion. */
- uap->curregs[R5] &= ~SND_BRK;
- pmz_maybe_update_regs(uap);
-
- /* Shut the chip down */
- pmz_set_scc_power(uap, 0);
+ if (!ZS_IS_ASLEEP(uap) && !ZS_IS_CONS(uap))
+ pmz_set_scc_power(uap, 0); /* Shut the chip down */
spin_unlock_irqrestore(&port->lock, flags);
@@ -1352,19 +1357,15 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
spin_lock_irqsave(&port->lock, flags);
/* Disable IRQs on the port */
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
+ pmz_interrupt_control(uap, 0);
/* Setup new port configuration */
__pmz_set_termios(port, termios, old);
/* Re-enable IRQs on the port */
- if (ZS_IS_OPEN(uap)) {
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
- }
+ if (ZS_IS_OPEN(uap))
+ pmz_interrupt_control(uap, 1);
+
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1671,14 +1672,17 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
spin_lock_irqsave(&uap->port.lock, flags);
if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
- /* Disable receiver and transmitter. */
+ /* Disable interrupt requests for the channel */
+ pmz_interrupt_control(uap, 0);
+
+ /* Disable receiver and transmitter */
uap->curregs[R3] &= ~RxENABLE;
uap->curregs[R5] &= ~TxENABLE;
- /* Disable all interrupts and BRK assertion. */
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+ /* Disable break assertion */
uap->curregs[R5] &= ~SND_BRK;
pmz_load_zsregs(uap, uap->curregs);
+
uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
mb();
}
@@ -1738,14 +1742,6 @@ static int pmz_resume(struct macio_dev *mdev)
/* Take care of config that may have changed while asleep */
__pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
- if (ZS_IS_OPEN(uap)) {
- /* Enable interrupts */
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
- }
-
spin_unlock_irqrestore(&uap->port.lock, flags);
if (ZS_IS_CONS(uap))
@@ -1757,6 +1753,12 @@ static int pmz_resume(struct macio_dev *mdev)
enable_irq(uap->port.irq);
}
+ if (ZS_IS_OPEN(uap)) {
+ spin_lock_irqsave(&uap->port.lock, flags);
+ pmz_interrupt_control(uap, 1);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+ }
+
bail:
mutex_unlock(&state->port.mutex);
mutex_unlock(&pmz_irq_mutex);
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 7408af843b8..23f81de5182 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -130,7 +130,6 @@ struct cpuidle_driver {
#ifdef CONFIG_CPU_IDLE
extern void disable_cpuidle(void);
extern int cpuidle_idle_call(void);
-
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
struct cpuidle_driver *cpuidle_get_driver(void);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
@@ -145,7 +144,6 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
#else
static inline void disable_cpuidle(void) { }
static inline int cpuidle_idle_call(void) { return -ENODEV; }
-
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }