summaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig4
-rw-r--r--arch/powerpc/boot/dts/mpc832x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc832x_rdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitxgp.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc834x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc836x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc836x_rdk.dts16
-rw-r--r--arch/powerpc/boot/dts/mpc8377_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8378_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8379_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8536ds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8540ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8541cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8544ds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8555cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8568mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8572ds.dts1
-rw-r--r--arch/powerpc/kernel/entry_32.S17
-rw-r--r--arch/powerpc/kernel/entry_64.S10
-rw-r--r--arch/powerpc/kernel/legacy_serial.c44
-rw-r--r--arch/powerpc/kernel/lparcfg.c4
-rw-r--r--arch/powerpc/kernel/process.c8
-rw-r--r--arch/powerpc/kernel/prom_init.c39
-rw-r--r--arch/powerpc/kernel/ptrace.c64
-rw-r--r--arch/powerpc/kernel/ptrace32.c2
-rw-r--r--arch/powerpc/kernel/setup-common.c24
-rw-r--r--arch/powerpc/kernel/setup_64.c3
-rw-r--r--arch/powerpc/kernel/signal.c23
-rw-r--r--arch/powerpc/kernel/smp.c119
-rw-r--r--arch/powerpc/kernel/stacktrace.c1
-rw-r--r--arch/powerpc/kernel/sysfs.c311
-rw-r--r--arch/powerpc/kernel/vio.c6
-rw-r--r--arch/powerpc/mm/Makefile3
-rw-r--r--arch/powerpc/mm/gup.c280
-rw-r--r--arch/powerpc/mm/hugetlbpage.c9
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c1
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c1
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c1
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_mds.c1
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c1
-rw-r--r--arch/powerpc/platforms/83xx/sbc834x.c1
-rw-r--r--arch/powerpc/platforms/85xx/ksi8560.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8536_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c1
-rw-r--r--arch/powerpc/platforms/85xx/sbc8560.c1
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig10
-rw-r--r--arch/powerpc/platforms/Kconfig3
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c6
-rw-r--r--arch/powerpc/platforms/powermac/setup.c72
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c12
-rw-r--r--arch/powerpc/platforms/pseries/cmm.c8
-rw-r--r--arch/powerpc/sysdev/cpm1.c267
-rw-r--r--arch/powerpc/sysdev/cpm2.c45
-rw-r--r--arch/powerpc/sysdev/cpm_common.c123
-rw-r--r--arch/powerpc/sysdev/rtc_cmos_setup.c23
60 files changed, 1378 insertions, 208 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index fe88418167c5..63c9cafda9c4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -42,6 +42,9 @@ config GENERIC_HARDIRQS
bool
default y
+config HAVE_GET_USER_PAGES_FAST
+ def_bool PPC64
+
config HAVE_SETUP_PER_CPU_AREA
def_bool PPC64
@@ -117,6 +120,7 @@ config PPC
select HAVE_KPROBES
select HAVE_ARCH_KGDB
select HAVE_KRETPROBES
+ select HAVE_ARCH_TRACEHOOK
select HAVE_LMB
select HAVE_DMA_ATTRS if PPC64
select USE_GENERIC_SMP_HELPERS if SMP
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 7345743d3d96..fbc930410ff6 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -68,6 +68,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <132000000>;
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index e74c045a0f8c..b157d1885a28 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -51,6 +51,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 8dfab5662585..700e076ef3f5 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -52,6 +52,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; // from bootloader
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index 49ca3497eefb..cdd3063258ea 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -50,6 +50,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; // from bootloader
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index ba586cb7afbb..783241c00240 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -57,6 +57,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 3701dae1ee02..a3b76a709951 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -61,6 +61,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <264000000>;
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
index 8acd1d6577f2..89c9202f8bd7 100644
--- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
+++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
@@ -149,18 +149,14 @@
};
crypto@30000 {
- compatible = "fsl,sec2-crypto";
+ compatible = "fsl,sec2.0";
reg = <0x30000 0x10000>;
- interrupts = <11 8>;
+ interrupts = <11 0x8>;
interrupt-parent = <&ipic>;
- num-channels = <4>;
- channel-fifo-len = <24>;
- exec-units-mask = <0x7e>;
- /*
- * desc mask is for rev1.x, we need runtime fixup
- * for >=2.x
- */
- descriptor-types-mask = <0x1010ebf>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0x7e>;
+ fsl,descriptor-types-mask = <0x01010ebf>;
};
ipic: interrupt-controller@700 {
diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts
index 0a700cb5f611..432782b6d20a 100644
--- a/arch/powerpc/boot/dts/mpc8377_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8377_mds.dts
@@ -117,6 +117,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts
index 29c8c76a58f7..ed32c8ddafe3 100644
--- a/arch/powerpc/boot/dts/mpc8378_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8378_mds.dts
@@ -117,6 +117,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts
index d641a8985ea3..f4db9ed4a301 100644
--- a/arch/powerpc/boot/dts/mpc8379_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8379_mds.dts
@@ -117,6 +117,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 02cfa24a1695..1505d6855eff 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -49,6 +49,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xffe00000 0x100000>;
reg = <0xffe00000 0x1000>;
bus-frequency = <0>; // Filled out by uboot.
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index f2273a872b11..9568bfaff8f7 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -53,6 +53,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x100000>; // CCSRBAR 1M
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index c4469f19ff82..6480f4fd96e0 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -53,6 +53,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
index 7d3829d3495e..f1fb20737e3e 100644
--- a/arch/powerpc/boot/dts/mpc8544ds.dts
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -54,6 +54,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index d84466bb7eca..431b496270dc 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -58,6 +58,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index e03a78006283..d833a5c4f476 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -53,6 +53,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index ba8159de040b..4d1f2f284094 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -53,6 +53,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x200>;
bus-frequency = <330000000>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index 9c30a34821dc..a15f10343f53 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -60,6 +60,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts
index 08c61e3daecc..e124dd18fb5a 100644
--- a/arch/powerpc/boot/dts/mpc8572ds.dts
+++ b/arch/powerpc/boot/dts/mpc8572ds.dts
@@ -68,6 +68,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
+ compatible = "simple-bus";
ranges = <0x0 0xffe00000 0x100000>;
reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed
bus-frequency = <0>; // Filled out by uboot.
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 81c8324a4a3c..1cbbf7033641 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -148,7 +148,7 @@ transfer_to_handler:
/* Check to see if the dbcr0 register is set up to debug. Use the
internal debug mode bit to do this. */
lwz r12,THREAD_DBCR0(r12)
- andis. r12,r12,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
+ andis. r12,r12,DBCR0_IDM@h
beq+ 3f
/* From user and task is ptraced - load up global dbcr0 */
li r12,-1 /* clear all pending debug events */
@@ -292,7 +292,7 @@ syscall_exit_cont:
/* If the process has its own DBCR0 value, load it up. The internal
debug mode bit tells us that dbcr0 should be loaded. */
lwz r0,THREAD+THREAD_DBCR0(r2)
- andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
+ andis. r10,r0,DBCR0_IDM@h
bnel- load_dbcr0
#endif
#ifdef CONFIG_44x
@@ -343,7 +343,12 @@ syscall_dotrace:
stw r0,_TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
bl do_syscall_trace_enter
- lwz r0,GPR0(r1) /* Restore original registers */
+ /*
+ * Restore argument registers possibly just changed.
+ * We use the return value of do_syscall_trace_enter
+ * for call number to look up in the table (r0).
+ */
+ mr r0,r3
lwz r3,GPR3(r1)
lwz r4,GPR4(r1)
lwz r5,GPR5(r1)
@@ -720,7 +725,7 @@ restore_user:
/* Check whether this process has its own DBCR0 value. The internal
debug mode bit tells us that dbcr0 should be loaded. */
lwz r0,THREAD+THREAD_DBCR0(r2)
- andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
+ andis. r10,r0,DBCR0_IDM@h
bnel- load_dbcr0
#endif
@@ -1055,8 +1060,8 @@ do_user_signal: /* r10 contains MSR_KERNEL here */
SAVE_NVGPRS(r1)
rlwinm r3,r3,0,0,30
stw r3,_TRAP(r1)
-2: li r3,0
- addi r4,r1,STACK_FRAME_OVERHEAD
+2: addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r9
bl do_signal
REST_NVGPRS(r1)
b recheck
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index d7369243ae44..2d802e97097c 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -214,7 +214,12 @@ syscall_dotrace:
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_syscall_trace_enter
- ld r0,GPR0(r1) /* Restore original registers */
+ /*
+ * Restore argument registers possibly just changed.
+ * We use the return value of do_syscall_trace_enter
+ * for the call number to look up in the table (r0).
+ */
+ mr r0,r3
ld r3,GPR3(r1)
ld r4,GPR4(r1)
ld r5,GPR5(r1)
@@ -638,8 +643,7 @@ user_work:
b .ret_from_except_lite
1: bl .save_nvgprs
- li r3,0
- addi r4,r1,STACK_FRAME_OVERHEAD
+ addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_signal
b .ret_from_except
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 4d96e1db55ee..9ddfaef1a184 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -493,18 +493,18 @@ static int __init serial_dev_init(void)
device_initcall(serial_dev_init);
+#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* This is called very early, as part of console_init() (typically just after
* time_init()). This function is respondible for trying to find a good
* default console on serial ports. It tries to match the open firmware
- * default output with one of the available serial console drivers, either
- * one of the platform serial ports that have been probed earlier by
- * find_legacy_serial_ports() or some more platform specific ones.
+ * default output with one of the available serial console drivers that have
+ * been probed earlier by find_legacy_serial_ports()
*/
static int __init check_legacy_serial_console(void)
{
struct device_node *prom_stdout = NULL;
- int speed = 0, offset = 0;
+ int i, speed = 0, offset = 0;
const char *name;
const u32 *spd;
@@ -548,31 +548,20 @@ static int __init check_legacy_serial_console(void)
if (spd)
speed = *spd;
- if (0)
- ;
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- else if (strcmp(name, "serial") == 0) {
- int i;
- /* Look for it in probed array */
- for (i = 0; i < legacy_serial_count; i++) {
- if (prom_stdout != legacy_serial_infos[i].np)
- continue;
- offset = i;
- speed = legacy_serial_infos[i].speed;
- break;
- }
- if (i >= legacy_serial_count)
- goto not_found;
+ if (strcmp(name, "serial") != 0)
+ goto not_found;
+
+ /* Look for it in probed array */
+ for (i = 0; i < legacy_serial_count; i++) {
+ if (prom_stdout != legacy_serial_infos[i].np)
+ continue;
+ offset = i;
+ speed = legacy_serial_infos[i].speed;
+ break;
}
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
- else if (strcmp(name, "ch-a") == 0)
- offset = 0;
- else if (strcmp(name, "ch-b") == 0)
- offset = 1;
-#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
- else
+ if (i >= legacy_serial_count)
goto not_found;
+
of_node_put(prom_stdout);
DBG("Found serial console at ttyS%d\n", offset);
@@ -591,3 +580,4 @@ static int __init check_legacy_serial_console(void)
}
console_initcall(check_legacy_serial_console);
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 9f856a0c3e38..1a09719c7628 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
retval = -EIO;
} else if (retval == H_PARAMETER) {
retval = -EINVAL;
- } else {
- printk(KERN_WARNING "%s: received unknown hv return code %ld",
- __func__, retval);
- retval = -EIO;
}
return retval;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index db2497ccc111..e030f3bd5024 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -254,7 +254,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
return;
/* Clear the DAC and struct entries. One shot trigger */
-#if (defined(CONFIG_44x) || defined(CONFIG_BOOKE))
+#if defined(CONFIG_BOOKE)
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W
| DBCR0_IDM));
#endif
@@ -286,7 +286,7 @@ int set_dabr(unsigned long dabr)
mtspr(SPRN_DABR, dabr);
#endif
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
mtspr(SPRN_DAC1, dabr);
#endif
@@ -373,7 +373,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
set_dabr(new->thread.dabr);
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
/* If new thread DAC (HW breakpoint) is the same then leave it */
if (new->thread.dabr)
set_dabr(new->thread.dabr);
@@ -568,7 +568,7 @@ void flush_thread(void)
current->thread.dabr = 0;
set_dabr(0);
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W);
#endif
}
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index c4ab2195b9cb..b72849ac7db3 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -205,8 +205,6 @@ static int __initdata mem_reserve_cnt;
static cell_t __initdata regbuf[1024];
-#define MAX_CPU_THREADS 2
-
/*
* Error results ... some OF calls will return "-1" on error, some
* will return 0, some will return either. To simplify, here are
@@ -1339,10 +1337,6 @@ static void __init prom_hold_cpus(void)
unsigned int reg;
phandle node;
char type[64];
- int cpuid = 0;
- unsigned int interrupt_server[MAX_CPU_THREADS];
- unsigned int cpu_threads, hw_cpu_num;
- int propsize;
struct prom_t *_prom = &RELOC(prom);
unsigned long *spinloop
= (void *) LOW_ADDR(__secondary_hold_spinloop);
@@ -1386,7 +1380,6 @@ static void __init prom_hold_cpus(void)
reg = -1;
prom_getprop(node, "reg", &reg, sizeof(reg));
- prom_debug("\ncpuid = 0x%x\n", cpuid);
prom_debug("cpu hw idx = 0x%x\n", reg);
/* Init the acknowledge var which will be reset by
@@ -1395,28 +1388,9 @@ static void __init prom_hold_cpus(void)
*/
*acknowledge = (unsigned long)-1;
- propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s",
- &interrupt_server,
- sizeof(interrupt_server));
- if (propsize < 0) {
- /* no property. old hardware has no SMT */
- cpu_threads = 1;
- interrupt_server[0] = reg; /* fake it with phys id */
- } else {
- /* We have a threaded processor */
- cpu_threads = propsize / sizeof(u32);
- if (cpu_threads > MAX_CPU_THREADS) {
- prom_printf("SMT: too many threads!\n"
- "SMT: found %x, max is %x\n",
- cpu_threads, MAX_CPU_THREADS);
- cpu_threads = 1; /* ToDo: panic? */
- }
- }
-
- hw_cpu_num = interrupt_server[0];
- if (hw_cpu_num != _prom->cpu) {
+ if (reg != _prom->cpu) {
/* Primary Thread of non-boot cpu */
- prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
+ prom_printf("starting cpu hw idx %x... ", reg);
call_prom("start-cpu", 3, 0, node,
secondary_hold, reg);
@@ -1431,17 +1405,10 @@ static void __init prom_hold_cpus(void)
}
#ifdef CONFIG_SMP
else
- prom_printf("%x : boot cpu %x\n", cpuid, reg);
+ prom_printf("boot cpu hw idx %x\n", reg);
#endif /* CONFIG_SMP */
-
- /* Reserve cpu #s for secondary threads. They start later. */
- cpuid += cpu_threads;
}
- if (cpuid > NR_CPUS)
- prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS)
- ") exceeded: ignoring extras\n");
-
prom_debug("prom_hold_cpus: end...\n");
}
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index a5d0e78779c8..3635be61f899 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/regset.h>
+#include <linux/tracehook.h>
#include <linux/elf.h>
#include <linux/user.h>
#include <linux/security.h>
@@ -374,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
flush_vsx_to_thread(target);
for (i = 0; i < 32 ; i++)
- buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET];
+ buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET];
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
@@ -393,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset,
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
for (i = 0; i < 32 ; i++)
- current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+ target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return ret;
@@ -717,7 +718,7 @@ void user_disable_single_step(struct task_struct *task)
struct pt_regs *regs = task->thread.regs;
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
/* If DAC then do not single step, skip */
if (task->thread.dabr)
return;
@@ -744,10 +745,11 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
if (addr > 0)
return -EINVAL;
+ /* The bottom 3 bits in dabr are flags */
if ((data & ~0x7UL) >= TASK_SIZE)
return -EIO;
-#ifdef CONFIG_PPC64
+#ifndef CONFIG_BOOKE
/* For processors using DABR (i.e. 970), the bottom 3 bits are flags.
* It was assumed, on previous implementations, that 3 bits were
@@ -769,7 +771,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
task->thread.dabr = data;
#endif
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
/* As described above, it was assumed 3 bits were passed with the data
* address, but we will assume only the mode bits will be passed
@@ -973,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_GETVSRREGS:
return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_VSX,
- 0, (32 * sizeof(vector128) +
- sizeof(u32)),
+ 0, 32 * sizeof(double),
(void __user *) data);
case PTRACE_SETVSRREGS:
return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_VSX,
- 0, (32 * sizeof(vector128) +
- sizeof(u32)),
+ 0, 32 * sizeof(double),
(const void __user *) data);
#endif
#ifdef CONFIG_SPE
@@ -1013,31 +1013,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-static void do_syscall_trace(void)
+/*
+ * We must return the syscall number to actually look up in the table.
+ * This can be -1L to skip running any syscall at all.
+ */
+long do_syscall_trace_enter(struct pt_regs *regs)
{
- /* the 0x80 provides a way for the tracing parent to distinguish
- between a syscall stop and SIGTRAP delivery */
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
-
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
-}
+ long ret = 0;
-void do_syscall_trace_enter(struct pt_regs *regs)
-{
secure_computing(regs->gpr[0]);
- if (test_thread_flag(TIF_SYSCALL_TRACE)
- && (current->ptrace & PT_PTRACED))
- do_syscall_trace();
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ tracehook_report_syscall_entry(regs))
+ /*
+ * Tracing decided this syscall should not happen.
+ * We'll return a bogus call number to get an ENOSYS
+ * error, but leave the original number in regs->gpr[0].
+ */
+ ret = -1L;
if (unlikely(current->audit_context)) {
#ifdef CONFIG_PPC64
@@ -1055,16 +1048,19 @@ void do_syscall_trace_enter(struct pt_regs *regs)
regs->gpr[5] & 0xffffffff,
regs->gpr[6] & 0xffffffff);
}
+
+ return ret ?: regs->gpr[0];
}
void do_syscall_trace_leave(struct pt_regs *regs)
{
+ int step;
+
if (unlikely(current->audit_context))
audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
regs->result);
- if ((test_thread_flag(TIF_SYSCALL_TRACE)
- || test_thread_flag(TIF_SINGLESTEP))
- && (current->ptrace & PT_PTRACED))
- do_syscall_trace();
+ step = test_thread_flag(TIF_SINGLESTEP);
+ if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, step);
}
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 67bf1a1e7e14..197d49c790ad 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
case PTRACE_SETFPREGS:
case PTRACE_GETVRREGS:
case PTRACE_SETVRREGS:
+ case PTRACE_GETVSRREGS:
+ case PTRACE_SETVSRREGS:
case PTRACE_GETREGS64:
case PTRACE_SETREGS64:
case PPC_PTRACE_GETFPREGS:
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 61a3f4132087..9cc5a52711e5 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -367,7 +367,6 @@ 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_sibling_map
*
* Having the possible map set up early allows us to restrict allocations
* of things like irqstacks to num_possible_cpus() rather than NR_CPUS.
@@ -475,29 +474,6 @@ void __init smp_setup_cpu_maps(void)
*/
cpu_init_thread_core_maps(nthreads);
}
-
-/*
- * Being that cpu_sibling_map is now a per_cpu array, then it cannot
- * be initialized until the per_cpu areas have been created. This
- * function is now called from setup_per_cpu_areas().
- */
-void __init smp_setup_cpu_sibling_map(void)
-{
-#ifdef CONFIG_PPC64
- int i, cpu, base;
-
- for_each_possible_cpu(cpu) {
- DBG("Sibling map for CPU %d:", cpu);
- base = cpu_first_thread_in_core(cpu);
- for (i = 0; i < threads_per_core; i++) {
- cpu_set(base + i, per_cpu(cpu_sibling_map, cpu));
- DBG(" %d", base + i);
- }
- DBG("\n");
- }
-
-#endif /* CONFIG_PPC64 */
-}
#endif /* CONFIG_SMP */
#ifdef CONFIG_PCSPKR_PLATFORM
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 04d8de9f0fc6..8b25f51f03bf 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -611,9 +611,6 @@ void __init setup_per_cpu_areas(void)
paca[i].data_offset = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
}
-
- /* Now that per_cpu is setup, initialize cpu_sibling_map */
- smp_setup_cpu_sibling_map();
}
#endif
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 7aada783ec6a..a54405ebd7b0 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -9,7 +9,7 @@
* this archive for more details.
*/
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
#include <linux/signal.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -112,7 +112,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
}
}
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
int signr;
@@ -147,7 +147,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
*/
if (current->thread.dabr) {
set_dabr(current->thread.dabr);
-#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
+#if defined(CONFIG_BOOKE)
mtspr(SPRN_DBCR0, current->thread.dbcr0);
#endif
}
@@ -177,11 +177,28 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
* its frame, and we can clear the TLF_RESTORE_SIGMASK flag.
*/
current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK;
+
+ /*
+ * Let tracing know that we've done the handler setup.
+ */
+ tracehook_signal_handler(signr, &info, &ka, regs,
+ test_thread_flag(TIF_SINGLESTEP));
}
return ret;
}
+void do_signal(struct pt_regs *regs, unsigned long thread_info_flags)
+{
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal_pending(NULL, regs);
+
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ }
+}
+
long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
unsigned long r5, unsigned long r6, unsigned long r7,
unsigned long r8, struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index f5ae9fa222ea..5337ca7bb649 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -41,6 +41,7 @@
#include <asm/smp.h>
#include <asm/time.h>
#include <asm/machdep.h>
+#include <asm/cputhreads.h>
#include <asm/cputable.h>
#include <asm/system.h>
#include <asm/mpic.h>
@@ -62,10 +63,12 @@ struct thread_info *secondary_ti;
cpumask_t cpu_possible_map = CPU_MASK_NONE;
cpumask_t cpu_online_map = CPU_MASK_NONE;
DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
+DEFINE_PER_CPU(cpumask_t, cpu_core_map) = CPU_MASK_NONE;
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
+EXPORT_PER_CPU_SYMBOL(cpu_core_map);
/* SMP operations for this machine */
struct smp_ops_t *smp_ops;
@@ -228,6 +231,8 @@ void __devinit smp_prepare_boot_cpu(void)
BUG_ON(smp_processor_id() != boot_cpuid);
cpu_set(boot_cpuid, cpu_online_map);
+ 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
@@ -375,11 +380,60 @@ int __cpuinit __cpu_up(unsigned int cpu)
return 0;
}
+/* Return the value of the reg property corresponding to the given
+ * logical cpu.
+ */
+int cpu_to_core_id(int cpu)
+{
+ struct device_node *np;
+ const int *reg;
+ int id = -1;
+
+ np = of_get_cpu_node(cpu, NULL);
+ if (!np)
+ goto out;
+
+ reg = of_get_property(np, "reg", NULL);
+ if (!reg)
+ goto out;
+
+ id = *reg;
+out:
+ of_node_put(np);
+ return id;
+}
+
+/* Must be called when no change can occur to cpu_present_map,
+ * i.e. during cpu online or offline.
+ */
+static struct device_node *cpu_to_l2cache(int cpu)
+{
+ struct device_node *np;
+ const phandle *php;
+ phandle ph;
+
+ if (!cpu_present(cpu))
+ return NULL;
+
+ np = of_get_cpu_node(cpu, NULL);
+ if (np == NULL)
+ return NULL;
+
+ php = of_get_property(np, "l2-cache", NULL);
+ if (php == NULL)
+ return NULL;
+ ph = *php;
+ of_node_put(np);
+
+ return of_find_node_by_phandle(ph);
+}
/* Activate a secondary processor. */
int __devinit start_secondary(void *unused)
{
unsigned int cpu = smp_processor_id();
+ struct device_node *l2_cache;
+ int i, base;
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
@@ -400,6 +454,33 @@ int __devinit start_secondary(void *unused)
ipi_call_lock();
cpu_set(cpu, cpu_online_map);
+ /* Update sibling maps */
+ base = cpu_first_thread_in_core(cpu);
+ 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));
+
+ /* 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));
+ }
+ l2_cache = cpu_to_l2cache(cpu);
+ for_each_online_cpu(i) {
+ struct device_node *np = cpu_to_l2cache(i);
+ 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));
+ }
+ of_node_put(np);
+ }
+ of_node_put(l2_cache);
ipi_call_unlock();
local_irq_enable();
@@ -437,10 +518,42 @@ void __init smp_cpus_done(unsigned int max_cpus)
#ifdef CONFIG_HOTPLUG_CPU
int __cpu_disable(void)
{
- if (smp_ops->cpu_disable)
- return smp_ops->cpu_disable();
+ struct device_node *l2_cache;
+ int cpu = smp_processor_id();
+ int base, i;
+ int err;
- return -ENOSYS;
+ if (!smp_ops->cpu_disable)
+ return -ENOSYS;
+
+ err = smp_ops->cpu_disable();
+ if (err)
+ return err;
+
+ /* 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));
+ }
+
+ l2_cache = cpu_to_l2cache(cpu);
+ for_each_present_cpu(i) {
+ struct device_node *np = cpu_to_l2cache(i);
+ 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));
+ }
+ of_node_put(np);
+ }
+ of_node_put(l2_cache);
+
+
+ return 0;
}
void __cpu_die(unsigned int cpu)
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c
index f2589645870a..b0dbb1daa4df 100644
--- a/arch/powerpc/kernel/stacktrace.c
+++ b/arch/powerpc/kernel/stacktrace.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/stacktrace.h>
-#include <linux/module.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 800e5e9a087b..56d172d16e56 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -22,6 +22,8 @@
static DEFINE_PER_CPU(struct cpu, cpu_devices);
+static DEFINE_PER_CPU(struct kobject *, cache_toplevel);
+
/* SMT stuff */
#ifdef CONFIG_PPC_MULTIPLATFORM
@@ -297,8 +299,289 @@ static struct sysdev_attribute pa6t_attrs[] = {
#endif /* CONFIG_DEBUG_KERNEL */
};
+struct cache_desc {
+ struct kobject kobj;
+ struct cache_desc *next;
+ const char *type; /* Instruction, Data, or Unified */
+ u32 size; /* total cache size in KB */
+ u32 line_size; /* in bytes */
+ u32 nr_sets; /* number of sets */
+ u32 level; /* e.g. 1, 2, 3... */
+ u32 associativity; /* e.g. 8-way... 0 is fully associative */
+};
+
+DEFINE_PER_CPU(struct cache_desc *, cache_desc);
+
+static struct cache_desc *kobj_to_cache_desc(struct kobject *k)
+{
+ return container_of(k, struct cache_desc, kobj);
+}
+
+static void cache_desc_release(struct kobject *k)
+{
+ struct cache_desc *desc = kobj_to_cache_desc(k);
+
+ pr_debug("%s: releasing %s\n", __func__, kobject_name(k));
+
+ if (desc->next)
+ kobject_put(&desc->next->kobj);
+
+ kfree(kobj_to_cache_desc(k));
+}
+
+static ssize_t cache_desc_show(struct kobject *k, struct attribute *attr, char *buf)
+{
+ struct kobj_attribute *kobj_attr;
+
+ kobj_attr = container_of(attr, struct kobj_attribute, attr);
+
+ return kobj_attr->show(k, kobj_attr, buf);
+}
+
+static struct sysfs_ops cache_desc_sysfs_ops = {
+ .show = cache_desc_show,
+};
+
+static struct kobj_type cache_desc_type = {
+ .release = cache_desc_release,
+ .sysfs_ops = &cache_desc_sysfs_ops,
+};
+
+static ssize_t cache_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%uK\n", cache->size);
+}
+
+static struct kobj_attribute cache_size_attr =
+ __ATTR(size, 0444, cache_size_show, NULL);
+
+static ssize_t cache_line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%u\n", cache->line_size);
+}
+
+static struct kobj_attribute cache_line_size_attr =
+ __ATTR(coherency_line_size, 0444, cache_line_size_show, NULL);
+
+static ssize_t cache_nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%u\n", cache->nr_sets);
+}
+
+static struct kobj_attribute cache_nr_sets_attr =
+ __ATTR(number_of_sets, 0444, cache_nr_sets_show, NULL);
+
+static ssize_t cache_type_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%s\n", cache->type);
+}
+
+static struct kobj_attribute cache_type_attr =
+ __ATTR(type, 0444, cache_type_show, NULL);
+
+static ssize_t cache_level_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%u\n", cache->level);
+}
+
+static struct kobj_attribute cache_level_attr =
+ __ATTR(level, 0444, cache_level_show, NULL);
+
+static ssize_t cache_assoc_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
+{
+ struct cache_desc *cache = kobj_to_cache_desc(k);
+
+ return sprintf(buf, "%u\n", cache->associativity);
+}
+
+static struct kobj_attribute cache_assoc_attr =
+ __ATTR(ways_of_associativity, 0444, cache_assoc_show, NULL);
+
+struct cache_desc_info {
+ const char *type;
+ const char *size_prop;
+ const char *line_size_prop;
+ const char *nr_sets_prop;
+};
+
+/* PowerPC Processor binding says the [di]-cache-* must be equal on
+ * unified caches, so just use d-cache properties. */
+static struct cache_desc_info ucache_info = {
+ .type = "Unified",
+ .size_prop = "d-cache-size",
+ .line_size_prop = "d-cache-line-size",
+ .nr_sets_prop = "d-cache-sets",
+};
-static void register_cpu_online(unsigned int cpu)
+static struct cache_desc_info dcache_info = {
+ .type = "Data",
+ .size_prop = "d-cache-size",
+ .line_size_prop = "d-cache-line-size",
+ .nr_sets_prop = "d-cache-sets",
+};
+
+static struct cache_desc_info icache_info = {
+ .type = "Instruction",
+ .size_prop = "i-cache-size",
+ .line_size_prop = "i-cache-line-size",
+ .nr_sets_prop = "i-cache-sets",
+};
+
+static struct cache_desc * __cpuinit create_cache_desc(struct device_node *np, struct kobject *parent, int index, int level, struct cache_desc_info *info)
+{
+ const u32 *cache_line_size;
+ struct cache_desc *new;
+ const u32 *cache_size;
+ const u32 *nr_sets;
+ int rc;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ rc = kobject_init_and_add(&new->kobj, &cache_desc_type, parent,
+ "index%d", index);
+ if (rc)
+ goto err;
+
+ /* type */
+ new->type = info->type;
+ rc = sysfs_create_file(&new->kobj, &cache_type_attr.attr);
+ WARN_ON(rc);
+
+ /* level */
+ new->level = level;
+ rc = sysfs_create_file(&new->kobj, &cache_level_attr.attr);
+ WARN_ON(rc);
+
+ /* size */
+ cache_size = of_get_property(np, info->size_prop, NULL);
+ if (cache_size) {
+ new->size = *cache_size / 1024;
+ rc = sysfs_create_file(&new->kobj,
+ &cache_size_attr.attr);
+ WARN_ON(rc);
+ }
+
+ /* coherency_line_size */
+ cache_line_size = of_get_property(np, info->line_size_prop, NULL);
+ if (cache_line_size) {
+ new->line_size = *cache_line_size;
+ rc = sysfs_create_file(&new->kobj,
+ &cache_line_size_attr.attr);
+ WARN_ON(rc);
+ }
+
+ /* number_of_sets */
+ nr_sets = of_get_property(np, info->nr_sets_prop, NULL);
+ if (nr_sets) {
+ new->nr_sets = *nr_sets;
+ rc = sysfs_create_file(&new->kobj,
+ &cache_nr_sets_attr.attr);
+ WARN_ON(rc);
+ }
+
+ /* ways_of_associativity */
+ if (new->nr_sets == 1) {
+ /* fully associative */
+ new->associativity = 0;
+ goto create_assoc;
+ }
+
+ if (new->nr_sets && new->size && new->line_size) {
+ /* If we have values for all of these we can derive
+ * the associativity. */
+ new->associativity =
+ ((new->size * 1024) / new->nr_sets) / new->line_size;
+create_assoc:
+ rc = sysfs_create_file(&new->kobj,
+ &cache_assoc_attr.attr);
+ WARN_ON(rc);
+ }
+
+ return new;
+err:
+ kfree(new);
+ return NULL;
+}
+
+static bool cache_is_unified(struct device_node *np)
+{
+ return of_get_property(np, "cache-unified", NULL);
+}
+
+static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level)
+{
+ const phandle *next_cache_phandle;
+ struct device_node *next_cache;
+ struct cache_desc *new, **end;
+
+ pr_debug("%s(node = %s, index = %d)\n", __func__, np->full_name, index);
+
+ if (cache_is_unified(np)) {
+ new = create_cache_desc(np, parent, index, level,
+ &ucache_info);
+ } else {
+ new = create_cache_desc(np, parent, index, level,
+ &dcache_info);
+ if (new) {
+ index++;
+ new->next = create_cache_desc(np, parent, index, level,
+ &icache_info);
+ }
+ }
+ if (!new)
+ return NULL;
+
+ end = &new->next;
+ while (*end)
+ end = &(*end)->next;
+
+ next_cache_phandle = of_get_property(np, "l2-cache", NULL);
+ if (!next_cache_phandle)
+ goto out;
+
+ next_cache = of_find_node_by_phandle(*next_cache_phandle);
+ if (!next_cache)
+ goto out;
+
+ *end = create_cache_index_info(next_cache, parent, ++index, ++level);
+
+ of_node_put(next_cache);
+out:
+ return new;
+}
+
+static void __cpuinit create_cache_info(struct sys_device *sysdev)
+{
+ struct kobject *cache_toplevel;
+ struct device_node *np = NULL;
+ int cpu = sysdev->id;
+
+ cache_toplevel = kobject_create_and_add("cache", &sysdev->kobj);
+ if (!cache_toplevel)
+ return;
+ per_cpu(cache_toplevel, cpu) = cache_toplevel;
+ np = of_get_cpu_node(cpu, NULL);
+ if (np != NULL) {
+ per_cpu(cache_desc, cpu) =
+ create_cache_index_info(np, cache_toplevel, 0, 1);
+ of_node_put(np);
+ }
+ return;
+}
+
+static void __cpuinit register_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct sys_device *s = &c->sysdev;
@@ -346,9 +629,33 @@ static void register_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_create_file(s, &attr_dscr);
+
+ create_cache_info(s);
}
#ifdef CONFIG_HOTPLUG_CPU
+static void remove_cache_info(struct sys_device *sysdev)
+{
+ struct kobject *cache_toplevel;
+ struct cache_desc *cache_desc;
+ int cpu = sysdev->id;
+
+ cache_desc = per_cpu(cache_desc, cpu);
+ if (cache_desc != NULL) {
+ sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr);
+ sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr);
+ sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr);
+ sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr);
+ sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr);
+ sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr);
+
+ kobject_put(&cache_desc->kobj);
+ }
+ cache_toplevel = per_cpu(cache_toplevel, cpu);
+ if (cache_toplevel != NULL)
+ kobject_put(cache_toplevel);
+}
+
static void unregister_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
@@ -399,6 +706,8 @@ static void unregister_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_remove_file(s, &attr_dscr);
+
+ remove_cache_info(s);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index ade8aeaa2e70..22a3c33fd751 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -530,7 +530,7 @@ static dma_addr_t vio_dma_iommu_map_single(struct device *dev, void *vaddr,
}
ret = dma_iommu_ops.map_single(dev, vaddr, size, direction, attrs);
- if (unlikely(dma_mapping_error(ret))) {
+ if (unlikely(dma_mapping_error(dev, ret))) {
vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE));
atomic_inc(&viodev->cmo.allocs_failed);
}
@@ -1031,8 +1031,8 @@ void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {}
static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; }
static void vio_cmo_bus_remove(struct vio_dev *viodev) {}
static void vio_cmo_set_dma_ops(struct vio_dev *viodev) {}
-static void vio_cmo_bus_init() {}
-static void vio_cmo_sysfs_init() { }
+static void vio_cmo_bus_init(void) {}
+static void vio_cmo_sysfs_init(void) { }
#endif /* CONFIG_PPC_SMLPAR */
EXPORT_SYMBOL(vio_cmo_entitlement_update);
EXPORT_SYMBOL(vio_cmo_set_dev_desired);
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 1c00e0196f6c..e7392b45a5ef 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -12,7 +12,8 @@ obj-y := fault.o mem.o \
mmu_context_$(CONFIG_WORD_SIZE).o
hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC64) += hash_utils_64.o \
- slb_low.o slb.o stab.o mmap.o $(hash-y)
+ slb_low.o slb.o stab.o \
+ gup.o mmap.o $(hash-y)
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
tlb_$(CONFIG_WORD_SIZE).o
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
new file mode 100644
index 000000000000..9fdf4d6335e4
--- /dev/null
+++ b/arch/powerpc/mm/gup.c
@@ -0,0 +1,280 @@
+/*
+ * Lockless get_user_pages_fast for powerpc
+ *
+ * Copyright (C) 2008 Nick Piggin
+ * Copyright (C) 2008 Novell Inc.
+ */
+#undef DEBUG
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/vmstat.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <asm/pgtable.h>
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long mask, result;
+ pte_t *ptep;
+
+ result = _PAGE_PRESENT|_PAGE_USER;
+ if (write)
+ result |= _PAGE_RW;
+ mask = result | _PAGE_SPECIAL;
+
+ ptep = pte_offset_kernel(&pmd, addr);
+ do {
+ pte_t pte = *ptep;
+ struct page *page;
+
+ if ((pte_val(pte) & mask) != result)
+ return 0;
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+ page = pte_page(pte);
+ if (!page_cache_get_speculative(page))
+ return 0;
+ if (unlikely(pte != *ptep)) {
+ put_page(page);
+ return 0;
+ }
+ pages[*nr] = page;
+ (*nr)++;
+
+ } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+ return 1;
+}
+
+#ifdef CONFIG_HUGETLB_PAGE
+static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate,
+ unsigned long *addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ unsigned long mask;
+ unsigned long pte_end;
+ struct page *head, *page;
+ pte_t pte;
+ int refs;
+
+ pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate);
+ if (pte_end < end)
+ end = pte_end;
+
+ pte = *ptep;
+ mask = _PAGE_PRESENT|_PAGE_USER;
+ if (write)
+ mask |= _PAGE_RW;
+ if ((pte_val(pte) & mask) != mask)
+ return 0;
+ /* hugepages are never "special" */
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+ refs = 0;
+ head = pte_page(pte);
+ page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT);
+ do {
+ VM_BUG_ON(compound_head(page) != head);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+ refs++;
+ } while (*addr += PAGE_SIZE, *addr != end);
+
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+ }
+ if (unlikely(pte != *ptep)) {
+ /* Could be optimized better */
+ while (*nr) {
+ put_page(page);
+ (*nr)--;
+ }
+ }
+
+ return 1;
+}
+#endif /* CONFIG_HUGETLB_PAGE */
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pmd_t *pmdp;
+
+ pmdp = pmd_offset(&pud, addr);
+ do {
+ pmd_t pmd = *pmdp;
+
+ next = pmd_addr_end(addr, end);
+ if (pmd_none(pmd))
+ return 0;
+ if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+ return 0;
+ } while (pmdp++, addr = next, addr != end);
+
+ return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ unsigned long next;
+ pud_t *pudp;
+
+ pudp = pud_offset(&pgd, addr);
+ do {
+ pud_t pud = *pudp;
+
+ next = pud_addr_end(addr, end);
+ if (pud_none(pud))
+ return 0;
+ if (!gup_pmd_range(pud, addr, next, write, pages, nr))
+ return 0;
+ } while (pudp++, addr = next, addr != end);
+
+ return 1;
+}
+
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **pages)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr, len, end;
+ unsigned long next;
+ pgd_t *pgdp;
+ int psize, nr = 0;
+ unsigned int shift;
+
+ pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
+
+ start &= PAGE_MASK;
+ addr = start;
+ len = (unsigned long) nr_pages << PAGE_SHIFT;
+ end = start + len;
+
+ if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+ start, len)))
+ goto slow_irqon;
+
+ pr_debug(" aligned: %lx .. %lx\n", start, end);
+
+#ifdef CONFIG_HUGETLB_PAGE
+ /* We bail out on slice boundary crossing when hugetlb is
+ * enabled in order to not have to deal with two different
+ * page table formats
+ */
+ if (addr < SLICE_LOW_TOP) {
+ if (end > SLICE_LOW_TOP)
+ goto slow_irqon;
+
+ if (unlikely(GET_LOW_SLICE_INDEX(addr) !=
+ GET_LOW_SLICE_INDEX(end - 1)))
+ goto slow_irqon;
+ } else {
+ if (unlikely(GET_HIGH_SLICE_INDEX(addr) !=
+ GET_HIGH_SLICE_INDEX(end - 1)))
+ goto slow_irqon;
+ }
+#endif /* CONFIG_HUGETLB_PAGE */
+
+ /*
+ * XXX: batch / limit 'nr', to avoid large irq off latency
+ * needs some instrumenting to determine the common sizes used by
+ * important workloads (eg. DB2), and whether limiting the batch size
+ * will decrease performance.
+ *
+ * It seems like we're in the clear for the moment. Direct-IO is
+ * the main guy that batches up lots of get_user_pages, and even
+ * they are limited to 64-at-a-time which is not so many.
+ */
+ /*
+ * This doesn't prevent pagetable teardown, but does prevent
+ * the pagetables from being freed on powerpc.
+ *
+ * So long as we atomically load page table pointers versus teardown,
+ * we can follow the address down to the the page and take a ref on it.
+ */
+ local_irq_disable();
+
+ psize = get_slice_psize(mm, addr);
+ shift = mmu_psize_defs[psize].shift;
+
+#ifdef CONFIG_HUGETLB_PAGE
+ if (unlikely(mmu_huge_psizes[psize])) {
+ pte_t *ptep;
+ unsigned long a = addr;
+ unsigned long sz = ((1UL) << shift);
+ struct hstate *hstate = size_to_hstate(sz);
+
+ BUG_ON(!hstate);
+ /*
+ * XXX: could be optimized to avoid hstate
+ * lookup entirely (just use shift)
+ */
+
+ do {
+ VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift);
+ ptep = huge_pte_offset(mm, a);
+ pr_debug(" %016lx: huge ptep %p\n", a, ptep);
+ if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages,
+ &nr))
+ goto slow;
+ } while (a != end);
+ } else
+#endif /* CONFIG_HUGETLB_PAGE */
+ {
+ pgdp = pgd_offset(mm, addr);
+ do {
+ pgd_t pgd = *pgdp;
+
+ VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
+ pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd);
+ next = pgd_addr_end(addr, end);
+ if (pgd_none(pgd))
+ goto slow;
+ if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+ goto slow;
+ } while (pgdp++, addr = next, addr != end);
+ }
+ local_irq_enable();
+
+ VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+ return nr;
+
+ {
+ int ret;
+
+slow:
+ local_irq_enable();
+slow_irqon:
+ pr_debug(" slow path ! nr = %d\n", nr);
+
+ /* Try to get the remaining pages with get_user_pages */
+ start += nr << PAGE_SHIFT;
+ pages += nr;
+
+ down_read(&mm->mmap_sem);
+ ret = get_user_pages(current, mm, start,
+ (end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+ up_read(&mm->mmap_sem);
+
+ /* Have to be a bit careful with return values */
+ if (nr > 0) {
+ if (ret < 0)
+ ret = nr;
+ else
+ ret += nr;
+ }
+
+ return ret;
+ }
+}
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index ed0aab0208a6..f1c2d55b4377 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -736,14 +736,21 @@ static int __init hugetlbpage_init(void)
if (!cpu_has_feature(CPU_FTR_16M_PAGE))
return -ENODEV;
+
/* Add supported huge page sizes. Need to change HUGE_MAX_HSTATE
* and adjust PTE_NONCACHE_NUM if the number of supported huge page
* sizes changes.
*/
set_huge_psize(MMU_PAGE_16M);
- set_huge_psize(MMU_PAGE_64K);
set_huge_psize(MMU_PAGE_16G);
+ /* Temporarily disable support for 64K huge pages when 64K SPU local
+ * store support is enabled as the current implementation conflicts.
+ */
+#ifndef CONFIG_SPU_FS_64K_LS
+ set_huge_psize(MMU_PAGE_64K);
+#endif
+
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
if (mmu_huge_psizes[psize]) {
huge_pgtable_cache(psize) = kmem_cache_create(
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index dd4be4aee314..ec43477caa63 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -105,6 +105,7 @@ static void __init mpc832x_sys_setup_arch(void)
static struct of_device_id mpc832x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{ .type = "qe", },
{ .compatible = "fsl,qe", },
{},
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index f049d692d4c8..0300268ce5b8 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -115,6 +115,7 @@ static void __init mpc832x_rdb_setup_arch(void)
static struct of_device_id mpc832x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{ .type = "qe", },
{ .compatible = "fsl,qe", },
{},
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 7301d77a08ee..76092d37c7d9 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -41,6 +41,7 @@
static struct of_device_id __initdata mpc834x_itx_ids[] = {
{ .compatible = "fsl,pq2pro-localbus", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c
index 30d509aa9f08..fc3f2ed1f3e9 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c
@@ -111,6 +111,7 @@ static void __init mpc834x_mds_init_IRQ(void)
static struct of_device_id mpc834x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index 75b80e836576..9d46e5bdd101 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -136,6 +136,7 @@ static void __init mpc836x_mds_setup_arch(void)
static struct of_device_id mpc836x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{ .type = "qe", },
{ .compatible = "fsl,qe", },
{},
diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c
index fc21f5c15bab..156c4e218009 100644
--- a/arch/powerpc/platforms/83xx/sbc834x.c
+++ b/arch/powerpc/platforms/83xx/sbc834x.c
@@ -83,6 +83,7 @@ static void __init sbc834x_init_IRQ(void)
static struct __initdata of_device_id sbc834x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c
index 2145adeb220c..8a3b117b6ce2 100644
--- a/arch/powerpc/platforms/85xx/ksi8560.c
+++ b/arch/powerpc/platforms/85xx/ksi8560.c
@@ -222,6 +222,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m)
static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", },
+ { .type = "simple-bus", },
{ .name = "cpm", },
{ .name = "localbus", },
{},
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c
index 6b846aa1ced9..1bf5aefdfeb1 100644
--- a/arch/powerpc/platforms/85xx/mpc8536_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c
@@ -91,6 +91,7 @@ static void __init mpc8536_ds_setup_arch(void)
static struct of_device_id __initdata mpc8536_ds_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index ba498d6f2d02..d17807a6b89a 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -230,6 +230,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 00c535806647..483b65cbabae 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -186,6 +186,7 @@ static int __init mpc8544_ds_probe(void)
static struct of_device_id __initdata mpc85xxds_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 43a459f63e31..2494c5155919 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -260,6 +260,7 @@ machine_arch_initcall(mpc85xx_mds, board_fixups);
static struct of_device_id mpc85xx_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
+ { .compatible = "simple-bus", },
{ .type = "qe", },
{ .compatible = "fsl,qe", },
{},
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
index 2c580cd24e4f..6509ade71668 100644
--- a/arch/powerpc/platforms/85xx/sbc8560.c
+++ b/arch/powerpc/platforms/85xx/sbc8560.c
@@ -217,6 +217,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", },
{ .name = "cpm", },
{ .name = "localbus", },
+ { .compatible = "simple-bus", },
{},
};
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index 6fc849e51e48..71d7562e190b 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -105,6 +105,16 @@ config 8xx_COPYBACK
If in doubt, say Y here.
+config 8xx_GPIO
+ bool "GPIO API Support"
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Saying Y here will cause the ports on an MPC8xx processor to be used
+ with the GPIO API. If you say N here, the kernel needs less memory.
+
+ If in doubt, say Y here.
+
config 8xx_CPU6
bool "CPU6 Silicon Errata (860 Pre Rev. C)"
help
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 1d0968775c0a..4c900efa164e 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -254,6 +254,8 @@ config CPM2
select CPM
select PPC_LIB_RHEAP
select PPC_PCI_CHOICE
+ select ARCH_REQUIRE_GPIOLIB
+ select GENERIC_GPIO
help
The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that
@@ -281,6 +283,7 @@ config FSL_ULI1575
config CPM
bool
+ select PPC_CLOCK
config OF_RTC
bool
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
index 69288f653144..3233fe84d158 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
@@ -96,6 +96,12 @@ static int pmi_notifier(struct notifier_block *nb,
struct cpufreq_frequency_table *cbe_freqs;
u8 node;
+ /* Should this really be called for CPUFREQ_ADJUST, CPUFREQ_INCOMPATIBLE
+ * and CPUFREQ_NOTIFY policy events?)
+ */
+ if (event == CPUFREQ_START)
+ return 0;
+
cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
node = cbe_cpu_to_node(policy->cpu);
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 31635446901a..88ccf3a08a9c 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -541,6 +541,78 @@ static int __init pmac_declare_of_platform_devices(void)
}
machine_device_initcall(powermac, pmac_declare_of_platform_devices);
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+/*
+ * This is called very early, as part of console_init() (typically just after
+ * time_init()). This function is respondible for trying to find a good
+ * default console on serial ports. It tries to match the open firmware
+ * default output with one of the available serial console drivers.
+ */
+static int __init check_pmac_serial_console(void)
+{
+ struct device_node *prom_stdout = NULL;
+ int offset = 0;
+ const char *name;
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+ char *devname = "ttyS";
+#else
+ char *devname = "ttyPZ";
+#endif
+
+ pr_debug(" -> check_pmac_serial_console()\n");
+
+ /* The user has requested a console so this is already set up. */
+ if (strstr(boot_command_line, "console=")) {
+ pr_debug(" console was specified !\n");
+ return -EBUSY;
+ }
+
+ if (!of_chosen) {
+ pr_debug(" of_chosen is NULL !\n");
+ return -ENODEV;
+ }
+
+ /* We are getting a weird phandle from OF ... */
+ /* ... So use the full path instead */
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL) {
+ pr_debug(" no linux,stdout-path !\n");
+ return -ENODEV;
+ }
+ prom_stdout = of_find_node_by_path(name);
+ if (!prom_stdout) {
+ pr_debug(" can't find stdout package %s !\n", name);
+ return -ENODEV;
+ }
+ pr_debug("stdout is %s\n", prom_stdout->full_name);
+
+ name = of_get_property(prom_stdout, "name", NULL);
+ if (!name) {
+ pr_debug(" stdout package has no name !\n");
+ goto not_found;
+ }
+
+ if (strcmp(name, "ch-a") == 0)
+ offset = 0;
+ else if (strcmp(name, "ch-b") == 0)
+ offset = 1;
+ else
+ goto not_found;
+ of_node_put(prom_stdout);
+
+ pr_debug("Found serial console at %s%d\n", devname, offset);
+
+ return add_preferred_console(devname, offset, NULL);
+
+ not_found:
+ pr_debug("No preferred console found !\n");
+ of_node_put(prom_stdout);
+ return -ENODEV;
+}
+console_initcall(check_pmac_serial_console);
+
+#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */
+
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 47de4d3fc167..572771fd8463 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -125,13 +125,23 @@ void udbg_scc_init(int force_scc)
out_8(sccc, 0xc0);
/* If SCC was the OF output port, read the BRG value, else
- * Setup for 57600 8N1
+ * Setup for 38400 or 57600 8N1 depending on the machine
*/
if (ch_def != NULL) {
out_8(sccc, 13);
scc_inittab[1] = in_8(sccc);
out_8(sccc, 12);
scc_inittab[3] = in_8(sccc);
+ } else if (machine_is_compatible("RackMac1,1")
+ || machine_is_compatible("RackMac1,2")
+ || machine_is_compatible("MacRISC4")) {
+ /* Xserves and G5s default to 57600 */
+ scc_inittab[1] = 0;
+ scc_inittab[3] = 0;
+ } else {
+ /* Others default to 38400 */
+ scc_inittab[1] = 0;
+ scc_inittab[3] = 1;
}
for (i = 0; i < sizeof(scc_inittab); ++i)
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index c6b3be03168b..38fe32a7cc70 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -289,7 +289,9 @@ static int cmm_thread(void *dummy)
}
#define CMM_SHOW(name, format, args...) \
- static ssize_t show_##name(struct sys_device *dev, char *buf) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ struct sysdev_attribute *attr, \
+ char *buf) \
{ \
return sprintf(buf, format, ##args); \
} \
@@ -298,12 +300,14 @@ static int cmm_thread(void *dummy)
CMM_SHOW(loaned_kb, "%lu\n", PAGES2KB(loaned_pages));
CMM_SHOW(loaned_target_kb, "%lu\n", PAGES2KB(loaned_pages_target));
-static ssize_t show_oom_pages(struct sys_device *dev, char *buf)
+static ssize_t show_oom_pages(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", PAGES2KB(oom_freed_pages));
}
static ssize_t store_oom_pages(struct sys_device *dev,
+ struct sysdev_attribute *attr,
const char *buf, size_t count)
{
unsigned long val = simple_strtoul (buf, NULL, 10);
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 661df42830b9..4a04823e8423 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -30,6 +30,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
@@ -42,6 +43,10 @@
#include <asm/fs_pd.h>
+#ifdef CONFIG_8xx_GPIO
+#include <linux/of_gpio.h>
+#endif
+
#define CPM_MAP_SIZE (0x4000)
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
@@ -290,20 +295,24 @@ struct cpm_ioport16 {
__be16 res[3];
};
-struct cpm_ioport32 {
- __be32 dir, par, sor;
+struct cpm_ioport32b {
+ __be32 dir, par, odr, dat;
+};
+
+struct cpm_ioport32e {
+ __be32 dir, par, sor, odr, dat;
};
static void cpm1_set_pin32(int port, int pin, int flags)
{
- struct cpm_ioport32 __iomem *iop;
+ struct cpm_ioport32e __iomem *iop;
pin = 1 << (31 - pin);
if (port == CPM_PORTB)
- iop = (struct cpm_ioport32 __iomem *)
+ iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pbdir;
else
- iop = (struct cpm_ioport32 __iomem *)
+ iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pedir;
if (flags & CPM_PIN_OUTPUT)
@@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
return 0;
}
+
+/*
+ * GPIO LIB API implementation
+ */
+#ifdef CONFIG_8xx_GPIO
+
+struct cpm1_gpio16_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u16 cpdata;
+};
+
+static inline struct cpm1_gpio16_chip *
+to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
+}
+
+static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+
+ cpm1_gc->cpdata = in_be16(&iop->dat);
+}
+
+static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ return !!(in_be16(&iop->dat) & pin_mask);
+}
+
+static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u16 pin_mask = 1 << (15 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ if (value)
+ cpm1_gc->cpdata |= pin_mask;
+ else
+ cpm1_gc->cpdata &= ~pin_mask;
+
+ out_be16(&iop->dat, cpm1_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+}
+
+static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ setbits16(&iop->dir, pin_mask);
+
+ cpm1_gpio16_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport16 __iomem *iop = mm_gc->regs;
+ u16 pin_mask;
+
+ pin_mask = 1 << (15 - gpio);
+
+ clrbits16(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm1_gpiochip_add16(struct device_node *np)
+{
+ struct cpm1_gpio16_chip *cpm1_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
+ if (!cpm1_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm1_gc->lock);
+
+ mm_gc = &cpm1_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm1_gpio16_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = 16;
+ gc->direction_input = cpm1_gpio16_dir_in;
+ gc->direction_output = cpm1_gpio16_dir_out;
+ gc->get = cpm1_gpio16_get;
+ gc->set = cpm1_gpio16_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+
+struct cpm1_gpio32_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct cpm1_gpio32_chip *
+to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
+}
+
+static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+
+ cpm1_gc->cpdata = in_be32(&iop->dat);
+}
+
+static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ return !!(in_be32(&iop->dat) & pin_mask);
+}
+
+static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ if (value)
+ cpm1_gc->cpdata |= pin_mask;
+ else
+ cpm1_gc->cpdata &= ~pin_mask;
+
+ out_be32(&iop->dat, cpm1_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+}
+
+static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ setbits32(&iop->dir, pin_mask);
+
+ cpm1_gpio32_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm_ioport32b __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ clrbits32(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm1_gpiochip_add32(struct device_node *np)
+{
+ struct cpm1_gpio32_chip *cpm1_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
+ if (!cpm1_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm1_gc->lock);
+
+ mm_gc = &cpm1_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm1_gpio32_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = 32;
+ gc->direction_input = cpm1_gpio32_dir_in;
+ gc->direction_output = cpm1_gpio32_dir_out;
+ gc->get = cpm1_gpio32_get;
+ gc->set = cpm1_gpio32_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+
+static int cpm_init_par_io(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a")
+ cpm1_gpiochip_add16(np);
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b")
+ cpm1_gpiochip_add32(np);
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c")
+ cpm1_gpiochip_add16(np);
+
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d")
+ cpm1_gpiochip_add16(np);
+
+ /* Port E uses CPM2 layout */
+ for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e")
+ cpm2_gpiochip_add32(np);
+ return 0;
+}
+arch_initcall(cpm_init_par_io);
+
+#endif /* CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c
index 5a6c5dfc53ef..f1c3395633b9 100644
--- a/arch/powerpc/sysdev/cpm2.c
+++ b/arch/powerpc/sysdev/cpm2.c
@@ -115,16 +115,10 @@ EXPORT_SYMBOL(cpm_command);
* Baud rate clocks are zero-based in the driver code (as that maps
* to port numbers). Documentation uses 1-based numbering.
*/
-#define BRG_INT_CLK (get_brgfreq())
-#define BRG_UART_CLK (BRG_INT_CLK/16)
-
-/* This function is used by UARTS, or anything else that uses a 16x
- * oversampled clock.
- */
-void
-cpm_setbrg(uint brg, uint rate)
+void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
{
u32 __iomem *bp;
+ u32 val;
/* This is good enough to get SMCs running.....
*/
@@ -135,34 +129,14 @@ cpm_setbrg(uint brg, uint rate)
brg -= 4;
}
bp += brg;
- out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN);
-
- cpm2_unmap(bp);
-}
-
-/* This function is used to set high speed synchronous baud rate
- * clocks.
- */
-void
-cpm2_fastbrg(uint brg, uint rate, int div16)
-{
- u32 __iomem *bp;
- u32 val;
-
- if (brg < 4) {
- bp = cpm2_map_size(im_brgc1, 16);
- } else {
- bp = cpm2_map_size(im_brgc5, 16);
- brg -= 4;
- }
- bp += brg;
- val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+ val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src;
if (div16)
val |= CPM_BRG_DIV16;
out_be32(bp, val);
cpm2_unmap(bp);
}
+EXPORT_SYMBOL(__cpm2_setbrg);
int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
{
@@ -377,3 +351,14 @@ void cpm2_set_pin(int port, int pin, int flags)
else
clrbits32(&iop[port].odr, pin);
}
+
+static int cpm_init_par_io(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank")
+ cpm2_gpiochip_add32(np);
+ return 0;
+}
+arch_initcall(cpm_init_par_io);
+
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index e4b7296acb2c..53da8a079f96 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -19,6 +19,8 @@
#include <linux/init.h>
#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
#include <asm/udbg.h>
#include <asm/io.h>
@@ -28,6 +30,10 @@
#include <mm/mmu_decl.h>
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+#include <linux/of_gpio.h>
+#endif
+
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
static u32 __iomem *cpm_udbg_txdesc =
(u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR;
@@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr)
return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
}
EXPORT_SYMBOL(cpm_muram_dma);
+
+#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
+
+struct cpm2_ioports {
+ u32 dir, par, sor, odr, dat;
+ u32 res[3];
+};
+
+struct cpm2_gpio32_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadowed data register to clear/set bits safely */
+ u32 cpdata;
+};
+
+static inline struct cpm2_gpio32_chip *
+to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
+}
+
+static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
+{
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+
+ cpm2_gc->cpdata = in_be32(&iop->dat);
+}
+
+static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ return !!(in_be32(&iop->dat) & pin_mask);
+}
+
+static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm2_gc->lock, flags);
+
+ if (value)
+ cpm2_gc->cpdata |= pin_mask;
+ else
+ cpm2_gc->cpdata &= ~pin_mask;
+
+ out_be32(&iop->dat, cpm2_gc->cpdata);
+
+ spin_unlock_irqrestore(&cpm2_gc->lock, flags);
+}
+
+static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ setbits32(&iop->dir, pin_mask);
+
+ cpm2_gpio32_set(gc, gpio, val);
+
+ return 0;
+}
+
+static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm2_ioports __iomem *iop = mm_gc->regs;
+ u32 pin_mask;
+
+ pin_mask = 1 << (31 - gpio);
+
+ clrbits32(&iop->dir, pin_mask);
+
+ return 0;
+}
+
+int cpm2_gpiochip_add32(struct device_node *np)
+{
+ struct cpm2_gpio32_chip *cpm2_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
+ if (!cpm2_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&cpm2_gc->lock);
+
+ mm_gc = &cpm2_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = cpm2_gpio32_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = 32;
+ gc->direction_input = cpm2_gpio32_dir_in;
+ gc->direction_output = cpm2_gpio32_dir_out;
+ gc->get = cpm2_gpio32_get;
+ gc->set = cpm2_gpio32_set;
+
+ return of_mm_gpiochip_add(np, mm_gc);
+}
+#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c
index c09ddc0dbeb3..c1879ebfd4f4 100644
--- a/arch/powerpc/sysdev/rtc_cmos_setup.c
+++ b/arch/powerpc/sysdev/rtc_cmos_setup.c
@@ -21,6 +21,7 @@ static int __init add_rtc(void)
struct device_node *np;
struct platform_device *pd;
struct resource res[2];
+ unsigned int num_res = 1;
int ret;
memset(&res, 0, sizeof(res));
@@ -41,14 +42,24 @@ static int __init add_rtc(void)
if (res[0].start != RTC_PORT(0))
return -EINVAL;
- /* Use a fixed interrupt value of 8 since on PPC if we are using this
- * its off an i8259 which we ensure has interrupt numbers 0..15. */
- res[1].start = 8;
- res[1].end = 8;
- res[1].flags = IORESOURCE_IRQ;
+ np = of_find_compatible_node(NULL, NULL, "chrp,iic");
+ if (!np)
+ np = of_find_compatible_node(NULL, NULL, "pnpPNP,000");
+ if (np) {
+ of_node_put(np);
+ /*
+ * Use a fixed interrupt value of 8 since on PPC if we are
+ * using this its off an i8259 which we ensure has interrupt
+ * numbers 0..15.
+ */
+ res[1].start = 8;
+ res[1].end = 8;
+ res[1].flags = IORESOURCE_IRQ;
+ num_res++;
+ }
pd = platform_device_register_simple("rtc_cmos", -1,
- &res[0], 2);
+ &res[0], num_res);
if (IS_ERR(pd))
return PTR_ERR(pd);