summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/Makefile11
-rw-r--r--arch/powerpc/kernel/asm-offsets.c18
-rw-r--r--arch/powerpc/kernel/audit.c66
-rw-r--r--arch/powerpc/kernel/binfmt_elf32.c1
-rw-r--r--arch/powerpc/kernel/btext.c29
-rw-r--r--arch/powerpc/kernel/compat_audit.c38
-rw-r--r--arch/powerpc/kernel/cpu_setup_6xx.S1
-rw-r--r--arch/powerpc/kernel/cpu_setup_ppc970.S (renamed from arch/powerpc/kernel/cpu_setup_power4.S)104
-rw-r--r--arch/powerpc/kernel/cputable.c34
-rw-r--r--arch/powerpc/kernel/crash.c164
-rw-r--r--arch/powerpc/kernel/crash_dump.c2
-rw-r--r--arch/powerpc/kernel/dma_64.c65
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/entry_64.S9
-rw-r--r--arch/powerpc/kernel/firmware.c1
-rw-r--r--arch/powerpc/kernel/fpu.S6
-rw-r--r--arch/powerpc/kernel/head_32.S1
-rw-r--r--arch/powerpc/kernel/head_44x.S1
-rw-r--r--arch/powerpc/kernel/head_4xx.S1
-rw-r--r--arch/powerpc/kernel/head_64.S152
-rw-r--r--arch/powerpc/kernel/head_8xx.S1
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S1
-rw-r--r--arch/powerpc/kernel/ibmebus.c15
-rw-r--r--arch/powerpc/kernel/idle.c1
-rw-r--r--arch/powerpc/kernel/idle_6xx.S1
-rw-r--r--arch/powerpc/kernel/idle_power4.S1
-rw-r--r--arch/powerpc/kernel/io.c131
-rw-r--r--arch/powerpc/kernel/iommu.c31
-rw-r--r--arch/powerpc/kernel/irq.c725
-rw-r--r--arch/powerpc/kernel/kprobes.c3
-rw-r--r--arch/powerpc/kernel/l2cr_6xx.S1
-rw-r--r--arch/powerpc/kernel/legacy_serial.c121
-rw-r--r--arch/powerpc/kernel/lparcfg.c172
-rw-r--r--arch/powerpc/kernel/machine_kexec.c56
-rw-r--r--arch/powerpc/kernel/machine_kexec_32.c4
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c69
-rw-r--r--arch/powerpc/kernel/misc.S45
-rw-r--r--arch/powerpc/kernel/misc_32.S157
-rw-r--r--arch/powerpc/kernel/misc_64.S236
-rw-r--r--arch/powerpc/kernel/of_device.c25
-rw-r--r--arch/powerpc/kernel/paca.c17
-rw-r--r--arch/powerpc/kernel/pci_32.c149
-rw-r--r--arch/powerpc/kernel/pci_64.c135
-rw-r--r--arch/powerpc/kernel/pci_dn.c13
-rw-r--r--arch/powerpc/kernel/perfmon_fsl_booke.c1
-rw-r--r--arch/powerpc/kernel/pmc.c1
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c26
-rw-r--r--arch/powerpc/kernel/proc_ppc64.c3
-rw-r--r--arch/powerpc/kernel/process.c1
-rw-r--r--arch/powerpc/kernel/prom.c546
-rw-r--r--arch/powerpc/kernel/prom_init.c75
-rw-r--r--arch/powerpc/kernel/prom_parse.c509
-rw-r--r--arch/powerpc/kernel/ptrace-common.h1
-rw-r--r--arch/powerpc/kernel/ptrace.c1
-rw-r--r--arch/powerpc/kernel/ptrace32.c1
-rw-r--r--arch/powerpc/kernel/rtas-proc.c25
-rw-r--r--arch/powerpc/kernel/rtas.c187
-rw-r--r--arch/powerpc/kernel/rtas_pci.c45
-rw-r--r--arch/powerpc/kernel/setup-common.c35
-rw-r--r--arch/powerpc/kernel/setup_32.c5
-rw-r--r--arch/powerpc/kernel/setup_64.c61
-rw-r--r--arch/powerpc/kernel/signal_32.c1
-rw-r--r--arch/powerpc/kernel/signal_64.c1
-rw-r--r--arch/powerpc/kernel/smp-tbsync.c6
-rw-r--r--arch/powerpc/kernel/smp.c25
-rw-r--r--arch/powerpc/kernel/swsusp_32.S5
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c3
-rw-r--r--arch/powerpc/kernel/sysfs.c41
-rw-r--r--arch/powerpc/kernel/systbl.S1
-rw-r--r--arch/powerpc/kernel/tau_6xx.c1
-rw-r--r--arch/powerpc/kernel/time.c59
-rw-r--r--arch/powerpc/kernel/traps.c94
-rw-r--r--arch/powerpc/kernel/udbg.c8
-rw-r--r--arch/powerpc/kernel/udbg_16550.c7
-rw-r--r--arch/powerpc/kernel/vdso.c1
-rw-r--r--arch/powerpc/kernel/vdso32/Makefile3
-rw-r--r--arch/powerpc/kernel/vdso32/cacheflush.S1
-rw-r--r--arch/powerpc/kernel/vdso32/datapage.S1
-rw-r--r--arch/powerpc/kernel/vdso32/gettimeofday.S1
-rw-r--r--arch/powerpc/kernel/vdso32/sigtramp.S1
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32.lds.S1
-rw-r--r--arch/powerpc/kernel/vdso64/Makefile3
-rw-r--r--arch/powerpc/kernel/vdso64/cacheflush.S1
-rw-r--r--arch/powerpc/kernel/vdso64/datapage.S1
-rw-r--r--arch/powerpc/kernel/vdso64/gettimeofday.S1
-rw-r--r--arch/powerpc/kernel/vdso64/sigtramp.S1
-rw-r--r--arch/powerpc/kernel/vdso64/vdso64.lds.S1
-rw-r--r--arch/powerpc/kernel/vector.S1
-rw-r--r--arch/powerpc/kernel/vio.c28
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S1
90 files changed, 2626 insertions, 2011 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 803858e86160..8b133afbdc20 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -16,7 +16,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o \
- paca.o cpu_setup_power4.o \
+ paca.o cpu_setup_ppc970.o \
firmware.o sysfs.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
@@ -50,7 +50,8 @@ extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
-obj-y += time.o prom.o traps.o setup-common.o udbg.o
+obj-y += time.o prom.o traps.o setup-common.o \
+ udbg.o misc.o io.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o
obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
@@ -66,9 +67,11 @@ pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \
pci_direct_iommu.o iomap.o
pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
-kexec-$(CONFIG_PPC64) := machine_kexec_64.o crash.o
+kexec-$(CONFIG_PPC64) := machine_kexec_64.o
kexec-$(CONFIG_PPC32) := machine_kexec_32.o
-obj-$(CONFIG_KEXEC) += machine_kexec.o $(kexec-y)
+obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y)
+obj-$(CONFIG_AUDIT) += audit.o
+obj64-$(CONFIG_AUDIT) += compat_audit.o
ifeq ($(CONFIG_PPC_ISERIES),y)
$(obj)/head_64.o: $(obj)/lparmap.s
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index ff2940548929..d06f378597bb 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -13,7 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -41,9 +40,10 @@
#ifdef CONFIG_PPC64
#include <asm/paca.h>
#include <asm/lppaca.h>
-#include <asm/iseries/hv_lp_event.h>
#include <asm/cache.h>
#include <asm/compat.h>
+#include <asm/mmu.h>
+#include <asm/hvcall.h>
#endif
#define DEFINE(sym, val) \
@@ -137,11 +137,18 @@ int main(void)
DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr));
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
+ DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr));
+ DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
+ DEFINE(SLBSHADOW_STACKVSID,
+ offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
+ DEFINE(SLBSHADOW_STACKESID,
+ offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
+ DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
#endif /* CONFIG_PPC64 */
/* RTAS */
@@ -160,6 +167,12 @@ int main(void)
/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
+
+ /* hcall statistics */
+ DEFINE(HCALL_STAT_SIZE, sizeof(struct hcall_stats));
+ DEFINE(HCALL_STAT_CALLS, offsetof(struct hcall_stats, num_calls));
+ DEFINE(HCALL_STAT_TB, offsetof(struct hcall_stats, tb_total));
+ DEFINE(HCALL_STAT_PURR, offsetof(struct hcall_stats, purr_total));
#endif /* CONFIG_PPC64 */
DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
@@ -241,6 +254,7 @@ int main(void)
DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
+ DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
#ifndef CONFIG_PPC64
DEFINE(pbe_address, offsetof(struct pbe, address));
diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c
new file mode 100644
index 000000000000..7fe5e6300e9a
--- /dev/null
+++ b/arch/powerpc/kernel/audit.c
@@ -0,0 +1,66 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+static unsigned write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+int audit_classify_syscall(int abi, unsigned syscall)
+{
+#ifdef CONFIG_PPC64
+ extern int ppc32_classify_syscall(unsigned);
+ if (abi == AUDIT_ARCH_PPC)
+ return ppc32_classify_syscall(syscall);
+#endif
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_PPC64
+ extern __u32 ppc32_dir_class[];
+ extern __u32 ppc32_write_class[];
+ extern __u32 ppc32_read_class[];
+ extern __u32 ppc32_chattr_class[];
+ audit_register_class(AUDIT_CLASS_WRITE_32, ppc32_write_class);
+ audit_register_class(AUDIT_CLASS_READ_32, ppc32_read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class);
+#endif
+ audit_register_class(AUDIT_CLASS_WRITE, write_class);
+ audit_register_class(AUDIT_CLASS_READ, read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/arch/powerpc/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c
index 8ad6b0f33651..5cb58757e1b1 100644
--- a/arch/powerpc/kernel/binfmt_elf32.c
+++ b/arch/powerpc/kernel/binfmt_elf32.c
@@ -19,7 +19,6 @@
#include <asm/processor.h>
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index 6223d39177cb..995fcef156fd 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -3,7 +3,6 @@
*
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -112,7 +111,7 @@ void __init btext_setup_display(int width, int height, int depth, int pitch,
logicalDisplayBase = (unsigned char *)address;
dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch;
- dispDeviceDepth = depth;
+ dispDeviceDepth = depth == 15 ? 16 : depth;
dispDeviceRect[0] = dispDeviceRect[1] = 0;
dispDeviceRect[2] = width;
dispDeviceRect[3] = height;
@@ -159,27 +158,35 @@ int btext_initialize(struct device_node *np)
{
unsigned int width, height, depth, pitch;
unsigned long address = 0;
- u32 *prop;
+ const u32 *prop;
- prop = (u32 *)get_property(np, "width", NULL);
+ prop = get_property(np, "linux,bootx-width", NULL);
+ if (prop == NULL)
+ prop = get_property(np, "width", NULL);
if (prop == NULL)
return -EINVAL;
width = *prop;
- prop = (u32 *)get_property(np, "height", NULL);
+ prop = get_property(np, "linux,bootx-height", NULL);
+ if (prop == NULL)
+ prop = get_property(np, "height", NULL);
if (prop == NULL)
return -EINVAL;
height = *prop;
- prop = (u32 *)get_property(np, "depth", NULL);
+ prop = get_property(np, "linux,bootx-depth", NULL);
+ if (prop == NULL)
+ prop = get_property(np, "depth", NULL);
if (prop == NULL)
return -EINVAL;
depth = *prop;
pitch = width * ((depth + 7) / 8);
- prop = (u32 *)get_property(np, "linebytes", NULL);
+ prop = get_property(np, "linux,bootx-linebytes", NULL);
+ if (prop == NULL)
+ prop = get_property(np, "linebytes", NULL);
if (prop)
pitch = *prop;
if (pitch == 1)
pitch = 0x1000;
- prop = (u32 *)get_property(np, "address", NULL);
+ prop = get_property(np, "address", NULL);
if (prop)
address = *prop;
@@ -195,7 +202,7 @@ int btext_initialize(struct device_node *np)
g_max_loc_Y = height / 16;
dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch;
- dispDeviceDepth = depth;
+ dispDeviceDepth = depth == 15 ? 16 : depth;
dispDeviceRect[0] = dispDeviceRect[1] = 0;
dispDeviceRect[2] = width;
dispDeviceRect[3] = height;
@@ -207,11 +214,11 @@ int btext_initialize(struct device_node *np)
int __init btext_find_display(int allow_nonstdout)
{
- char *name;
+ const char *name;
struct device_node *np = NULL;
int rc = -ENODEV;
- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ name = get_property(of_chosen, "linux,stdout-path", NULL);
if (name != NULL) {
np = of_find_node_by_path(name);
if (np != NULL) {
diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c
new file mode 100644
index 000000000000..640d4bb29321
--- /dev/null
+++ b/arch/powerpc/kernel/compat_audit.c
@@ -0,0 +1,38 @@
+#undef __powerpc64__
+#include <asm/unistd.h>
+
+unsigned ppc32_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned ppc32_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+unsigned ppc32_write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+unsigned ppc32_read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+int ppc32_classify_syscall(unsigned syscall)
+{
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 1;
+ }
+}
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
index 365381fcb27c..8b4a4ee85eca 100644
--- a/arch/powerpc/kernel/cpu_setup_6xx.S
+++ b/arch/powerpc/kernel/cpu_setup_6xx.S
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
diff --git a/arch/powerpc/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_ppc970.S
index 271418308d53..652594891d58 100644
--- a/arch/powerpc/kernel/cpu_setup_power4.S
+++ b/arch/powerpc/kernel/cpu_setup_ppc970.S
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
@@ -17,27 +16,12 @@
#include <asm/asm-offsets.h>
#include <asm/cache.h>
-_GLOBAL(__970_cpu_preinit)
- /*
- * Do nothing if not running in HV mode
- */
+_GLOBAL(__cpu_preinit_ppc970)
+ /* Do nothing if not running in HV mode */
mfmsr r0
rldicl. r0,r0,4,63
beqlr
- /*
- * Deal only with PPC970 and PPC970FX.
- */
- mfspr r0,SPRN_PVR
- srwi r0,r0,16
- cmpwi r0,0x39
- beq 1f
- cmpwi r0,0x3c
- beq 1f
- cmpwi r0,0x44
- bnelr
-1:
-
/* Make sure HID4:rm_ci is off before MMU is turned off, that large
* pages are enabled with HID4:61 and clear HID5:DCBZ_size and
* HID5:DCBZ32_ill
@@ -73,21 +57,6 @@ _GLOBAL(__970_cpu_preinit)
isync
blr
-_GLOBAL(__setup_cpu_ppc970)
- mfspr r0,SPRN_HID0
- li r11,5 /* clear DOZE and SLEEP */
- rldimi r0,r11,52,8 /* set NAP and DPM */
- mtspr SPRN_HID0,r0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- sync
- isync
- blr
-
/* Definitions for the table use to save CPU states */
#define CS_HID0 0
#define CS_HID1 8
@@ -102,30 +71,32 @@ cpu_state_storage:
.balign L1_CACHE_BYTES,0
.text
-/* Called in normal context to backup CPU 0 state. This
- * does not include cache settings. This function is also
- * called for machine sleep. This does not include the MMU
- * setup, BATs, etc... but rather the "special" registers
- * like HID0, HID1, HID4, etc...
- */
-_GLOBAL(__save_cpu_setup)
- /* Some CR fields are volatile, we back it up all */
- mfcr r7
- /* Get storage ptr */
+_GLOBAL(__setup_cpu_ppc970)
+ /* Do nothing if not running in HV mode */
+ mfmsr r0
+ rldicl. r0,r0,4,63
+ beqlr
+
+ mfspr r0,SPRN_HID0
+ li r11,5 /* clear DOZE and SLEEP */
+ rldimi r0,r11,52,8 /* set NAP and DPM */
+ li r11,0
+ rldimi r0,r11,32,31 /* clear EN_ATTN */
+ mtspr SPRN_HID0,r0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ sync
+ isync
+
+ /* Save away cpu state */
LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
- /* We only deal with 970 for now */
- mfspr r0,SPRN_PVR
- srwi r0,r0,16
- cmpwi r0,0x39
- beq 1f
- cmpwi r0,0x3c
- beq 1f
- cmpwi r0,0x44
- bne 2f
-
-1: /* Save HID0,1,4 and 5 */
+ /* Save HID0,1,4 and 5 */
mfspr r3,SPRN_HID0
std r3,CS_HID0(r5)
mfspr r3,SPRN_HID1
@@ -135,31 +106,20 @@ _GLOBAL(__save_cpu_setup)
mfspr r3,SPRN_HID5
std r3,CS_HID5(r5)
-2:
- mtcr r7
blr
/* Called with no MMU context (typically MSR:IR/DR off) to
* restore CPU state as backed up by the previous
* function. This does not include cache setting
*/
-_GLOBAL(__restore_cpu_setup)
- /* Get storage ptr (FIXME when using anton reloc as we
- * are running with translation disabled here
- */
- LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+_GLOBAL(__restore_cpu_ppc970)
+ /* Do nothing if not running in HV mode */
+ mfmsr r0
+ rldicl. r0,r0,4,63
+ beqlr
- /* We only deal with 970 for now */
- mfspr r0,SPRN_PVR
- srwi r0,r0,16
- cmpwi r0,0x39
- beq 1f
- cmpwi r0,0x3c
- beq 1f
- cmpwi r0,0x44
- bnelr
-
-1: /* Before accessing memory, we make sure rm_ci is clear */
+ LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+ /* Before accessing memory, we make sure rm_ci is clear */
li r0,0
mfspr r3,SPRN_HID4
rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 1c114880dc05..190a57e20765 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -10,7 +10,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/threads.h>
@@ -40,7 +39,10 @@ extern void __setup_cpu_7400(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_7410(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec);
#endif /* CONFIG_PPC32 */
+#ifdef CONFIG_PPC64
extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_ppc970(void);
+#endif /* CONFIG_PPC64 */
/* This table only contains "desktop" CPUs, it need to be filled with embedded
* ones as well...
@@ -56,6 +58,9 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
#define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\
PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
PPC_FEATURE_TRUE_LE)
+#define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
+ PPC_FEATURE_TRUE_LE | \
+ PPC_FEATURE_HAS_ALTIVEC_COMP)
#define COMMON_USER_BOOKE (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
PPC_FEATURE_BOOKE)
@@ -185,6 +190,7 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
+ .cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "ppc970",
@@ -200,6 +206,7 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
+ .cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "ppc970",
@@ -215,6 +222,7 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 8,
.cpu_setup = __setup_cpu_ppc970,
+ .cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "ppc970",
@@ -281,6 +289,17 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 128,
.platform = "ppc-cell-be",
},
+ { /* PA Semi PA6T */
+ .pvr_mask = 0x7fff0000,
+ .pvr_value = 0x00900000,
+ .cpu_name = "PA6T",
+ .cpu_features = CPU_FTRS_PA6T,
+ .cpu_user_features = COMMON_USER_PA6T,
+ .icache_bsize = 64,
+ .dcache_bsize = 64,
+ .num_pmcs = 6,
+ .platform = "pa6t",
+ },
{ /* default match */
.pvr_mask = 0x00000000,
.pvr_value = 0x00000000,
@@ -722,18 +741,6 @@ struct cpu_spec cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_G4,
.platform = "ppc7450",
},
- { /* 8641 */
- .pvr_mask = 0xffffffff,
- .pvr_value = 0x80040010,
- .cpu_name = "8641",
- .cpu_features = CPU_FTRS_7447A,
- .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP,
- .icache_bsize = 32,
- .dcache_bsize = 32,
- .num_pmcs = 6,
- .cpu_setup = __setup_cpu_745x
- },
-
{ /* 82xx (8240, 8245, 8260 are all 603e cores) */
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00810000,
@@ -942,6 +949,7 @@ struct cpu_spec cpu_specs[] = {
PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
.icache_bsize = 32,
.dcache_bsize = 32,
+ .platform = "ppc405",
},
{ /* 405EP */
.pvr_mask = 0xffff0000,
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index dbcb85994f46..1af41f7616dc 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -24,9 +24,11 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
+#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/machdep.h>
+#include <asm/kexec.h>
#include <asm/kdump.h>
#include <asm/lmb.h>
#include <asm/firmware.h>
@@ -41,6 +43,8 @@
/* This keeps a track of which one is crashing cpu. */
int crashing_cpu = -1;
+static cpumask_t cpus_in_crash = CPU_MASK_NONE;
+cpumask_t cpus_in_sr = CPU_MASK_NONE;
static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
size_t data_len)
@@ -98,34 +102,72 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
}
#ifdef CONFIG_SMP
-static atomic_t waiting_for_crash_ipi;
+static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
void crash_ipi_callback(struct pt_regs *regs)
{
int cpu = smp_processor_id();
- if (cpu == crashing_cpu)
- return;
-
if (!cpu_online(cpu))
return;
+ local_irq_disable();
+ if (!cpu_isset(cpu, cpus_in_crash))
+ crash_save_this_cpu(regs, cpu);
+ cpu_set(cpu, cpus_in_crash);
+
+ /*
+ * Entered via soft-reset - could be the kdump
+ * process is invoked using soft-reset or user activated
+ * it if some CPU did not respond to an IPI.
+ * For soft-reset, the secondary CPU can enter this func
+ * twice. 1 - using IPI, and 2. soft-reset.
+ * Tell the kexec CPU that entered via soft-reset and ready
+ * to go down.
+ */
+ if (cpu_isset(cpu, cpus_in_sr)) {
+ cpu_clear(cpu, cpus_in_sr);
+ atomic_inc(&enter_on_soft_reset);
+ }
+
+ /*
+ * Starting the kdump boot.
+ * This barrier is needed to make sure that all CPUs are stopped.
+ * If not, soft-reset will be invoked to bring other CPUs.
+ */
+ while (!cpu_isset(crashing_cpu, cpus_in_crash))
+ cpu_relax();
+
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 1);
- local_irq_disable();
-
- crash_save_this_cpu(regs, cpu);
- atomic_dec(&waiting_for_crash_ipi);
+#ifdef CONFIG_PPC64
kexec_smp_wait();
+#else
+ for (;;); /* FIXME */
+#endif
+
/* NOTREACHED */
}
-static void crash_kexec_prepare_cpus(void)
+/*
+ * Wait until all CPUs are entered via soft-reset.
+ */
+static void crash_soft_reset_check(int cpu)
+{
+ unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
+
+ cpu_clear(cpu, cpus_in_sr);
+ while (atomic_read(&enter_on_soft_reset) != ncpus)
+ cpu_relax();
+}
+
+
+static void crash_kexec_prepare_cpus(int cpu)
{
unsigned int msecs;
- atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+ unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
crash_send_ipi(crash_ipi_callback);
smp_wmb();
@@ -133,14 +175,13 @@ static void crash_kexec_prepare_cpus(void)
/*
* FIXME: Until we will have the way to stop other CPUSs reliabally,
* the crash CPU will send an IPI and wait for other CPUs to
- * respond. If not, proceed the kexec boot even though we failed to
- * capture other CPU states.
+ * respond.
* Delay of at least 10 seconds.
*/
- printk(KERN_ALERT "Sending IPI to other cpus...\n");
+ printk(KERN_EMERG "Sending IPI to other cpus...\n");
msecs = 10000;
- while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
- barrier();
+ while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) {
+ cpu_relax();
mdelay(1);
}
@@ -149,18 +190,71 @@ static void crash_kexec_prepare_cpus(void)
/*
* FIXME: In case if we do not get all CPUs, one possibility: ask the
* user to do soft reset such that we get all.
- * IPI handler is already set by the panic cpu initially. Therefore,
- * all cpus could invoke this handler from die() and the panic CPU
- * will call machine_kexec() directly from this handler to do
- * kexec boot.
+ * Soft-reset will be used until better mechanism is implemented.
+ */
+ if (cpus_weight(cpus_in_crash) < ncpus) {
+ printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
+ ncpus - cpus_weight(cpus_in_crash));
+ printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
+ cpus_in_sr = CPU_MASK_NONE;
+ atomic_set(&enter_on_soft_reset, 0);
+ while (cpus_weight(cpus_in_crash) < ncpus)
+ cpu_relax();
+ }
+ /*
+ * Make sure all CPUs are entered via soft-reset if the kdump is
+ * invoked using soft-reset.
*/
- if (atomic_read(&waiting_for_crash_ipi))
- printk(KERN_ALERT "done waiting: %d cpus not responding\n",
- atomic_read(&waiting_for_crash_ipi));
+ if (cpu_isset(cpu, cpus_in_sr))
+ crash_soft_reset_check(cpu);
/* Leave the IPI callback set */
}
+
+/*
+ * This function will be called by secondary cpus or by kexec cpu
+ * if soft-reset is activated to stop some CPUs.
+ */
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ unsigned long flags;
+ int msecs = 5;
+
+ local_irq_save(flags);
+ /* Wait 5ms if the kexec CPU is not entered yet. */
+ while (crashing_cpu < 0) {
+ if (--msecs < 0) {
+ /*
+ * Either kdump image is not loaded or
+ * kdump process is not started - Probably xmon
+ * exited using 'x'(exit and recover) or
+ * kexec_should_crash() failed for all running tasks.
+ */
+ cpu_clear(cpu, cpus_in_sr);
+ local_irq_restore(flags);
+ return;
+ }
+ mdelay(1);
+ cpu_relax();
+ }
+ if (cpu == crashing_cpu) {
+ /*
+ * Panic CPU will enter this func only via soft-reset.
+ * Wait until all secondary CPUs entered and
+ * then start kexec boot.
+ */
+ crash_soft_reset_check(cpu);
+ cpu_set(crashing_cpu, cpus_in_crash);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(1, 0);
+ machine_kexec(kexec_crash_image);
+ /* NOTREACHED */
+ }
+ crash_ipi_callback(regs);
+}
+
#else
-static void crash_kexec_prepare_cpus(void)
+static void crash_kexec_prepare_cpus(int cpu)
{
/*
* move the secondarys to us so that we can copy
@@ -168,9 +262,17 @@ static void crash_kexec_prepare_cpus(void)
*
* do this if kexec in setup.c ?
*/
+#ifdef CONFIG_PPC64
smp_release_cpus();
+#else
+ /* FIXME */
+#endif
}
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+ cpus_in_sr = CPU_MASK_NONE;
+}
#endif
void default_machine_crash_shutdown(struct pt_regs *regs)
@@ -179,7 +281,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
/*
* This function is only called after the system
- * has paniced or is otherwise in a critical state.
+ * has panicked or is otherwise in a critical state.
* The minimum amount of code to allow a kexec'd kernel
* to run successfully needs to happen here.
*
@@ -190,23 +292,23 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
local_irq_disable();
for_each_irq(irq) {
- struct irq_desc *desc = irq_descp(irq);
+ struct irq_desc *desc = irq_desc + irq;
if (desc->status & IRQ_INPROGRESS)
- desc->handler->end(irq);
+ desc->chip->eoi(irq);
if (!(desc->status & IRQ_DISABLED))
- desc->handler->disable(irq);
+ desc->chip->disable(irq);
}
- if (ppc_md.kexec_cpu_down)
- ppc_md.kexec_cpu_down(1, 0);
-
/*
* Make a note of crashing cpu. Will be used in machine_kexec
* such that another IPI will not be sent.
*/
crashing_cpu = smp_processor_id();
- crash_kexec_prepare_cpus();
crash_save_this_cpu(regs, crashing_cpu);
+ crash_kexec_prepare_cpus(crashing_cpu);
+ cpu_set(crashing_cpu, cpus_in_crash);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(1, 0);
}
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 371973be8d71..2f6f5a7bc69e 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -80,7 +80,7 @@ static int __init parse_savemaxmem(char *p)
}
__setup("savemaxmem=", parse_savemaxmem);
-/*
+/**
* copy_oldmem_page - copy one page from "oldmem"
* @pfn: page frame number to be copied
* @buf: target memory address for the copy; this can be in kernel address
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c
index 36aaa7663f02..6c168f6ea142 100644
--- a/arch/powerpc/kernel/dma_64.c
+++ b/arch/powerpc/kernel/dma_64.c
@@ -35,10 +35,9 @@ int dma_supported(struct device *dev, u64 mask)
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- return dma_ops->dma_supported(dev, mask);
- BUG();
- return 0;
+ BUG_ON(!dma_ops);
+
+ return dma_ops->dma_supported(dev, mask);
}
EXPORT_SYMBOL(dma_supported);
@@ -66,10 +65,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
- BUG();
- return NULL;
+ BUG_ON(!dma_ops);
+
+ return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
}
EXPORT_SYMBOL(dma_alloc_coherent);
@@ -78,10 +76,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
- else
- BUG();
+ BUG_ON(!dma_ops);
+
+ dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
}
EXPORT_SYMBOL(dma_free_coherent);
@@ -90,10 +87,9 @@ dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- return dma_ops->map_single(dev, cpu_addr, size, direction);
- BUG();
- return (dma_addr_t)0;
+ BUG_ON(!dma_ops);
+
+ return dma_ops->map_single(dev, cpu_addr, size, direction);
}
EXPORT_SYMBOL(dma_map_single);
@@ -102,10 +98,9 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- dma_ops->unmap_single(dev, dma_addr, size, direction);
- else
- BUG();
+ BUG_ON(!dma_ops);
+
+ dma_ops->unmap_single(dev, dma_addr, size, direction);
}
EXPORT_SYMBOL(dma_unmap_single);
@@ -115,11 +110,10 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- return dma_ops->map_single(dev,
- (page_address(page) + offset), size, direction);
- BUG();
- return (dma_addr_t)0;
+ BUG_ON(!dma_ops);
+
+ return dma_ops->map_single(dev, page_address(page) + offset, size,
+ direction);
}
EXPORT_SYMBOL(dma_map_page);
@@ -128,10 +122,9 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- dma_ops->unmap_single(dev, dma_address, size, direction);
- else
- BUG();
+ BUG_ON(!dma_ops);
+
+ dma_ops->unmap_single(dev, dma_address, size, direction);
}
EXPORT_SYMBOL(dma_unmap_page);
@@ -140,10 +133,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- return dma_ops->map_sg(dev, sg, nents, direction);
- BUG();
- return 0;
+ BUG_ON(!dma_ops);
+
+ return dma_ops->map_sg(dev, sg, nents, direction);
}
EXPORT_SYMBOL(dma_map_sg);
@@ -152,9 +144,8 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
{
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
- if (dma_ops)
- dma_ops->unmap_sg(dev, sg, nhwentries, direction);
- else
- BUG();
+ BUG_ON(!dma_ops);
+
+ dma_ops->unmap_sg(dev, sg, nhwentries, direction);
}
EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 8866fd26c6b9..c03e829fee3c 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sys.h>
#include <linux/threads.h>
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 221062c960c9..2cd872b5283b 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -18,7 +18,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <asm/unistd.h>
#include <asm/processor.h>
@@ -376,6 +375,14 @@ BEGIN_FTR_SECTION
ld r7,KSP_VSID(r4) /* Get new stack's VSID */
oris r0,r6,(SLB_ESID_V)@h
ori r0,r0,(SLB_NUM_BOLTED-1)@l
+
+ /* Update the last bolted SLB */
+ ld r9,PACA_SLBSHADOWPTR(r13)
+ li r12,0
+ std r12,SLBSHADOW_STACKESID(r9) /* Clear ESID */
+ std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */
+ std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */
+
slbie r6
slbie r6 /* Workaround POWER5 < DD2.1 issue */
slbmte r7,r0
diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c
index 0bfe9061720a..1679a70bbcad 100644
--- a/arch/powerpc/kernel/firmware.c
+++ b/arch/powerpc/kernel/firmware.c
@@ -13,7 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/firmware.h>
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 01f71200c603..821e152e093c 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -2,6 +2,11 @@
* FPU support code, moved here from head.S so that it can be used
* by chips which use other head-whatever.S files.
*
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ * Copyright (C) 1996 Paul Mackerras.
+ * Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -9,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <asm/reg.h>
#include <asm/page.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index b25b25902d15..d88e182e40b3 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <asm/reg.h>
#include <asm/page.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 47c7fa148c9a..accb39d49911 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -28,7 +28,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/head_4xx.S b/arch/powerpc/kernel/head_4xx.S
index 2590e97f5539..adc7f8097cd4 100644
--- a/arch/powerpc/kernel/head_4xx.S
+++ b/arch/powerpc/kernel/head_4xx.S
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 831acbdf2592..3065b472b95d 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -21,7 +21,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/threads.h>
#include <asm/reg.h>
#include <asm/page.h>
@@ -85,34 +84,6 @@ END_FTR_SECTION(0, 1)
/* Catch branch to 0 in real mode */
trap
-#ifdef CONFIG_PPC_ISERIES
- /*
- * At offset 0x20, there is a pointer to iSeries LPAR data.
- * This is required by the hypervisor
- */
- . = 0x20
- .llong hvReleaseData-KERNELBASE
-
- /*
- * At offset 0x28 and 0x30 are offsets to the mschunks_map
- * array (used by the iSeries LPAR debugger to do translation
- * between physical addresses and absolute addresses) and
- * to the pidhash table (also used by the debugger)
- */
- .llong mschunks_map-KERNELBASE
- .llong 0 /* pidhash-KERNELBASE SFRXXX */
-
- /* Offset 0x38 - Pointer to start of embedded System.map */
- .globl embedded_sysmap_start
-embedded_sysmap_start:
- .llong 0
- /* Offset 0x40 - Pointer to end of embedded System.map */
- .globl embedded_sysmap_end
-embedded_sysmap_end:
- .llong 0
-
-#endif /* CONFIG_PPC_ISERIES */
-
/* Secondary processors spin on this value until it goes to 1. */
.globl __secondary_hold_spinloop
__secondary_hold_spinloop:
@@ -124,6 +95,15 @@ __secondary_hold_spinloop:
__secondary_hold_acknowledge:
.llong 0x0
+#ifdef CONFIG_PPC_ISERIES
+ /*
+ * At offset 0x20, there is a pointer to iSeries LPAR data.
+ * This is required by the hypervisor
+ */
+ . = 0x20
+ .llong hvReleaseData-KERNELBASE
+#endif /* CONFIG_PPC_ISERIES */
+
. = 0x60
/*
* The following code is used on pSeries to hold secondary processors
@@ -152,7 +132,7 @@ _GLOBAL(__secondary_hold)
bne 100b
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
- LOAD_REG_IMMEDIATE(r4, .pSeries_secondary_smp_init)
+ LOAD_REG_IMMEDIATE(r4, .generic_secondary_smp_init)
mtctr r4
mr r3,r24
bctr
@@ -211,6 +191,37 @@ exception_marker:
ori reg,reg,(label)@l; /* virt addr of handler ... */
#endif
+/*
+ * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode.
+ * The firmware calls the registered system_reset_fwnmi and
+ * machine_check_fwnmi handlers in 32bit mode if the cpu happens to run
+ * a 32bit application at the time of the event.
+ * This firmware bug is present on POWER4 and JS20.
+ */
+#define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label) \
+ mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
+ std r9,area+EX_R9(r13); /* save r9 - r12 */ \
+ std r10,area+EX_R10(r13); \
+ std r11,area+EX_R11(r13); \
+ std r12,area+EX_R12(r13); \
+ mfspr r9,SPRN_SPRG1; \
+ std r9,area+EX_R13(r13); \
+ mfcr r9; \
+ clrrdi r12,r13,32; /* get high part of &label */ \
+ mfmsr r10; \
+ /* force 64bit mode */ \
+ li r11,5; /* MSR_SF_LG|MSR_ISF_LG */ \
+ rldimi r10,r11,61,0; /* insert into top 3 bits */ \
+ /* done 64bit mode */ \
+ mfspr r11,SPRN_SRR0; /* save SRR0 */ \
+ LOAD_HANDLER(r12,label) \
+ ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
+ mtspr SPRN_SRR0,r12; \
+ mfspr r12,SPRN_SRR1; /* and SRR1 */ \
+ mtspr SPRN_SRR1,r10; \
+ rfid; \
+ b . /* prevent speculative execution */
+
#define EXCEPTION_PROLOG_PSERIES(area, label) \
mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
std r9,area+EX_R9(r13); /* save r9 - r12 */ \
@@ -624,14 +635,14 @@ slb_miss_user_pseries:
system_reset_fwnmi:
HMT_MEDIUM
mtspr SPRN_SPRG1,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
+ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi
.align 7
machine_check_fwnmi:
HMT_MEDIUM
mtspr SPRN_SPRG1,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+ EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common)
#ifdef CONFIG_PPC_ISERIES
/*** ISeries-LPAR interrupt handlers ***/
@@ -1473,19 +1484,17 @@ fwnmi_data_area:
. = 0x8000
/*
- * On pSeries, secondary processors spin in the following code.
+ * On pSeries and most other platforms, secondary processors spin
+ * in the following code.
* At entry, r3 = this processor's number (physical cpu id)
*/
-_GLOBAL(pSeries_secondary_smp_init)
+_GLOBAL(generic_secondary_smp_init)
mr r24,r3
/* turn on 64-bit mode */
bl .enable_64b_mode
isync
- /* Copy some CPU settings from CPU 0 */
- bl .__restore_cpu_setup
-
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
* which logical id maps to our physical one.
@@ -1511,15 +1520,28 @@ _GLOBAL(pSeries_secondary_smp_init)
/* start. */
sync
- /* Create a temp kernel stack for use before relocation is on. */
+#ifndef CONFIG_SMP
+ b 3b /* Never go on non-SMP */
+#else
+ cmpwi 0,r23,0
+ beq 3b /* Loop until told to go */
+
+ /* See if we need to call a cpu state restore handler */
+ LOAD_REG_IMMEDIATE(r23, cur_cpu_spec)
+ ld r23,0(r23)
+ ld r23,CPU_SPEC_RESTORE(r23)
+ cmpdi 0,r23,0
+ beq 4f
+ ld r23,0(r23)
+ mtctr r23
+ bctrl
+
+4: /* Create a temp kernel stack for use before relocation is on. */
ld r1,PACAEMERGSP(r13)
subi r1,r1,STACK_FRAME_OVERHEAD
- cmpwi 0,r23,0
-#ifdef CONFIG_SMP
- bne .__secondary_start
+ b .__secondary_start
#endif
- b 3b /* Loop until told to go */
#ifdef CONFIG_PPC_ISERIES
_STATIC(__start_initialization_iSeries)
@@ -1600,10 +1622,16 @@ _GLOBAL(__start_initialization_multiplatform)
bl .enable_64b_mode
/* Setup some critical 970 SPRs before switching MMU off */
- bl .__970_cpu_preinit
-
- /* cpu # */
- li r24,0
+ mfspr r0,SPRN_PVR
+ srwi r0,r0,16
+ cmpwi r0,0x39 /* 970 */
+ beq 1f
+ cmpwi r0,0x3c /* 970FX */
+ beq 1f
+ cmpwi r0,0x44 /* 970MP */
+ bne 2f
+1: bl .__cpu_preinit_ppc970
+2:
/* Switch off MMU if not already */
LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
@@ -1683,6 +1711,9 @@ _STATIC(__after_prom_start)
/* i.e. where we are running */
/* the source addr */
+ cmpdi r4,0 /* In some cases the loader may */
+ beq .start_here_multiplatform /* have already put us at zero */
+ /* so we can skip the copy. */
LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
sub r5,r5,r27
@@ -1717,7 +1748,7 @@ _STATIC(__after_prom_start)
_GLOBAL(copy_and_flush)
addi r5,r5,-8
addi r6,r6,-8
-4: li r0,16 /* Use the least common */
+4: li r0,8 /* Use the smallest common */
/* denominator cache line */
/* size. This results in */
/* extra cache line flushes */
@@ -1771,7 +1802,7 @@ _GLOBAL(pmac_secondary_start)
isync
/* Copy some CPU settings from CPU 0 */
- bl .__restore_cpu_setup
+ bl .__restore_cpu_ppc970
/* pSeries do that early though I don't think we really need it */
mfmsr r3
@@ -1921,12 +1952,6 @@ _STATIC(start_here_multiplatform)
mr r5,r26
bl .identify_cpu
- /* Save some low level config HIDs of CPU0 to be copied to
- * other CPUs later on, or used for suspend/resume
- */
- bl .__save_cpu_setup
- sync
-
/* Do very early kernel initializations, including initial hash table,
* stab and slb setup before we turn on relocation. */
@@ -1962,14 +1987,6 @@ _STATIC(start_here_common)
li r3,0
bl .do_cpu_ftr_fixups
- LOAD_REG_IMMEDIATE(r26, boot_cpuid)
- lwz r26,0(r26)
-
- LOAD_REG_IMMEDIATE(r24, paca) /* Get base vaddr of paca array */
- mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */
- add r13,r13,r24 /* for this processor. */
- mtspr SPRN_SPRG3,r13
-
/* ptr to current */
LOAD_REG_IMMEDIATE(r4, init_task)
std r4,PACACURRENT(r13)
@@ -1995,17 +2012,6 @@ _STATIC(start_here_common)
/* Not reached */
BUG_OPCODE
-/* Put the paca pointer into r13 and SPRG3 */
-_GLOBAL(setup_boot_paca)
- LOAD_REG_IMMEDIATE(r3, boot_cpuid)
- lwz r3,0(r3)
- LOAD_REG_IMMEDIATE(r4, paca) /* Get base vaddr of paca array */
- mulli r3,r3,PACA_SIZE /* Calculate vaddr of right paca */
- add r13,r3,r4 /* for this processor. */
- mtspr SPRN_SPRG3,r13
-
- blr
-
/*
* We put a few things here that have to be page-aligned.
* This stuff goes at the beginning of the bss, which is page-aligned.
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 28941f5ce673..901be47a02a9 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index dd86bbed7627..66877bdfe0b7 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -30,7 +30,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index e47d40ac6f39..124dbcba94a8 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -167,7 +167,7 @@ static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
NULL);
static struct ibmebus_dev* __devinit ibmebus_register_device_common(
- struct ibmebus_dev *dev, char *name)
+ struct ibmebus_dev *dev, const char *name)
{
int err = 0;
@@ -194,10 +194,10 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
struct device_node *dn)
{
struct ibmebus_dev *dev;
- char *loc_code;
+ const char *loc_code;
int length;
- loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
+ loc_code = get_property(dn, "ibm,loc-code", NULL);
if (!loc_code) {
printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
__FUNCTION__, dn->name ? dn->name : "<unknown>");
@@ -323,13 +323,11 @@ int ibmebus_request_irq(struct ibmebus_dev *dev,
unsigned long irq_flags, const char * devname,
void *dev_id)
{
- unsigned int irq = virt_irq_create_mapping(ist);
+ unsigned int irq = irq_create_mapping(NULL, ist);
if (irq == NO_IRQ)
return -EINVAL;
- irq = irq_offset_up(irq);
-
return request_irq(irq, handler,
irq_flags, devname, dev_id);
}
@@ -337,12 +335,9 @@ EXPORT_SYMBOL(ibmebus_request_irq);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
{
- unsigned int irq = virt_irq_create_mapping(ist);
+ unsigned int irq = irq_find_mapping(NULL, ist);
- irq = irq_offset_up(irq);
free_irq(irq, dev_id);
-
- return;
}
EXPORT_SYMBOL(ibmebus_free_irq);
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index d491052c8e0c..4180c3998b39 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -19,7 +19,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/smp.h>
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index b45fa0e37212..01bcd52bbf8e 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -13,7 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/threads.h>
#include <asm/reg.h>
#include <asm/page.h>
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index d85c7c938eed..30de81da7b40 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -7,7 +7,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c
new file mode 100644
index 000000000000..e98180686b35
--- /dev/null
+++ b/arch/powerpc/kernel/io.c
@@ -0,0 +1,131 @@
+/*
+ * I/O string operations
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
+ *
+ * Rewritten in C by Stephen Rothwell.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/firmware.h>
+#include <asm/bug.h>
+
+void _insb(volatile u8 __iomem *port, void *buf, long count)
+{
+ u8 *tbuf = buf;
+ u8 tmp;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ tmp = *port;
+ asm volatile("eieio");
+ *tbuf++ = tmp;
+ } while (--count != 0);
+ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
+}
+EXPORT_SYMBOL(_insb);
+
+void _outsb(volatile u8 __iomem *port, const void *buf, long count)
+{
+ const u8 *tbuf = buf;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ *port = *tbuf++;
+ } while (--count != 0);
+ asm volatile("sync");
+}
+EXPORT_SYMBOL(_outsb);
+
+void _insw_ns(volatile u16 __iomem *port, void *buf, long count)
+{
+ u16 *tbuf = buf;
+ u16 tmp;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ tmp = *port;
+ asm volatile("eieio");
+ *tbuf++ = tmp;
+ } while (--count != 0);
+ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
+}
+EXPORT_SYMBOL(_insw_ns);
+
+void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count)
+{
+ const u16 *tbuf = buf;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ *port = *tbuf++;
+ } while (--count != 0);
+ asm volatile("sync");
+}
+EXPORT_SYMBOL(_outsw_ns);
+
+void _insl_ns(volatile u32 __iomem *port, void *buf, long count)
+{
+ u32 *tbuf = buf;
+ u32 tmp;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ tmp = *port;
+ asm volatile("eieio");
+ *tbuf++ = tmp;
+ } while (--count != 0);
+ asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
+}
+EXPORT_SYMBOL(_insl_ns);
+
+void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count)
+{
+ const u32 *tbuf = buf;
+
+ BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES));
+
+ if (unlikely(count <= 0))
+ return;
+ asm volatile("sync");
+ do {
+ *port = *tbuf++;
+ } while (--count != 0);
+ asm volatile("sync");
+}
+EXPORT_SYMBOL(_outsl_ns);
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 7cb77c20fc5d..ba0694071728 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -23,7 +23,6 @@
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -38,6 +37,7 @@
#include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
+#include <asm/kdump.h>
#define DBG(...)
@@ -440,8 +440,37 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
tbl->it_largehint = tbl->it_halfpoint;
spin_lock_init(&tbl->it_lock);
+#ifdef CONFIG_CRASH_DUMP
+ if (ppc_md.tce_get) {
+ unsigned long index, tceval;
+ unsigned long tcecount = 0;
+
+ /*
+ * Reserve the existing mappings left by the first kernel.
+ */
+ for (index = 0; index < tbl->it_size; index++) {
+ tceval = ppc_md.tce_get(tbl, index + tbl->it_offset);
+ /*
+ * Freed TCE entry contains 0x7fffffffffffffff on JS20
+ */
+ if (tceval && (tceval != 0x7fffffffffffffffUL)) {
+ __set_bit(index, tbl->it_map);
+ tcecount++;
+ }
+ }
+ if ((tbl->it_size - tcecount) < KDUMP_MIN_TCE_ENTRIES) {
+ printk(KERN_WARNING "TCE table is full; ");
+ printk(KERN_WARNING "freeing %d entries for the kdump boot\n",
+ KDUMP_MIN_TCE_ENTRIES);
+ for (index = tbl->it_size - KDUMP_MIN_TCE_ENTRIES;
+ index < tbl->it_size; index++)
+ __clear_bit(index, tbl->it_map);
+ }
+ }
+#else
/* Clear the hardware table in case firmware left allocations in it */
ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
+#endif
if (!welcomed) {
printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 40d4c14fde8f..b4432332341f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -29,6 +29,8 @@
* to reduce code space and undefined function references.
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/threads.h>
#include <linux/kernel_stat.h>
@@ -38,7 +40,6 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -47,6 +48,10 @@
#include <linux/cpumask.h>
#include <linux/profile.h>
#include <linux/bitops.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <linux/mutex.h>
+#include <linux/bootmem.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
@@ -58,39 +63,38 @@
#include <asm/prom.h>
#include <asm/ptrace.h>
#include <asm/machdep.h>
+#include <asm/udbg.h>
#ifdef CONFIG_PPC_ISERIES
#include <asm/paca.h>
#endif
int __irq_offset_value;
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(__irq_offset_value);
-#endif
-
static int ppc_spurious_interrupts;
#ifdef CONFIG_PPC32
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+EXPORT_SYMBOL(__irq_offset_value);
+atomic_t ppc_n_lost_interrupts;
+#ifndef CONFIG_PPC_MERGE
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
-atomic_t ppc_n_lost_interrupts;
+#endif
#ifdef CONFIG_TAU_INT
extern int tau_initialized;
extern int tau_interrupts(int);
#endif
+#endif /* CONFIG_PPC32 */
#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
extern atomic_t ipi_recv;
extern atomic_t ipi_sent;
#endif
-#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
EXPORT_SYMBOL(irq_desc);
int distribute_irqs = 1;
-u64 ppc64_interrupt_controller;
#endif /* CONFIG_PPC64 */
int show_interrupts(struct seq_file *p, void *v)
@@ -120,8 +124,8 @@ int show_interrupts(struct seq_file *p, void *v)
#else
seq_printf(p, "%10u ", kstat_irqs(i));
#endif /* CONFIG_SMP */
- if (desc->handler)
- seq_printf(p, " %s ", desc->handler->typename);
+ if (desc->chip)
+ seq_printf(p, " %s ", desc->chip->typename);
else
seq_puts(p, " None ");
seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge ");
@@ -164,13 +168,13 @@ void fixup_irqs(cpumask_t map)
if (irq_desc[irq].status & IRQ_PER_CPU)
continue;
- cpus_and(mask, irq_affinity[irq], map);
+ cpus_and(mask, irq_desc[irq].affinity, map);
if (any_online_cpu(mask) == NR_CPUS) {
printk("Breaking affinity for irq %i\n", irq);
mask = map;
}
- if (irq_desc[irq].handler->set_affinity)
- irq_desc[irq].handler->set_affinity(irq, mask);
+ if (irq_desc[irq].chip->set_affinity)
+ irq_desc[irq].chip->set_affinity(irq, mask);
else if (irq_desc[irq].action && !(warned++))
printk("Cannot set affinity for irq %i\n", irq);
}
@@ -183,7 +187,7 @@ void fixup_irqs(cpumask_t map)
void do_IRQ(struct pt_regs *regs)
{
- int irq;
+ unsigned int irq;
#ifdef CONFIG_IRQSTACKS
struct thread_info *curtp, *irqtp;
#endif
@@ -214,22 +218,26 @@ void do_IRQ(struct pt_regs *regs)
*/
irq = ppc_md.get_irq(regs);
- if (irq >= 0) {
+ if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
#ifdef CONFIG_IRQSTACKS
/* Switch to the irq stack to handle this */
curtp = current_thread_info();
irqtp = hardirq_ctx[smp_processor_id()];
if (curtp != irqtp) {
+ struct irq_desc *desc = irq_desc + irq;
+ void *handler = desc->handle_irq;
+ if (handler == NULL)
+ handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
- call___do_IRQ(irq, regs, irqtp);
+ call_handle_irq(irq, desc, regs, irqtp, handler);
irqtp->task = NULL;
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
#endif
- __do_IRQ(irq, regs);
- } else if (irq != -2)
+ generic_handle_irq(irq, regs);
+ } else if (irq != NO_IRQ_IGNORE)
/* That's not SMP safe ... but who cares ? */
ppc_spurious_interrupts++;
@@ -246,196 +254,619 @@ void do_IRQ(struct pt_regs *regs)
void __init init_IRQ(void)
{
+ ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
- static int once = 0;
+ irq_ctx_init();
+#endif
+}
+
+
+#ifdef CONFIG_IRQSTACKS
+struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
+struct thread_info *hardirq_ctx[NR_CPUS] __read_mostly;
+
+void irq_ctx_init(void)
+{
+ struct thread_info *tp;
+ int i;
+
+ for_each_possible_cpu(i) {
+ memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
+ tp = softirq_ctx[i];
+ tp->cpu = i;
+ tp->preempt_count = SOFTIRQ_OFFSET;
+
+ memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
+ tp = hardirq_ctx[i];
+ tp->cpu = i;
+ tp->preempt_count = HARDIRQ_OFFSET;
+ }
+}
+
+static inline void do_softirq_onstack(void)
+{
+ struct thread_info *curtp, *irqtp;
+
+ curtp = current_thread_info();
+ irqtp = softirq_ctx[smp_processor_id()];
+ irqtp->task = curtp->task;
+ call_do_softirq(irqtp);
+ irqtp->task = NULL;
+}
+
+#else
+#define do_softirq_onstack() __do_softirq()
+#endif /* CONFIG_IRQSTACKS */
- if (once)
+void do_softirq(void)
+{
+ unsigned long flags;
+
+ if (in_interrupt())
return;
- once++;
+ local_irq_save(flags);
+
+ if (local_softirq_pending())
+ do_softirq_onstack();
-#endif
- ppc_md.init_IRQ();
-#ifdef CONFIG_PPC64
- irq_ctx_init();
-#endif
+ local_irq_restore(flags);
}
+EXPORT_SYMBOL(do_softirq);
+
-#ifdef CONFIG_PPC64
/*
- * Virtual IRQ mapping code, used on systems with XICS interrupt controllers.
+ * IRQ controller and virtual interrupts
*/
-#define UNDEFINED_IRQ 0xffffffff
-unsigned int virt_irq_to_real_map[NR_IRQS];
+#ifdef CONFIG_PPC_MERGE
-/*
- * Don't use virtual irqs 0, 1, 2 for devices.
- * The pcnet32 driver considers interrupt numbers < 2 to be invalid,
- * and 2 is the XICS IPI interrupt.
- * We limit virtual irqs to __irq_offet_value less than virt_irq_max so
- * that when we offset them we don't end up with an interrupt
- * number >= virt_irq_max.
- */
-#define MIN_VIRT_IRQ 3
+static LIST_HEAD(irq_hosts);
+static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
+static unsigned int irq_radix_writer;
+struct irq_map_entry irq_map[NR_IRQS];
+static unsigned int irq_virq_count = NR_IRQS;
+static struct irq_host *irq_default_host;
+
+struct irq_host *irq_alloc_host(unsigned int revmap_type,
+ unsigned int revmap_arg,
+ struct irq_host_ops *ops,
+ irq_hw_number_t inval_irq)
+{
+ struct irq_host *host;
+ unsigned int size = sizeof(struct irq_host);
+ unsigned int i;
+ unsigned int *rmap;
+ unsigned long flags;
+
+ /* Allocate structure and revmap table if using linear mapping */
+ if (revmap_type == IRQ_HOST_MAP_LINEAR)
+ size += revmap_arg * sizeof(unsigned int);
+ if (mem_init_done)
+ host = kzalloc(size, GFP_KERNEL);
+ else {
+ host = alloc_bootmem(size);
+ if (host)
+ memset(host, 0, size);
+ }
+ if (host == NULL)
+ return NULL;
-unsigned int virt_irq_max;
-static unsigned int max_virt_irq;
-static unsigned int nr_virt_irqs;
+ /* Fill structure */
+ host->revmap_type = revmap_type;
+ host->inval_irq = inval_irq;
+ host->ops = ops;
-void
-virt_irq_init(void)
+ spin_lock_irqsave(&irq_big_lock, flags);
+
+ /* If it's a legacy controller, check for duplicates and
+ * mark it as allocated (we use irq 0 host pointer for that
+ */
+ if (revmap_type == IRQ_HOST_MAP_LEGACY) {
+ if (irq_map[0].host != NULL) {
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+ /* If we are early boot, we can't free the structure,
+ * too bad...
+ * this will be fixed once slab is made available early
+ * instead of the current cruft
+ */
+ if (mem_init_done)
+ kfree(host);
+ return NULL;
+ }
+ irq_map[0].host = host;
+ }
+
+ list_add(&host->link, &irq_hosts);
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+
+ /* Additional setups per revmap type */
+ switch(revmap_type) {
+ case IRQ_HOST_MAP_LEGACY:
+ /* 0 is always the invalid number for legacy */
+ host->inval_irq = 0;
+ /* setup us as the host for all legacy interrupts */
+ for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
+ irq_map[i].hwirq = 0;
+ smp_wmb();
+ irq_map[i].host = host;
+ smp_wmb();
+
+ /* Clear norequest flags */
+ get_irq_desc(i)->status &= ~IRQ_NOREQUEST;
+
+ /* Legacy flags are left to default at this point,
+ * one can then use irq_create_mapping() to
+ * explicitely change them
+ */
+ ops->map(host, i, i);
+ }
+ break;
+ case IRQ_HOST_MAP_LINEAR:
+ rmap = (unsigned int *)(host + 1);
+ for (i = 0; i < revmap_arg; i++)
+ rmap[i] = IRQ_NONE;
+ host->revmap_data.linear.size = revmap_arg;
+ smp_wmb();
+ host->revmap_data.linear.revmap = rmap;
+ break;
+ default:
+ break;
+ }
+
+ pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
+
+ return host;
+}
+
+struct irq_host *irq_find_host(struct device_node *node)
{
- int i;
+ struct irq_host *h, *found = NULL;
+ unsigned long flags;
- if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1)))
- virt_irq_max = NR_IRQS - 1;
- max_virt_irq = virt_irq_max - __irq_offset_value;
- nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1;
+ /* We might want to match the legacy controller last since
+ * it might potentially be set to match all interrupts in
+ * the absence of a device node. This isn't a problem so far
+ * yet though...
+ */
+ spin_lock_irqsave(&irq_big_lock, flags);
+ list_for_each_entry(h, &irq_hosts, link)
+ if (h->ops->match == NULL || h->ops->match(h, node)) {
+ found = h;
+ break;
+ }
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+ return found;
+}
+EXPORT_SYMBOL_GPL(irq_find_host);
- for (i = 0; i < NR_IRQS; i++)
- virt_irq_to_real_map[i] = UNDEFINED_IRQ;
+void irq_set_default_host(struct irq_host *host)
+{
+ pr_debug("irq: Default host set to @0x%p\n", host);
+
+ irq_default_host = host;
}
-/* Create a mapping for a real_irq if it doesn't already exist.
- * Return the virtual irq as a convenience.
+void irq_set_virq_count(unsigned int count)
+{
+ pr_debug("irq: Trying to set virq count to %d\n", count);
+
+ BUG_ON(count < NUM_ISA_INTERRUPTS);
+ if (count < NR_IRQS)
+ irq_virq_count = count;
+}
+
+/* radix tree not lockless safe ! we use a brlock-type mecanism
+ * for now, until we can use a lockless radix tree
*/
-int virt_irq_create_mapping(unsigned int real_irq)
+static void irq_radix_wrlock(unsigned long *flags)
{
- unsigned int virq, first_virq;
- static int warned;
+ unsigned int cpu, ok;
- if (ppc64_interrupt_controller == IC_OPEN_PIC)
- return real_irq; /* no mapping for openpic (for now) */
+ spin_lock_irqsave(&irq_big_lock, *flags);
+ irq_radix_writer = 1;
+ smp_mb();
+ do {
+ barrier();
+ ok = 1;
+ for_each_possible_cpu(cpu) {
+ if (per_cpu(irq_radix_reader, cpu)) {
+ ok = 0;
+ break;
+ }
+ }
+ if (!ok)
+ cpu_relax();
+ } while(!ok);
+}
- if (ppc64_interrupt_controller == IC_CELL_PIC)
- return real_irq; /* no mapping for iic either */
+static void irq_radix_wrunlock(unsigned long flags)
+{
+ smp_wmb();
+ irq_radix_writer = 0;
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+}
- /* don't map interrupts < MIN_VIRT_IRQ */
- if (real_irq < MIN_VIRT_IRQ) {
- virt_irq_to_real_map[real_irq] = real_irq;
- return real_irq;
+static void irq_radix_rdlock(unsigned long *flags)
+{
+ local_irq_save(*flags);
+ __get_cpu_var(irq_radix_reader) = 1;
+ smp_mb();
+ if (likely(irq_radix_writer == 0))
+ return;
+ __get_cpu_var(irq_radix_reader) = 0;
+ smp_wmb();
+ spin_lock(&irq_big_lock);
+ __get_cpu_var(irq_radix_reader) = 1;
+ spin_unlock(&irq_big_lock);
+}
+
+static void irq_radix_rdunlock(unsigned long flags)
+{
+ __get_cpu_var(irq_radix_reader) = 0;
+ local_irq_restore(flags);
+}
+
+
+unsigned int irq_create_mapping(struct irq_host *host,
+ irq_hw_number_t hwirq)
+{
+ unsigned int virq, hint;
+
+ pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
+
+ /* Look for default host if nececssary */
+ if (host == NULL)
+ host = irq_default_host;
+ if (host == NULL) {
+ printk(KERN_WARNING "irq_create_mapping called for"
+ " NULL host, hwirq=%lx\n", hwirq);
+ WARN_ON(1);
+ return NO_IRQ;
}
+ pr_debug("irq: -> using host @%p\n", host);
- /* map to a number between MIN_VIRT_IRQ and max_virt_irq */
- virq = real_irq;
- if (virq > max_virt_irq)
- virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
-
- /* search for this number or a free slot */
- first_virq = virq;
- while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) {
- if (virt_irq_to_real_map[virq] == real_irq)
- return virq;
- if (++virq > max_virt_irq)
- virq = MIN_VIRT_IRQ;
- if (virq == first_virq)
- goto nospace; /* oops, no free slots */
+ /* Check if mapping already exist, if it does, call
+ * host->ops->map() to update the flags
+ */
+ virq = irq_find_mapping(host, hwirq);
+ if (virq != IRQ_NONE) {
+ pr_debug("irq: -> existing mapping on virq %d\n", virq);
+ return virq;
}
- virt_irq_to_real_map[virq] = real_irq;
+ /* Get a virtual interrupt number */
+ if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {
+ /* Handle legacy */
+ virq = (unsigned int)hwirq;
+ if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
+ return NO_IRQ;
+ return virq;
+ } else {
+ /* Allocate a virtual interrupt number */
+ hint = hwirq % irq_virq_count;
+ virq = irq_alloc_virt(host, 1, hint);
+ if (virq == NO_IRQ) {
+ pr_debug("irq: -> virq allocation failed\n");
+ return NO_IRQ;
+ }
+ }
+ pr_debug("irq: -> obtained virq %d\n", virq);
+
+ /* Clear IRQ_NOREQUEST flag */
+ get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
+
+ /* map it */
+ smp_wmb();
+ irq_map[virq].hwirq = hwirq;
+ smp_mb();
+ if (host->ops->map(host, virq, hwirq)) {
+ pr_debug("irq: -> mapping failed, freeing\n");
+ irq_free_virt(virq, 1);
+ return NO_IRQ;
+ }
return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_mapping);
- nospace:
- if (!warned) {
- printk(KERN_CRIT "Interrupt table is full\n");
- printk(KERN_CRIT "Increase virt_irq_max (currently %d) "
- "in your kernel sources and rebuild.\n", virt_irq_max);
- warned = 1;
+extern unsigned int irq_create_of_mapping(struct device_node *controller,
+ u32 *intspec, unsigned int intsize)
+{
+ struct irq_host *host;
+ irq_hw_number_t hwirq;
+ unsigned int type = IRQ_TYPE_NONE;
+ unsigned int virq;
+
+ if (controller == NULL)
+ host = irq_default_host;
+ else
+ host = irq_find_host(controller);
+ if (host == NULL) {
+ printk(KERN_WARNING "irq: no irq host found for %s !\n",
+ controller->full_name);
+ return NO_IRQ;
}
- return NO_IRQ;
+
+ /* If host has no translation, then we assume interrupt line */
+ if (host->ops->xlate == NULL)
+ hwirq = intspec[0];
+ else {
+ if (host->ops->xlate(host, controller, intspec, intsize,
+ &hwirq, &type))
+ return NO_IRQ;
+ }
+
+ /* Create mapping */
+ virq = irq_create_mapping(host, hwirq);
+ if (virq == NO_IRQ)
+ return virq;
+
+ /* Set type if specified and different than the current one */
+ if (type != IRQ_TYPE_NONE &&
+ type != (get_irq_desc(virq)->status & IRQF_TRIGGER_MASK))
+ set_irq_type(virq, type);
+ return virq;
}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-/*
- * In most cases will get a hit on the very first slot checked in the
- * virt_irq_to_real_map. Only when there are a large number of
- * IRQs will this be expensive.
- */
-unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
+unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
- unsigned int virq;
- unsigned int first_virq;
+ struct of_irq oirq;
- virq = real_irq;
+ if (of_irq_map_one(dev, index, &oirq))
+ return NO_IRQ;
- if (virq > max_virt_irq)
- virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ;
+ return irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+}
+EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
- first_virq = virq;
+void irq_dispose_mapping(unsigned int virq)
+{
+ struct irq_host *host = irq_map[virq].host;
+ irq_hw_number_t hwirq;
+ unsigned long flags;
- do {
- if (virt_irq_to_real_map[virq] == real_irq)
- return virq;
+ WARN_ON (host == NULL);
+ if (host == NULL)
+ return;
- virq++;
+ /* Never unmap legacy interrupts */
+ if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
+ return;
- if (virq >= max_virt_irq)
- virq = 0;
+ /* remove chip and handler */
+ set_irq_chip_and_handler(virq, NULL, NULL);
+
+ /* Make sure it's completed */
+ synchronize_irq(virq);
+
+ /* Tell the PIC about it */
+ if (host->ops->unmap)
+ host->ops->unmap(host, virq);
+ smp_mb();
+
+ /* Clear reverse map */
+ hwirq = irq_map[virq].hwirq;
+ switch(host->revmap_type) {
+ case IRQ_HOST_MAP_LINEAR:
+ if (hwirq < host->revmap_data.linear.size)
+ host->revmap_data.linear.revmap[hwirq] = IRQ_NONE;
+ break;
+ case IRQ_HOST_MAP_TREE:
+ /* Check if radix tree allocated yet */
+ if (host->revmap_data.tree.gfp_mask == 0)
+ break;
+ irq_radix_wrlock(&flags);
+ radix_tree_delete(&host->revmap_data.tree, hwirq);
+ irq_radix_wrunlock(flags);
+ break;
+ }
- } while (first_virq != virq);
+ /* Destroy map */
+ smp_mb();
+ irq_map[virq].hwirq = host->inval_irq;
- return NO_IRQ;
+ /* Set some flags */
+ get_irq_desc(virq)->status |= IRQ_NOREQUEST;
+ /* Free it */
+ irq_free_virt(virq, 1);
}
-#endif /* CONFIG_PPC64 */
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-#ifdef CONFIG_IRQSTACKS
-struct thread_info *softirq_ctx[NR_CPUS] __read_mostly;
-struct thread_info *hardirq_ctx[NR_CPUS] __read_mostly;
+unsigned int irq_find_mapping(struct irq_host *host,
+ irq_hw_number_t hwirq)
+{
+ unsigned int i;
+ unsigned int hint = hwirq % irq_virq_count;
+
+ /* Look for default host if nececssary */
+ if (host == NULL)
+ host = irq_default_host;
+ if (host == NULL)
+ return NO_IRQ;
+
+ /* legacy -> bail early */
+ if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
+ return hwirq;
+
+ /* Slow path does a linear search of the map */
+ if (hint < NUM_ISA_INTERRUPTS)
+ hint = NUM_ISA_INTERRUPTS;
+ i = hint;
+ do {
+ if (irq_map[i].host == host &&
+ irq_map[i].hwirq == hwirq)
+ return i;
+ i++;
+ if (i >= irq_virq_count)
+ i = NUM_ISA_INTERRUPTS;
+ } while(i != hint);
+ return NO_IRQ;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping);
-void irq_ctx_init(void)
+
+unsigned int irq_radix_revmap(struct irq_host *host,
+ irq_hw_number_t hwirq)
{
- struct thread_info *tp;
- int i;
+ struct radix_tree_root *tree;
+ struct irq_map_entry *ptr;
+ unsigned int virq;
+ unsigned long flags;
- for_each_possible_cpu(i) {
- memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
- tp = softirq_ctx[i];
- tp->cpu = i;
- tp->preempt_count = SOFTIRQ_OFFSET;
+ WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
- memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
- tp = hardirq_ctx[i];
- tp->cpu = i;
- tp->preempt_count = HARDIRQ_OFFSET;
+ /* Check if the radix tree exist yet. We test the value of
+ * the gfp_mask for that. Sneaky but saves another int in the
+ * structure. If not, we fallback to slow mode
+ */
+ tree = &host->revmap_data.tree;
+ if (tree->gfp_mask == 0)
+ return irq_find_mapping(host, hwirq);
+
+ /* Now try to resolve */
+ irq_radix_rdlock(&flags);
+ ptr = radix_tree_lookup(tree, hwirq);
+ irq_radix_rdunlock(flags);
+
+ /* Found it, return */
+ if (ptr) {
+ virq = ptr - irq_map;
+ return virq;
}
+
+ /* If not there, try to insert it */
+ virq = irq_find_mapping(host, hwirq);
+ if (virq != NO_IRQ) {
+ irq_radix_wrlock(&flags);
+ radix_tree_insert(tree, hwirq, &irq_map[virq]);
+ irq_radix_wrunlock(flags);
+ }
+ return virq;
}
-static inline void do_softirq_onstack(void)
+unsigned int irq_linear_revmap(struct irq_host *host,
+ irq_hw_number_t hwirq)
{
- struct thread_info *curtp, *irqtp;
+ unsigned int *revmap;
- curtp = current_thread_info();
- irqtp = softirq_ctx[smp_processor_id()];
- irqtp->task = curtp->task;
- call_do_softirq(irqtp);
- irqtp->task = NULL;
+ WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);
+
+ /* Check revmap bounds */
+ if (unlikely(hwirq >= host->revmap_data.linear.size))
+ return irq_find_mapping(host, hwirq);
+
+ /* Check if revmap was allocated */
+ revmap = host->revmap_data.linear.revmap;
+ if (unlikely(revmap == NULL))
+ return irq_find_mapping(host, hwirq);
+
+ /* Fill up revmap with slow path if no mapping found */
+ if (unlikely(revmap[hwirq] == NO_IRQ))
+ revmap[hwirq] = irq_find_mapping(host, hwirq);
+
+ return revmap[hwirq];
}
-#else
-#define do_softirq_onstack() __do_softirq()
-#endif /* CONFIG_IRQSTACKS */
+unsigned int irq_alloc_virt(struct irq_host *host,
+ unsigned int count,
+ unsigned int hint)
+{
+ unsigned long flags;
+ unsigned int i, j, found = NO_IRQ;
+ unsigned int limit = irq_virq_count - count;
-void do_softirq(void)
+ if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
+ return NO_IRQ;
+
+ spin_lock_irqsave(&irq_big_lock, flags);
+
+ /* Use hint for 1 interrupt if any */
+ if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
+ hint < irq_virq_count && irq_map[hint].host == NULL) {
+ found = hint;
+ goto hint_found;
+ }
+
+ /* Look for count consecutive numbers in the allocatable
+ * (non-legacy) space
+ */
+ for (i = NUM_ISA_INTERRUPTS; i <= limit; ) {
+ for (j = i; j < (i + count); j++)
+ if (irq_map[j].host != NULL) {
+ i = j + 1;
+ continue;
+ }
+ found = i;
+ break;
+ }
+ if (found == NO_IRQ) {
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+ return NO_IRQ;
+ }
+ hint_found:
+ for (i = found; i < (found + count); i++) {
+ irq_map[i].hwirq = host->inval_irq;
+ smp_wmb();
+ irq_map[i].host = host;
+ }
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+ return found;
+}
+
+void irq_free_virt(unsigned int virq, unsigned int count)
{
unsigned long flags;
+ unsigned int i;
- if (in_interrupt())
- return;
+ WARN_ON (virq < NUM_ISA_INTERRUPTS);
+ WARN_ON (count == 0 || (virq + count) > irq_virq_count);
- local_irq_save(flags);
+ spin_lock_irqsave(&irq_big_lock, flags);
+ for (i = virq; i < (virq + count); i++) {
+ struct irq_host *host;
- if (local_softirq_pending()) {
- account_system_vtime(current);
- local_bh_disable();
- do_softirq_onstack();
- account_system_vtime(current);
- __local_bh_enable();
+ if (i < NUM_ISA_INTERRUPTS ||
+ (virq + count) > irq_virq_count)
+ continue;
+
+ host = irq_map[i].host;
+ irq_map[i].hwirq = host->inval_irq;
+ smp_wmb();
+ irq_map[i].host = NULL;
}
+ spin_unlock_irqrestore(&irq_big_lock, flags);
+}
- local_irq_restore(flags);
+void irq_early_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < NR_IRQS; i++)
+ get_irq_desc(i)->status |= IRQ_NOREQUEST;
}
-EXPORT_SYMBOL(do_softirq);
+
+/* We need to create the radix trees late */
+static int irq_late_init(void)
+{
+ struct irq_host *h;
+ unsigned long flags;
+
+ irq_radix_wrlock(&flags);
+ list_for_each_entry(h, &irq_hosts, link) {
+ if (h->revmap_type == IRQ_HOST_MAP_TREE)
+ INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
+ }
+ irq_radix_wrunlock(flags);
+
+ return 0;
+}
+arch_initcall(irq_late_init);
+
+#endif /* CONFIG_PPC_MERGE */
#ifdef CONFIG_PCI_MSI
int pci_enable_msi(struct pci_dev * pdev)
@@ -445,12 +876,14 @@ int pci_enable_msi(struct pci_dev * pdev)
else
return -1;
}
+EXPORT_SYMBOL(pci_enable_msi);
void pci_disable_msi(struct pci_dev * pdev)
{
if (ppc_md.disable_msi)
ppc_md.disable_msi(pdev);
}
+EXPORT_SYMBOL(pci_disable_msi);
void pci_scan_msi_device(struct pci_dev *dev) {}
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
@@ -458,6 +891,8 @@ void pci_disable_msix(struct pci_dev *dev) {}
void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
void pci_no_msi(void) {}
+EXPORT_SYMBOL(pci_enable_msix);
+EXPORT_SYMBOL(pci_disable_msix);
#endif
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index f78866367b70..cd65c367b8b6 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -26,7 +26,6 @@
* for PPC64
*/
-#include <linux/config.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/preempt.h>
@@ -62,6 +61,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
if (!ret) {
memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
+ flush_icache_range((unsigned long)p->ainsn.insn,
+ (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
}
return ret;
diff --git a/arch/powerpc/kernel/l2cr_6xx.S b/arch/powerpc/kernel/l2cr_6xx.S
index d7f4e982b539..858f28ac8a06 100644
--- a/arch/powerpc/kernel/l2cr_6xx.S
+++ b/arch/powerpc/kernel/l2cr_6xx.S
@@ -40,7 +40,6 @@
Author: Terry Greeniaus (tgree@phys.ualberta.ca)
Please e-mail updates to this file to me, thanks!
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/cputable.h>
#include <asm/ppc_asm.h>
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 6e67b5b49ba1..5e6ddfa474c0 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
@@ -29,6 +28,7 @@ static struct legacy_serial_info {
struct device_node *np;
unsigned int speed;
unsigned int clock;
+ int irq_check_parent;
phys_addr_t taddr;
} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
static unsigned int legacy_serial_count;
@@ -37,18 +37,19 @@ static int legacy_serial_console = -1;
static int __init add_legacy_port(struct device_node *np, int want_index,
int iotype, phys_addr_t base,
phys_addr_t taddr, unsigned long irq,
- upf_t flags)
+ upf_t flags, int irq_check_parent)
{
- u32 *clk, *spd, clock = BASE_BAUD * 16;
+ const u32 *clk, *spd;
+ u32 clock = BASE_BAUD * 16;
int index;
/* get clock freq. if present */
- clk = (u32 *)get_property(np, "clock-frequency", NULL);
+ clk = get_property(np, "clock-frequency", NULL);
if (clk && *clk)
clock = *clk;
/* get default speed if present */
- spd = (u32 *)get_property(np, "current-speed", NULL);
+ spd = get_property(np, "current-speed", NULL);
/* If we have a location index, then try to use it */
if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
@@ -69,7 +70,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
if (legacy_serial_infos[index].np != 0) {
/* if we still have some room, move it, else override */
if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
- printk(KERN_INFO "Moved legacy port %d -> %d\n",
+ printk(KERN_DEBUG "Moved legacy port %d -> %d\n",
index, legacy_serial_count);
legacy_serial_ports[legacy_serial_count] =
legacy_serial_ports[index];
@@ -77,7 +78,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
legacy_serial_infos[index];
legacy_serial_count++;
} else {
- printk(KERN_INFO "Replacing legacy port %d\n", index);
+ printk(KERN_DEBUG "Replacing legacy port %d\n", index);
}
}
@@ -96,10 +97,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
legacy_serial_infos[index].np = of_node_get(np);
legacy_serial_infos[index].clock = clock;
legacy_serial_infos[index].speed = spd ? *spd : 0;
+ legacy_serial_infos[index].irq_check_parent = irq_check_parent;
- printk(KERN_INFO "Found legacy serial port %d for %s\n",
+ printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
index, np->full_name);
- printk(KERN_INFO " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
+ printk(KERN_DEBUG " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
(iotype == UPIO_PORT) ? "port" : "mem",
(unsigned long long)base, (unsigned long long)taddr, irq,
legacy_serial_ports[index].uartclk,
@@ -111,9 +113,10 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
static int __init add_legacy_soc_port(struct device_node *np,
struct device_node *soc_dev)
{
- phys_addr_t addr;
- u32 *addrp;
+ u64 addr;
+ const u32 *addrp;
upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ struct device_node *tsi = of_get_parent(np);
/* We only support ports that have a clock frequency properly
* encoded in the device-tree.
@@ -127,23 +130,30 @@ static int __init add_legacy_soc_port(struct device_node *np,
return -1;
addr = of_translate_address(soc_dev, addrp);
+ if (addr == OF_BAD_ADDR)
+ return -1;
/* Add port, irq will be dealt with later. We passed a translated
* IO port value. It will be fixed up later along with the irq
*/
- return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);
+ if (tsi && !strcmp(tsi->type, "tsi-bridge"))
+ return add_legacy_port(np, -1, UPIO_TSI, addr, addr, NO_IRQ, flags, 0);
+ else
+ return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags, 0);
}
static int __init add_legacy_isa_port(struct device_node *np,
struct device_node *isa_brg)
{
- u32 *reg;
- char *typep;
+ const u32 *reg;
+ const char *typep;
int index = -1;
- phys_addr_t taddr;
+ u64 taddr;
+
+ DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
/* Get the ISA port number */
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = get_property(np, "reg", NULL);
if (reg == NULL)
return -1;
@@ -154,17 +164,23 @@ static int __init add_legacy_isa_port(struct device_node *np,
/* Now look for an "ibm,aix-loc" property that gives us ordering
* if any...
*/
- typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+ typep = get_property(np, "ibm,aix-loc", NULL);
/* If we have a location index, then use it */
if (typep && *typep == 'S')
index = simple_strtol(typep+1, NULL, 0) - 1;
- /* Translate ISA address */
+ /* Translate ISA address. If it fails, we still register the port
+ * with no translated address so that it can be picked up as an IO
+ * port later by the serial driver
+ */
taddr = of_translate_address(np, reg);
+ if (taddr == OF_BAD_ADDR)
+ taddr = 0;
/* Add port, irq will be dealt with later */
- return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF);
+ return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+ NO_IRQ, UPF_BOOT_AUTOCONF, 0);
}
@@ -172,11 +188,13 @@ static int __init add_legacy_isa_port(struct device_node *np,
static int __init add_legacy_pci_port(struct device_node *np,
struct device_node *pci_dev)
{
- phys_addr_t addr, base;
- u32 *addrp;
+ u64 addr, base;
+ const u32 *addrp;
unsigned int flags;
int iotype, index = -1, lindex = 0;
+ DBG(" -> add_legacy_pci_port(%s)\n", np->full_name);
+
/* We only support ports that have a clock frequency properly
* encoded in the device-tree (that is have an fcode). Anything
* else can't be used that early and will be normally probed by
@@ -195,6 +213,8 @@ static int __init add_legacy_pci_port(struct device_node *np,
/* We only support BAR 0 for now */
iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
addr = of_translate_address(pci_dev, addrp);
+ if (addr == OF_BAD_ADDR)
+ return -1;
/* Set the IO base to the same as the translated address for MMIO,
* or to the domain local IO base for PIO (it will be fixed up later)
@@ -208,7 +228,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
* we get to their "reg" property
*/
if (np != pci_dev) {
- u32 *reg = (u32 *)get_property(np, "reg", NULL);
+ const u32 *reg = get_property(np, "reg", NULL);
if (reg && (*reg < 4))
index = lindex = *reg;
}
@@ -232,7 +252,8 @@ static int __init add_legacy_pci_port(struct device_node *np,
/* Add port, irq will be dealt with later. We passed a translated
* IO port value. It will be fixed up later along with the irq
*/
- return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF);
+ return add_legacy_port(np, index, iotype, base, addr, NO_IRQ,
+ UPF_BOOT_AUTOCONF, np != pci_dev);
}
#endif
@@ -265,13 +286,13 @@ static void __init setup_legacy_serial_console(int console)
void __init find_legacy_serial_ports(void)
{
struct device_node *np, *stdout = NULL;
- char *path;
+ const char *path;
int index;
DBG(" -> find_legacy_serial_port()\n");
/* Now find out if one of these is out firmware console */
- path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ path = get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL) {
stdout = of_find_node_by_path(path);
if (stdout)
@@ -302,6 +323,17 @@ void __init find_legacy_serial_ports(void)
of_node_put(isa);
}
+ /* First fill our array with tsi-bridge ports */
+ for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) {
+ struct device_node *tsi = of_get_parent(np);
+ if (tsi && !strcmp(tsi->type, "tsi-bridge")) {
+ index = add_legacy_soc_port(np, np);
+ if (index >= 0 && np == stdout)
+ legacy_serial_console = index;
+ }
+ of_node_put(tsi);
+ }
+
#ifdef CONFIG_PCI
/* Next, try to locate PCI ports */
for (np = NULL; (np = of_find_all_nodes(np));) {
@@ -352,27 +384,22 @@ static void __init fixup_port_irq(int index,
struct device_node *np,
struct plat_serial8250_port *port)
{
+ unsigned int virq;
+
DBG("fixup_port_irq(%d)\n", index);
- /* Check for interrupts in that node */
- if (np->n_intrs > 0) {
- port->irq = np->intrs[0].line;
- DBG(" port %d (%s), irq=%d\n",
- index, np->full_name, port->irq);
- return;
+ virq = irq_of_parse_and_map(np, 0);
+ if (virq == NO_IRQ && legacy_serial_infos[index].irq_check_parent) {
+ np = of_get_parent(np);
+ if (np == NULL)
+ return;
+ virq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
}
-
- /* Check for interrupts in the parent */
- np = of_get_parent(np);
- if (np == NULL)
+ if (virq == NO_IRQ)
return;
- if (np->n_intrs > 0) {
- port->irq = np->intrs[0].line;
- DBG(" port %d (%s), irq=%d\n",
- index, np->full_name, port->irq);
- }
- of_node_put(np);
+ port->irq = virq;
}
static void __init fixup_port_pio(int index,
@@ -442,7 +469,7 @@ static int __init serial_dev_init(void)
fixup_port_irq(i, np, port);
if (port->iotype == UPIO_PORT)
fixup_port_pio(i, np, port);
- if (port->iotype == UPIO_MEM)
+ if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_TSI))
fixup_port_mmio(i, np, port);
}
@@ -465,8 +492,8 @@ static int __init check_legacy_serial_console(void)
{
struct device_node *prom_stdout = NULL;
int speed = 0, offset = 0;
- char *name;
- u32 *spd;
+ const char *name;
+ const u32 *spd;
DBG(" -> check_legacy_serial_console()\n");
@@ -487,7 +514,7 @@ static int __init check_legacy_serial_console(void)
}
/* We are getting a weird phandle from OF ... */
/* ... So use the full path instead */
- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+ name = get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL) {
DBG(" no linux,stdout-path !\n");
return -ENODEV;
@@ -499,12 +526,12 @@ static int __init check_legacy_serial_console(void)
}
DBG("stdout is %s\n", prom_stdout->full_name);
- name = (char *)get_property(prom_stdout, "name", NULL);
+ name = get_property(prom_stdout, "name", NULL);
if (!name) {
DBG(" stdout package has no name !\n");
goto not_found;
}
- spd = (u32 *)get_property(prom_stdout, "current-speed", NULL);
+ spd = get_property(prom_stdout, "current-speed", NULL);
if (spd)
speed = *spd;
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index c02deaab26c7..41c05dcd68f4 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -18,7 +18,6 @@
* keyword - value pairs that specify the configuration of the partition.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -33,7 +32,6 @@
#include <asm/rtas.h>
#include <asm/system.h>
#include <asm/time.h>
-#include <asm/iseries/it_exp_vpd_panel.h>
#include <asm/prom.h>
#include <asm/vdso_datapage.h>
@@ -45,11 +43,9 @@
static struct proc_dir_entry *proc_ppc64_lparcfg;
#define LPARCFG_BUFF_SIZE 4096
-#ifdef CONFIG_PPC_ISERIES
-
/*
- * For iSeries legacy systems, the PPA purr function is available from the
- * emulated_time_base field in the paca.
+ * Track sum of all purrs across all processors. This is used to further
+ * calculate usage values by different applications
*/
static unsigned long get_purr(void)
{
@@ -57,48 +53,31 @@ static unsigned long get_purr(void)
int cpu;
for_each_possible_cpu(cpu) {
- sum_purr += lppaca[cpu].emulated_time_base;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ sum_purr += lppaca[cpu].emulated_time_base;
+ else {
+ struct cpu_usage *cu;
-#ifdef PURR_DEBUG
- printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n",
- cpu, lppaca[cpu].emulated_time_base);
-#endif
+ cu = &per_cpu(cpu_usage_array, cpu);
+ sum_purr += cu->current_tb;
+ }
}
return sum_purr;
}
-#define lparcfg_write NULL
+#ifdef CONFIG_PPC_ISERIES
/*
* Methods used to fetch LPAR data when running on an iSeries platform.
*/
-static int lparcfg_data(struct seq_file *m, void *v)
+static int iseries_lparcfg_data(struct seq_file *m, void *v)
{
- unsigned long pool_id, lp_index;
+ unsigned long pool_id;
int shared, entitled_capacity, max_entitled_capacity;
int processors, max_processors;
unsigned long purr = get_purr();
- seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
-
shared = (int)(get_lppaca()->shared_proc);
- seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n",
- e2a(xItExtVpdPanel.mfgID[2]),
- e2a(xItExtVpdPanel.mfgID[3]),
- e2a(xItExtVpdPanel.systemSerial[1]),
- e2a(xItExtVpdPanel.systemSerial[2]),
- e2a(xItExtVpdPanel.systemSerial[3]),
- e2a(xItExtVpdPanel.systemSerial[4]),
- e2a(xItExtVpdPanel.systemSerial[5]));
-
- seq_printf(m, "system_type=%c%c%c%c\n",
- e2a(xItExtVpdPanel.machineType[0]),
- e2a(xItExtVpdPanel.machineType[1]),
- e2a(xItExtVpdPanel.machineType[2]),
- e2a(xItExtVpdPanel.machineType[3]));
-
- lp_index = HvLpConfig_getLpIndex();
- seq_printf(m, "partition_id=%d\n", (int)lp_index);
seq_printf(m, "system_active_processors=%d\n",
(int)HvLpConfig_getSystemPhysicalProcessors());
@@ -137,6 +116,14 @@ static int lparcfg_data(struct seq_file *m, void *v)
return 0;
}
+
+#else /* CONFIG_PPC_ISERIES */
+
+static int iseries_lparcfg_data(struct seq_file *m, void *v)
+{
+ return 0;
+}
+
#endif /* CONFIG_PPC_ISERIES */
#ifdef CONFIG_PPC_PSERIES
@@ -195,8 +182,14 @@ static unsigned int h_get_ppp(unsigned long *entitled,
unsigned long *resource)
{
unsigned long rc;
- rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated,
- aggregation, resource);
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_GET_PPP, retbuf);
+
+ *entitled = retbuf[0];
+ *unallocated = retbuf[1];
+ *aggregation = retbuf[2];
+ *resource = retbuf[3];
log_plpar_hcall_return(rc, "H_GET_PPP");
@@ -206,27 +199,15 @@ static unsigned int h_get_ppp(unsigned long *entitled,
static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
{
unsigned long rc;
- unsigned long dummy;
- rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy);
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
- if (rc != H_AUTHORITY)
- log_plpar_hcall_return(rc, "H_PIC");
-}
+ rc = plpar_hcall(H_PIC, retbuf);
-/* Track sum of all purrs across all processors. This is used to further */
-/* calculate usage values by different applications */
+ *pool_idle_time = retbuf[0];
+ *num_procs = retbuf[1];
-static unsigned long get_purr(void)
-{
- unsigned long sum_purr = 0;
- int cpu;
- struct cpu_usage *cu;
-
- for_each_possible_cpu(cpu) {
- cu = &per_cpu(cpu_usage_array, cpu);
- sum_purr += cu->current_tb;
- }
- return sum_purr;
+ if (rc != H_AUTHORITY)
+ log_plpar_hcall_return(rc, "H_PIC");
}
#define SPLPAR_CHARACTERISTICS_TOKEN 20
@@ -333,39 +314,16 @@ static int lparcfg_count_active_processors(void)
return count;
}
-static int lparcfg_data(struct seq_file *m, void *v)
+static int pseries_lparcfg_data(struct seq_file *m, void *v)
{
int partition_potential_processors;
int partition_active_processors;
- struct device_node *rootdn;
- const char *model = "";
- const char *system_id = "";
- unsigned int *lp_index_ptr, lp_index = 0;
struct device_node *rtas_node;
- int *lrdrp = NULL;
-
- rootdn = find_path_device("/");
- if (rootdn) {
- model = get_property(rootdn, "model", NULL);
- system_id = get_property(rootdn, "system-id", NULL);
- lp_index_ptr = (unsigned int *)
- get_property(rootdn, "ibm,partition-no", NULL);
- if (lp_index_ptr)
- lp_index = *lp_index_ptr;
- }
-
- seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
-
- seq_printf(m, "serial_number=%s\n", system_id);
-
- seq_printf(m, "system_type=%s\n", model);
-
- seq_printf(m, "partition_id=%d\n", (int)lp_index);
+ const int *lrdrp = NULL;
rtas_node = find_path_device("/rtas");
if (rtas_node)
- lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity",
- NULL);
+ lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
if (lrdrp == NULL) {
partition_potential_processors = vdso_data->processorCount;
@@ -549,8 +507,61 @@ out:
return retval;
}
+#else /* CONFIG_PPC_PSERIES */
+
+static int pseries_lparcfg_data(struct seq_file *m, void *v)
+{
+ return 0;
+}
+
+static ssize_t lparcfg_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * off)
+{
+ return count;
+}
+
#endif /* CONFIG_PPC_PSERIES */
+static int lparcfg_data(struct seq_file *m, void *v)
+{
+ struct device_node *rootdn;
+ const char *model = "";
+ const char *system_id = "";
+ const char *tmp;
+ const unsigned int *lp_index_ptr;
+ unsigned int lp_index = 0;
+
+ seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
+
+ rootdn = find_path_device("/");
+ if (rootdn) {
+ tmp = get_property(rootdn, "model", NULL);
+ if (tmp) {
+ model = tmp;
+ /* Skip "IBM," - see platforms/iseries/dt.c */
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ model += 4;
+ }
+ tmp = get_property(rootdn, "system-id", NULL);
+ if (tmp) {
+ system_id = tmp;
+ /* Skip "IBM," - see platforms/iseries/dt.c */
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ system_id += 4;
+ }
+ lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ if (lp_index_ptr)
+ lp_index = *lp_index_ptr;
+ }
+ seq_printf(m, "serial_number=%s\n", system_id);
+ seq_printf(m, "system_type=%s\n", model);
+ seq_printf(m, "partition_id=%d\n", (int)lp_index);
+
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return iseries_lparcfg_data(m, v);
+ return pseries_lparcfg_data(m, v);
+}
+
static int lparcfg_open(struct inode *inode, struct file *file)
{
return single_open(file, lparcfg_data, NULL);
@@ -569,7 +580,8 @@ int __init lparcfg_init(void)
mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
/* Allow writing if we have FW_FEATURE_SPLPAR */
- if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
+ !firmware_has_feature(FW_FEATURE_ISERIES)) {
lparcfg_fops.write = lparcfg_write;
mode |= S_IWUSR;
}
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index a81ca1b841ec..e60a0c544d63 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -13,6 +13,7 @@
#include <linux/reboot.h>
#include <linux/threads.h>
#include <asm/machdep.h>
+#include <asm/lmb.h>
void machine_crash_shutdown(struct pt_regs *regs)
{
@@ -59,3 +60,58 @@ NORET_TYPE void machine_kexec(struct kimage *image)
}
for(;;);
}
+
+static int __init early_parse_crashk(char *p)
+{
+ unsigned long size;
+
+ if (!p)
+ return 1;
+
+ size = memparse(p, &p);
+
+ if (*p == '@')
+ crashk_res.start = memparse(p + 1, &p);
+ else
+ crashk_res.start = KDUMP_KERNELBASE;
+
+ crashk_res.end = crashk_res.start + size - 1;
+
+ return 0;
+}
+early_param("crashkernel", early_parse_crashk);
+
+void __init reserve_crashkernel(void)
+{
+ unsigned long size;
+
+ if (crashk_res.start == 0)
+ return;
+
+ /* We might have got these values via the command line or the
+ * device tree, either way sanitise them now. */
+
+ size = crashk_res.end - crashk_res.start + 1;
+
+ if (crashk_res.start != KDUMP_KERNELBASE)
+ printk("Crash kernel location must be 0x%x\n",
+ KDUMP_KERNELBASE);
+
+ crashk_res.start = KDUMP_KERNELBASE;
+ size = PAGE_ALIGN(size);
+ crashk_res.end = crashk_res.start + size - 1;
+
+ /* Crash kernel trumps memory limit */
+ if (memory_limit && memory_limit <= crashk_res.end) {
+ memory_limit = crashk_res.end + 1;
+ printk("Adjusted memory limit for crashkernel, now 0x%lx\n",
+ memory_limit);
+ }
+
+ lmb_reserve(crashk_res.start, size);
+}
+
+int overlaps_crashkernel(unsigned long start, unsigned long size)
+{
+ return (start + size) > crashk_res.start && start <= crashk_res.end;
+}
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c
index 443606134dff..cbaa34196797 100644
--- a/arch/powerpc/kernel/machine_kexec_32.c
+++ b/arch/powerpc/kernel/machine_kexec_32.c
@@ -30,8 +30,8 @@ typedef NORET_TYPE void (*relocate_new_kernel_t)(
*/
void default_machine_kexec(struct kimage *image)
{
- const extern unsigned char relocate_new_kernel[];
- const extern unsigned int relocate_new_kernel_size;
+ extern const unsigned char relocate_new_kernel[];
+ extern const unsigned int relocate_new_kernel_size;
unsigned long page_list;
unsigned long reboot_code_buffer, reboot_code_buffer_phys;
relocate_new_kernel_t rnk;
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index a8fa04ef27cd..a24b09c27718 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -10,7 +10,6 @@
*/
-#include <linux/cpumask.h>
#include <linux/kexec.h>
#include <linux/smp.h>
#include <linux/thread_info.h>
@@ -21,7 +20,6 @@
#include <asm/machdep.h>
#include <asm/cacheflush.h>
#include <asm/paca.h>
-#include <asm/lmb.h>
#include <asm/mmu.h>
#include <asm/sections.h> /* _end */
#include <asm/prom.h>
@@ -33,8 +31,8 @@ int default_machine_kexec_prepare(struct kimage *image)
unsigned long begin, end; /* limits of segment */
unsigned long low, high; /* limits of blocked memory range */
struct device_node *node;
- unsigned long *basep;
- unsigned int *sizep;
+ const unsigned long *basep;
+ const unsigned int *sizep;
if (!ppc_md.hpte_clear_all)
return -ENOENT;
@@ -74,10 +72,8 @@ int default_machine_kexec_prepare(struct kimage *image)
/* We also should not overwrite the tce tables */
for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
node = of_find_node_by_type(node, "pci")) {
- basep = (unsigned long *)get_property(node, "linux,tce-base",
- NULL);
- sizep = (unsigned int *)get_property(node, "linux,tce-size",
- NULL);
+ basep = get_property(node, "linux,tce-base", NULL);
+ sizep = get_property(node, "linux,tce-size", NULL);
if (basep == NULL || sizep == NULL)
continue;
@@ -378,63 +374,10 @@ static void __init export_crashk_values(void)
of_node_put(node);
}
-void __init kexec_setup(void)
+static int __init kexec_setup(void)
{
export_htab_values();
export_crashk_values();
-}
-
-static int __init early_parse_crashk(char *p)
-{
- unsigned long size;
-
- if (!p)
- return 1;
-
- size = memparse(p, &p);
-
- if (*p == '@')
- crashk_res.start = memparse(p + 1, &p);
- else
- crashk_res.start = KDUMP_KERNELBASE;
-
- crashk_res.end = crashk_res.start + size - 1;
-
return 0;
}
-early_param("crashkernel", early_parse_crashk);
-
-void __init reserve_crashkernel(void)
-{
- unsigned long size;
-
- if (crashk_res.start == 0)
- return;
-
- /* We might have got these values via the command line or the
- * device tree, either way sanitise them now. */
-
- size = crashk_res.end - crashk_res.start + 1;
-
- if (crashk_res.start != KDUMP_KERNELBASE)
- printk("Crash kernel location must be 0x%x\n",
- KDUMP_KERNELBASE);
-
- crashk_res.start = KDUMP_KERNELBASE;
- size = PAGE_ALIGN(size);
- crashk_res.end = crashk_res.start + size - 1;
-
- /* Crash kernel trumps memory limit */
- if (memory_limit && memory_limit <= crashk_res.end) {
- memory_limit = crashk_res.end + 1;
- printk("Adjusted memory limit for crashkernel, now 0x%lx\n",
- memory_limit);
- }
-
- lmb_reserve(crashk_res.start, size);
-}
-
-int overlaps_crashkernel(unsigned long start, unsigned long size)
-{
- return (start + size) > crashk_res.start && start <= crashk_res.end;
-}
+__initcall(kexec_setup);
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
new file mode 100644
index 000000000000..330c9dc7db86
--- /dev/null
+++ b/arch/powerpc/kernel/misc.S
@@ -0,0 +1,45 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/ppc_asm.h>
+
+ .text
+
+/*
+ * Returns (address we are running at) - (address we were linked at)
+ * for use before the text and data are mapped to KERNELBASE.
+ */
+
+_GLOBAL(reloc_offset)
+ mflr r0
+ bl 1f
+1: mflr r3
+ LOAD_REG_IMMEDIATE(r4,1b)
+ subf r3,r4,r3
+ mtlr r0
+ blr
+
+/*
+ * add_reloc_offset(x) returns x + reloc_offset().
+ */
+_GLOBAL(add_reloc_offset)
+ mflr r0
+ bl 1f
+1: mflr r5
+ LOAD_REG_IMMEDIATE(r4,1b)
+ subf r5,r4,r5
+ add r3,r3,r5
+ mtlr r0
+ blr
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 01d3916c4cb1..58758d883361 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -16,7 +16,6 @@
*
*/
-#include <linux/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
@@ -61,32 +60,6 @@ _GLOBAL(mulhdu)
blr
/*
- * Returns (address we're running at) - (address we were linked at)
- * for use before the text and data are mapped to KERNELBASE.
- */
-_GLOBAL(reloc_offset)
- mflr r0
- bl 1f
-1: mflr r3
- LOAD_REG_IMMEDIATE(r4,1b)
- subf r3,r4,r3
- mtlr r0
- blr
-
-/*
- * add_reloc_offset(x) returns x + reloc_offset().
- */
-_GLOBAL(add_reloc_offset)
- mflr r0
- bl 1f
-1: mflr r5
- LOAD_REG_IMMEDIATE(r4,1b)
- subf r5,r4,r5
- add r3,r3,r5
- mtlr r0
- blr
-
-/*
* sub_reloc_offset(x) returns x - reloc_offset().
*/
_GLOBAL(sub_reloc_offset)
@@ -781,136 +754,6 @@ _GLOBAL(atomic_set_mask)
blr
/*
- * I/O string operations
- *
- * insb(port, buf, len)
- * outsb(port, buf, len)
- * insw(port, buf, len)
- * outsw(port, buf, len)
- * insl(port, buf, len)
- * outsl(port, buf, len)
- * insw_ns(port, buf, len)
- * outsw_ns(port, buf, len)
- * insl_ns(port, buf, len)
- * outsl_ns(port, buf, len)
- *
- * The *_ns versions don't do byte-swapping.
- */
-_GLOBAL(_insb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbz r5,0(r3)
- eieio
- stbu r5,1(r4)
- bdnz 00b
- blr
-
-_GLOBAL(_outsb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbzu r5,1(r4)
- stb r5,0(r3)
- eieio
- bdnz 00b
- blr
-
-_GLOBAL(_insw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhbrx r5,0,r3
- eieio
- sthu r5,2(r4)
- bdnz 00b
- blr
-
-_GLOBAL(_outsw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- eieio
- sthbrx r5,0,r3
- bdnz 00b
- blr
-
-_GLOBAL(_insl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwbrx r5,0,r3
- eieio
- stwu r5,4(r4)
- bdnz 00b
- blr
-
-_GLOBAL(_outsl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stwbrx r5,0,r3
- eieio
- bdnz 00b
- blr
-
-_GLOBAL(__ide_mm_insw)
-_GLOBAL(_insw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhz r5,0(r3)
- eieio
- sthu r5,2(r4)
- bdnz 00b
- blr
-
-_GLOBAL(__ide_mm_outsw)
-_GLOBAL(_outsw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- sth r5,0(r3)
- eieio
- bdnz 00b
- blr
-
-_GLOBAL(__ide_mm_insl)
-_GLOBAL(_insl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwz r5,0(r3)
- eieio
- stwu r5,4(r4)
- bdnz 00b
- blr
-
-_GLOBAL(__ide_mm_outsl)
-_GLOBAL(_outsl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stw r5,0(r3)
- eieio
- bdnz 00b
- blr
-
-/*
* Extended precision shifts.
*
* Updated to be valid for shift counts from 0 to 63 inclusive.
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index e8883d42c43c..e3ed21cd3d94 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -1,14 +1,12 @@
/*
- * arch/powerpc/kernel/misc64.S
- *
* This file contains miscellaneous low-level functions.
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
*
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
* and Paul Mackerras.
* Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
- *
+ * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -16,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
@@ -30,41 +27,10 @@
.text
-/*
- * Returns (address we are running at) - (address we were linked at)
- * for use before the text and data are mapped to KERNELBASE.
- */
-
-_GLOBAL(reloc_offset)
- mflr r0
- bl 1f
-1: mflr r3
- LOAD_REG_IMMEDIATE(r4,1b)
- subf r3,r4,r3
- mtlr r0
- blr
-
-/*
- * add_reloc_offset(x) returns x + reloc_offset().
- */
-_GLOBAL(add_reloc_offset)
- mflr r0
- bl 1f
-1: mflr r5
- LOAD_REG_IMMEDIATE(r4,1b)
- subf r5,r4,r5
- add r3,r3,r5
- mtlr r0
- blr
-
_GLOBAL(get_msr)
mfmsr r3
blr
-_GLOBAL(get_dar)
- mfdar r3
- blr
-
_GLOBAL(get_srr0)
mfsrr0 r3
blr
@@ -72,10 +38,6 @@ _GLOBAL(get_srr0)
_GLOBAL(get_srr1)
mfsrr1 r3
blr
-
-_GLOBAL(get_sp)
- mr r3,r1
- blr
#ifdef CONFIG_IRQSTACKS
_GLOBAL(call_do_softirq)
@@ -89,60 +51,20 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr
-_GLOBAL(call___do_IRQ)
+_GLOBAL(call_handle_irq)
+ ld r8,0(r7)
mflr r0
std r0,16(r1)
- stdu r1,THREAD_SIZE-112(r5)
- mr r1,r5
- bl .__do_IRQ
+ mtctr r8
+ stdu r1,THREAD_SIZE-112(r6)
+ mr r1,r6
+ bctrl
ld r1,0(r1)
ld r0,16(r1)
mtlr r0
blr
#endif /* CONFIG_IRQSTACKS */
- /*
- * To be called by C code which needs to do some operations with MMU
- * disabled. Note that interrupts have to be disabled by the caller
- * prior to calling us. The code called _MUST_ be in the RMO of course
- * and part of the linear mapping as we don't attempt to translate the
- * stack pointer at all. The function is called with the stack switched
- * to this CPU emergency stack
- *
- * prototype is void *call_with_mmu_off(void *func, void *data);
- *
- * the called function is expected to be of the form
- *
- * void *called(void *data);
- */
-_GLOBAL(call_with_mmu_off)
- mflr r0 /* get link, save it on stackframe */
- std r0,16(r1)
- mr r1,r5 /* save old stack ptr */
- ld r1,PACAEMERGSP(r13) /* get emerg. stack */
- subi r1,r1,STACK_FRAME_OVERHEAD
- std r0,16(r1) /* save link on emerg. stack */
- std r5,0(r1) /* save old stack ptr in backchain */
- ld r3,0(r3) /* get to real function ptr (assume same TOC) */
- bl 2f /* we need LR to return, continue at label 2 */
-
- ld r0,16(r1) /* we return here from the call, get LR and */
- ld r1,0(r1) /* .. old stack ptr */
- mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */
- mfmsr r4
- ori r4,r4,MSR_IR|MSR_DR
- mtspr SPRN_SRR1,r4
- rfid
-
-2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */
- mr r3,r4 /* get parameter */
- mfmsr r0
- ori r0,r0,MSR_IR|MSR_DR
- xori r0,r0,MSR_IR|MSR_DR
- mtspr SPRN_SRR1,r0
- rfid
-
-
.section ".toc","aw"
PPC64_CACHES:
.tc ppc64_caches[TC],ppc64_caches
@@ -323,144 +245,6 @@ _GLOBAL(__flush_dcache_icache)
bdnz 1b
isync
blr
-
-/*
- * I/O string operations
- *
- * insb(port, buf, len)
- * outsb(port, buf, len)
- * insw(port, buf, len)
- * outsw(port, buf, len)
- * insl(port, buf, len)
- * outsl(port, buf, len)
- * insw_ns(port, buf, len)
- * outsw_ns(port, buf, len)
- * insl_ns(port, buf, len)
- * outsl_ns(port, buf, len)
- *
- * The *_ns versions don't do byte-swapping.
- */
-_GLOBAL(_insb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbz r5,0(r3)
- eieio
- stbu r5,1(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbzu r5,1(r4)
- stb r5,0(r3)
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhbrx r5,0,r3
- eieio
- sthu r5,2(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- sthbrx r5,0,r3
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwbrx r5,0,r3
- eieio
- stwu r5,4(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stwbrx r5,0,r3
- bdnz 00b
- sync
- blr
-
-/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_insw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhz r5,0(r3)
- eieio
- sthu r5,2(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_outsw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- sth r5,0(r3)
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwz r5,0(r3)
- eieio
- stwu r5,4(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stw r5,0(r3)
- bdnz 00b
- sync
- blr
/*
* identify_cpu and calls setup_cpu
@@ -605,6 +389,7 @@ _GLOBAL(real_writeb)
blr
#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
+#ifdef CONFIG_CPU_FREQ_PMAC64
/*
* SCOM access functions for 970 (FX only for now)
*
@@ -673,6 +458,7 @@ _GLOBAL(scom970_write)
/* restore interrupts */
mtmsrd r5,1
blr
+#endif /* CONFIG_CPU_FREQ_PMAC64 */
/*
@@ -901,7 +687,7 @@ _GLOBAL(kexec_sequence)
/* clear out hardware hash page table and tlb */
ld r5,0(r27) /* deref function descriptor */
mtctr r5
- bctrl /* ppc_md.hash_clear_all(void); */
+ bctrl /* ppc_md.hpte_clear_all(void); */
/*
* kexec image calling is:
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 9feeeef5a875..397c83eda20e 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -190,27 +189,9 @@ void of_release_dev(struct device *dev)
int of_device_register(struct of_device *ofdev)
{
int rc;
- struct of_device **odprop;
BUG_ON(ofdev->node == NULL);
- odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
- if (!odprop) {
- struct property *new_prop;
-
- new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *),
- GFP_KERNEL);
- if (new_prop == NULL)
- return -ENOMEM;
- new_prop->name = "linux,device";
- new_prop->length = sizeof(sizeof(struct of_device *));
- new_prop->value = (unsigned char *)&new_prop[1];
- odprop = (struct of_device **)new_prop->value;
- *odprop = NULL;
- prom_add_property(ofdev->node, new_prop);
- }
- *odprop = ofdev;
-
rc = device_register(&ofdev->dev);
if (rc)
return rc;
@@ -222,14 +203,8 @@ int of_device_register(struct of_device *ofdev)
void of_device_unregister(struct of_device *ofdev)
{
- struct of_device **odprop;
-
device_remove_file(&ofdev->dev, &dev_attr_devspec);
- odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
- if (odprop)
- *odprop = NULL;
-
device_unregister(&ofdev->dev);
}
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index f505a8827e3e..55f1a25085cd 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -7,7 +7,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/threads.h>
#include <linux/module.h>
@@ -16,9 +15,9 @@
#include <asm/ptrace.h>
#include <asm/page.h>
#include <asm/lppaca.h>
-#include <asm/iseries/it_lp_queue.h>
#include <asm/iseries/it_lp_reg_save.h>
#include <asm/paca.h>
+#include <asm/mmu.h>
/* This symbol is provided by the linker - let it fill in the paca
@@ -47,6 +46,17 @@ struct lppaca lppaca[] = {
},
};
+/*
+ * 3 persistent SLBs are registered here. The buffer will be zero
+ * initially, hence will all be invaild until we actually write them.
+ */
+struct slb_shadow slb_shadow[] __cacheline_aligned = {
+ [0 ... (NR_CPUS-1)] = {
+ .persistent = SLB_NUM_BOLTED,
+ .buffer_length = sizeof(struct slb_shadow),
+ },
+};
+
/* The Paca is an array with one entry per processor. Each contains an
* lppaca, which contains the information shared between the
* hypervisor and Linux.
@@ -61,7 +71,8 @@ struct lppaca lppaca[] = {
.lock_token = 0x8000, \
.paca_index = (number), /* Paca Index */ \
.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \
- .hw_cpu_id = 0xffff,
+ .hw_cpu_id = 0xffff, \
+ .slb_shadow_ptr = &slb_shadow[number],
#ifdef CONFIG_PPC_ISERIES
#define PACA_INIT_ISERIES(number) \
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index c858eb4bef17..9b49f8691d29 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -2,7 +2,6 @@
* Common pmac/prep/chrp pci routines. -- Cort
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -12,6 +11,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/bootmem.h>
+#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -19,7 +19,6 @@
#include <asm/sections.h>
#include <asm/pci-bridge.h>
#include <asm/byteorder.h>
-#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/machdep.h>
@@ -99,7 +98,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
if (!res->flags)
continue;
if (res->end == 0xffffffff) {
- DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
+ DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n",
pci_name(dev), i, res->start, res->end);
res->end -= res->start;
res->start = 0;
@@ -117,7 +116,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
res->start += offset;
res->end += offset;
#ifdef DEBUG
- printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n",
+ printk("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",
i, res->flags, pci_name(dev),
res->start - offset, res->start);
#endif
@@ -173,18 +172,18 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
* but we want to try to avoid allocating at 0x2900-0x2bff
* which might have be mirrored at 0x0100-0x03ff..
*/
-void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
- unsigned long align)
+void pcibios_align_resource(void *data, struct resource *res,
+ resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
- unsigned long start = res->start;
+ resource_size_t start = res->start;
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
- " (%ld bytes)\n", pci_name(dev),
- dev->resource - res, size);
+ " (%lld bytes)\n", pci_name(dev),
+ dev->resource - res, (unsigned long long)size);
}
if (start & 0x300) {
@@ -255,8 +254,8 @@ pcibios_allocate_bus_resources(struct list_head *bus_list)
}
}
- DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
- res->start, res->end, res->flags, pr);
+ DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n",
+ res->start, res->end, res->flags, pr);
if (pr) {
if (request_resource(pr, res) == 0)
continue;
@@ -306,7 +305,7 @@ reparent_resources(struct resource *parent, struct resource *res)
*pp = NULL;
for (p = res->child; p != NULL; p = p->sibling) {
p->parent = res;
- DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+ DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n",
p->name, p->start, p->end, res->name);
}
return 0;
@@ -362,13 +361,14 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i)
try = conflict->start - 1;
}
if (request_resource(pr, res)) {
- DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+ DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n",
res->start, res->end);
return -1; /* "can't happen" */
}
update_bridge_base(bus, i);
- printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
- bus->number, i, res->start, res->end);
+ printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n",
+ bus->number, i, (unsigned long long)res->start,
+ (unsigned long long)res->end);
return 0;
}
@@ -479,14 +479,14 @@ static inline void alloc_resource(struct pci_dev *dev, int idx)
{
struct resource *pr, *r = &dev->resource[idx];
- DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
+ DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n",
pci_name(dev), idx, r->start, r->end, r->flags);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d"
" of device %s\n", idx, pci_name(dev));
if (pr)
- DBG("PCI: parent is %p: %08lx-%08lx (f=%lx)\n",
+ DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n",
pr, pr->start, pr->end, pr->flags);
/* We'll assign a new address later */
r->flags |= IORESOURCE_UNSET;
@@ -633,12 +633,12 @@ pcibios_alloc_controller(void)
static void
make_one_node_map(struct device_node* node, u8 pci_bus)
{
- int *bus_range;
+ const int *bus_range;
int len;
if (pci_bus >= pci_bus_count)
return;
- bus_range = (int *) get_property(node, "bus-range", &len);
+ bus_range = get_property(node, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, "
"assuming it starts at 0\n", node->full_name);
@@ -648,13 +648,13 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
for (node=node->child; node != 0;node = node->sibling) {
struct pci_dev* dev;
- unsigned int *class_code, *reg;
+ const unsigned int *class_code, *reg;
- class_code = (unsigned int *) get_property(node, "class-code", NULL);
+ class_code = get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- reg = (unsigned int *)get_property(node, "reg", NULL);
+ reg = get_property(node, "reg", NULL);
if (!reg)
continue;
dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
@@ -669,7 +669,7 @@ pcibios_make_OF_bus_map(void)
{
int i;
struct pci_controller* hose;
- u8* of_prop_map;
+ struct property *map_prop;
pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL);
if (!pci_to_OF_bus_map) {
@@ -691,9 +691,12 @@ pcibios_make_OF_bus_map(void)
continue;
make_one_node_map(node, hose->first_busno);
}
- of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL);
- if (of_prop_map)
- memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);
+ map_prop = of_find_property(find_path_device("/"),
+ "pci-OF-bus-map", NULL);
+ if (map_prop) {
+ BUG_ON(pci_bus_count > map_prop->length);
+ memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
+ }
#ifdef DEBUG
printk("PCI->OF bus map:\n");
for (i=0; i<pci_bus_count; i++) {
@@ -712,7 +715,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
struct device_node* sub_node;
for (; node != 0;node = node->sibling) {
- unsigned int *class_code;
+ const unsigned int *class_code;
if (filter(node, data))
return node;
@@ -722,7 +725,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
* a fake root for all functions of a multi-function device,
* we go down them as well.
*/
- class_code = (unsigned int *) get_property(node, "class-code", NULL);
+ class_code = get_property(node, "class-code", NULL);
if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
strcmp(node->name, "multifunc-device"))
@@ -737,10 +740,10 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
static int
scan_OF_pci_childs_iterator(struct device_node* node, void* data)
{
- unsigned int *reg;
+ const unsigned int *reg;
u8* fdata = (u8*)data;
- reg = (unsigned int *) get_property(node, "reg", NULL);
+ reg = get_property(node, "reg", NULL);
if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
&& ((reg[0] >> 16) & 0xff) == fdata[0])
return 1;
@@ -841,7 +844,7 @@ find_OF_pci_device_filter(struct device_node* node, void* data)
int
pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
{
- unsigned int *reg;
+ const unsigned int *reg;
struct pci_controller* hose;
struct pci_dev* dev = NULL;
@@ -854,7 +857,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
find_OF_pci_device_filter, (void *)node))
return -ENODEV;
- reg = (unsigned int *) get_property(node, "reg", NULL);
+ reg = get_property(node, "reg", NULL);
if (!reg)
return -ENODEV;
*bus = (reg[0] >> 16) & 0xff;
@@ -885,8 +888,8 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary)
{
static unsigned int static_lc_ranges[256] __initdata;
- unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
- unsigned int size;
+ const unsigned int *dt_ranges;
+ unsigned int *lc_ranges, *ranges, *prev, size;
int rlen = 0, orig_rlen;
int memno = 0;
struct resource *res;
@@ -897,7 +900,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* that can have more than 3 ranges, fortunately using contiguous
* addresses -- BenH
*/
- dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+ dt_ranges = get_property(dev, "ranges", &rlen);
if (!dt_ranges)
return;
/* Sanity check, though hopefully that never happens */
@@ -956,7 +959,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
res = &hose->io_resource;
res->flags = IORESOURCE_IO;
res->start = ranges[2];
- DBG("PCI: IO 0x%lx -> 0x%lx\n",
+ DBG("PCI: IO 0x%llx -> 0x%llx\n",
res->start, res->start + size - 1);
break;
case 2: /* memory space */
@@ -978,7 +981,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
if(ranges[0] & 0x40000000)
res->flags |= IORESOURCE_PREFETCH;
res->start = ranges[na+2];
- DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+ DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno,
res->start, res->start + size - 1);
}
break;
@@ -1074,7 +1077,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
- DBG(" IO window: %08lx-%08lx\n", res.start, res.end);
+ DBG(" IO window: %016llx-%016llx\n", res.start, res.end);
/* Set up the top and bottom of the PCI I/O segment for this bus. */
pci_read_config_dword(bridge, PCI_IO_BASE, &l);
@@ -1223,8 +1226,8 @@ do_fixup_p2p_level(struct pci_bus *bus)
continue;
if ((r->flags & IORESOURCE_IO) == 0)
continue;
- DBG("Trying to allocate from %08lx, size %08lx from parent"
- " res %d: %08lx -> %08lx\n",
+ DBG("Trying to allocate from %016llx, size %016llx from parent"
+ " res %d: %016llx -> %016llx\n",
res->start, res->end, i, r->start, r->end);
if (allocate_resource(r, res, res->end + 1, res->start, max,
@@ -1404,6 +1407,65 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
/* XXX FIXME - update OF device tree node interrupt property */
}
+#ifdef CONFIG_PPC_MERGE
+/* XXX This is a copy of the ppc64 version. This is temporary until we start
+ * merging the 2 PCI layers
+ */
+/*
+ * Reads the interrupt pin to determine if interrupt is use by card.
+ * If the interrupt is used, then gets the interrupt line from the
+ * openfirmware and sets it in the pci_dev and pci_config line.
+ */
+int pci_read_irq_line(struct pci_dev *pci_dev)
+{
+ struct of_irq oirq;
+ unsigned int virq;
+
+ DBG("Try to map irq for %s...\n", pci_name(pci_dev));
+
+ /* Try to get a mapping from the device-tree */
+ if (of_irq_map_pci(pci_dev, &oirq)) {
+ u8 line, pin;
+
+ /* If that fails, lets fallback to what is in the config
+ * space and map that through the default controller. We
+ * also set the type to level low since that's what PCI
+ * interrupts are. If your platform does differently, then
+ * either provide a proper interrupt tree or don't use this
+ * function.
+ */
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
+ return -1;
+ if (pin == 0)
+ return -1;
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
+ line == 0xff) {
+ return -1;
+ }
+ DBG(" -> no map ! Using irq line %d from PCI config\n", line);
+
+ virq = irq_create_mapping(NULL, line);
+ if (virq != NO_IRQ)
+ set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+ } else {
+ DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
+ oirq.size, oirq.specifier[0], oirq.controller->full_name);
+
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+ }
+ if(virq == NO_IRQ) {
+ DBG(" -> failed to map !\n");
+ return -1;
+ }
+ pci_dev->irq = virq;
+ pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_read_irq_line);
+#endif /* CONFIG_PPC_MERGE */
+
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
@@ -1574,8 +1636,8 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
else
prot |= _PAGE_GUARDED;
- printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
- prot);
+ printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
+ (unsigned long long)rp->start, prot);
return __pgprot(prot);
}
@@ -1654,7 +1716,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
vma->vm_page_prot,
mmap_state, write_combine);
@@ -1756,7 +1817,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
- u64 *start, u64 *end)
+ resource_size_t *start, resource_size_t *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
unsigned long offset = 0;
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 5ad87c426bed..c1b1e14775e4 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -13,7 +13,6 @@
#undef DEBUG
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/string.h>
@@ -22,13 +21,13 @@
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/syscalls.h>
+#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/byteorder.h>
-#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
@@ -138,11 +137,11 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
* which might have be mirrored at 0x0100-0x03ff..
*/
void pcibios_align_resource(void *data, struct resource *res,
- unsigned long size, unsigned long align)
+ resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long start = res->start;
+ resource_size_t start = res->start;
unsigned long alignto;
if (res->flags & IORESOURCE_IO) {
@@ -186,34 +185,6 @@ static void __devinit pci_setup_pci_controller(struct pci_controller *hose)
spin_unlock(&hose_spinlock);
}
-static void add_linux_pci_domain(struct device_node *dev,
- struct pci_controller *phb)
-{
- struct property *of_prop;
- unsigned int size;
-
- of_prop = (struct property *)
- get_property(dev, "linux,pci-domain", &size);
- if (of_prop != NULL)
- return;
- WARN_ON(of_prop && size < sizeof(int));
- if (of_prop && size < sizeof(int))
- of_prop = NULL;
- size = sizeof(struct property) + sizeof(int);
- if (of_prop == NULL) {
- if (mem_init_done)
- of_prop = kmalloc(size, GFP_KERNEL);
- else
- of_prop = alloc_bootmem(size);
- }
- memset(of_prop, 0, sizeof(struct property));
- of_prop->name = "linux,pci-domain";
- of_prop->length = sizeof(int);
- of_prop->value = (unsigned char *)&of_prop[1];
- *((int *)of_prop->value) = phb->global_number;
- prom_add_property(dev, of_prop);
-}
-
struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
{
struct pci_controller *phb;
@@ -227,22 +198,13 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
pci_setup_pci_controller(phb);
phb->arch_data = dev;
phb->is_dynamic = mem_init_done;
- if (dev) {
+ if (dev)
PHB_SET_NODE(phb, of_node_to_nid(dev));
- add_linux_pci_domain(dev, phb);
- }
return phb;
}
void pcibios_free_controller(struct pci_controller *phb)
{
- if (phb->arch_data) {
- struct device_node *np = phb->arch_data;
- int *domain = (int *)get_property(np,
- "linux,pci-domain", NULL);
- if (domain)
- *domain = -1;
- }
if (phb->is_dynamic)
kfree(phb);
}
@@ -284,10 +246,10 @@ static void __init pcibios_claim_of_setup(void)
#ifdef CONFIG_PPC_MULTIPLATFORM
static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
{
- u32 *prop;
+ const u32 *prop;
int len;
- prop = (u32 *) get_property(np, name, &len);
+ prop = get_property(np, name, &len);
if (prop && len >= 4)
return *prop;
return def;
@@ -316,10 +278,11 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
u64 base, size;
unsigned int flags;
struct resource *res;
- u32 *addrs, i;
+ const u32 *addrs;
+ u32 i;
int proplen;
- addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
+ addrs = get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
@@ -399,12 +362,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
} else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
+ /* Maybe do a default OF mapping here */
dev->irq = NO_IRQ;
- if (node->n_intrs > 0) {
- dev->irq = node->intrs[0].line;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
- dev->irq);
- }
}
pci_parse_of_addrs(node, dev);
@@ -423,7 +382,7 @@ void __devinit of_scan_bus(struct device_node *node,
struct pci_bus *bus)
{
struct device_node *child = NULL;
- u32 *reg;
+ const u32 *reg;
int reglen, devfn;
struct pci_dev *dev;
@@ -431,7 +390,7 @@ void __devinit of_scan_bus(struct device_node *node,
while ((child = of_get_next_child(node, child)) != NULL) {
DBG(" * %s\n", child->full_name);
- reg = (u32 *) get_property(child, "reg", &reglen);
+ reg = get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
devfn = (reg[0] >> 8) & 0xff;
@@ -455,7 +414,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
struct pci_dev *dev)
{
struct pci_bus *bus;
- u32 *busrange, *ranges;
+ const u32 *busrange, *ranges;
int len, i, mode;
struct resource *res;
unsigned int flags;
@@ -464,13 +423,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
DBG("of_scan_pci_bridge(%s)\n", node->full_name);
/* parse bus-range property */
- busrange = (u32 *) get_property(node, "bus-range", &len);
+ busrange = get_property(node, "bus-range", &len);
if (busrange == NULL || len != 8) {
printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
node->full_name);
return;
}
- ranges = (u32 *) get_property(node, "ranges", &len);
+ ranges = get_property(node, "ranges", &len);
if (ranges == NULL) {
printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
node->full_name);
@@ -877,7 +836,6 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
vma->vm_page_prot,
mmap_state, write_combine);
@@ -935,13 +893,13 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned int size;
};
- struct isa_range *range;
+ const struct isa_range *range;
unsigned long pci_addr;
unsigned int isa_addr;
unsigned int size;
int rlen = 0;
- range = (struct isa_range *) get_property(isa_node, "ranges", &rlen);
+ range = get_property(isa_node, "ranges", &rlen);
if (range == NULL || (rlen < sizeof(struct isa_range))) {
printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
"mapping 64k\n");
@@ -982,7 +940,8 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int prim)
{
- unsigned int *ranges, pci_space;
+ const unsigned int *ranges;
+ unsigned int pci_space;
unsigned long size;
int rlen = 0;
int memno = 0;
@@ -1000,7 +959,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
* (size depending on dev->n_addr_cells)
* cells 4+5 or 5+6: the size of the range
*/
- ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+ ranges = get_property(dev, "ranges", &rlen);
if (ranges == NULL)
return;
hose->io_base_phys = 0;
@@ -1290,23 +1249,55 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
*/
int pci_read_irq_line(struct pci_dev *pci_dev)
{
- u8 intpin;
- struct device_node *node;
+ struct of_irq oirq;
+ unsigned int virq;
- pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin);
- if (intpin == 0)
- return 0;
+ DBG("Try to map irq for %s...\n", pci_name(pci_dev));
- node = pci_device_to_OF_node(pci_dev);
- if (node == NULL)
- return -1;
+#ifdef DEBUG
+ memset(&oirq, 0xff, sizeof(oirq));
+#endif
+ /* Try to get a mapping from the device-tree */
+ if (of_irq_map_pci(pci_dev, &oirq)) {
+ u8 line, pin;
+
+ /* If that fails, lets fallback to what is in the config
+ * space and map that through the default controller. We
+ * also set the type to level low since that's what PCI
+ * interrupts are. If your platform does differently, then
+ * either provide a proper interrupt tree or don't use this
+ * function.
+ */
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
+ return -1;
+ if (pin == 0)
+ return -1;
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
+ line == 0xff) {
+ return -1;
+ }
+ DBG(" -> no map ! Using irq line %d from PCI config\n", line);
+
+ virq = irq_create_mapping(NULL, line);
+ if (virq != NO_IRQ)
+ set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+ } else {
+ DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
+ oirq.size, oirq.specifier[0], oirq.specifier[1],
+ oirq.controller->full_name);
- if (node->n_intrs == 0)
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+ }
+ if(virq == NO_IRQ) {
+ DBG(" -> failed to map !\n");
return -1;
+ }
- pci_dev->irq = node->intrs[0].line;
+ DBG(" -> mapped to linux irq %d\n", virq);
- pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq);
+ pci_dev->irq = virq;
+ pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
return 0;
}
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 1c18953514c3..68df018dae0e 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -40,8 +40,8 @@
static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
{
struct pci_controller *phb = data;
- int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
- u32 *regs;
+ const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
+ const u32 *regs;
struct pci_dn *pdn;
if (mem_init_done)
@@ -54,14 +54,14 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
dn->data = pdn;
pdn->node = dn;
pdn->phb = phb;
- regs = (u32 *)get_property(dn, "reg", NULL);
+ regs = get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
pdn->busno = (regs[0] >> 16) & 0xff;
pdn->devfn = (regs[0] >> 8) & 0xff;
}
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- u32 *busp = (u32 *)get_property(dn, "linux,subbus", NULL);
+ const u32 *busp = get_property(dn, "linux,subbus", NULL);
if (busp)
pdn->bussubno = *busp;
}
@@ -96,10 +96,11 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
/* We started with a phb, iterate all childs */
for (dn = start->child; dn; dn = nextdn) {
- u32 *classp, class;
+ const u32 *classp;
+ u32 class;
nextdn = NULL;
- classp = (u32 *)get_property(dn, "class-code", NULL);
+ classp = get_property(dn, "class-code", NULL);
class = classp ? *classp : 0;
if (pre && ((ret = pre(dn, data)) != NULL))
diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c
index 32455dfcc36b..bdc3977a7b06 100644
--- a/arch/powerpc/kernel/perfmon_fsl_booke.c
+++ b/arch/powerpc/kernel/perfmon_fsl_booke.c
@@ -21,7 +21,6 @@
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/prctl.h>
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c
index e6fb194fe537..a0a2efadeabf 100644
--- a/arch/powerpc/kernel/pmc.c
+++ b/arch/powerpc/kernel/pmc.c
@@ -12,7 +12,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/module.h>
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 4b052ae5dc34..807193a3c784 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/threads.h>
#include <linux/smp.h>
@@ -6,7 +5,7 @@
#include <linux/elfcore.h>
#include <linux/string.h>
#include <linux/interrupt.h>
-#include <linux/tty.h>
+#include <linux/screen_info.h>
#include <linux/vt_kern.h>
#include <linux/nvram.h>
#include <linux/console.h>
@@ -92,25 +91,10 @@ EXPORT_SYMBOL(__copy_tofrom_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
-
-#ifndef __powerpc64__
-EXPORT_SYMBOL(__ide_mm_insl);
-EXPORT_SYMBOL(__ide_mm_outsw);
-EXPORT_SYMBOL(__ide_mm_insw);
-EXPORT_SYMBOL(__ide_mm_outsl);
+#ifdef CONFIG_PPC64
+EXPORT_SYMBOL(copy_4K_page);
#endif
-EXPORT_SYMBOL(_insb);
-EXPORT_SYMBOL(_outsb);
-EXPORT_SYMBOL(_insw);
-EXPORT_SYMBOL(_outsw);
-EXPORT_SYMBOL(_insl);
-EXPORT_SYMBOL(_outsl);
-EXPORT_SYMBOL(_insw_ns);
-EXPORT_SYMBOL(_outsw_ns);
-EXPORT_SYMBOL(_insl_ns);
-EXPORT_SYMBOL(_outsl_ns);
-
#if defined(CONFIG_PPC32) && (defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE))
EXPORT_SYMBOL(ppc_ide_md);
#endif
@@ -127,10 +111,6 @@ EXPORT_SYMBOL(pci_bus_mem_base_phys);
EXPORT_SYMBOL(pci_bus_to_hose);
#endif /* CONFIG_PCI */
-#ifdef CONFIG_NOT_COHERENT_CACHE
-EXPORT_SYMBOL(flush_dcache_all);
-#endif
-
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(kernel_thread);
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index 2b87f82df135..f598cb519539 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
@@ -115,8 +114,6 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
{
struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
- vma->vm_flags |= VM_SHM | VM_LOCKED;
-
if ((vma->vm_end - vma->vm_start) > dp->size)
return -EINVAL;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e4732459c485..a127a1e3c097 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -14,7 +14,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 483455c5bb02..eb913f80bfb1 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -16,7 +16,6 @@
#undef DEBUG
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -30,6 +29,8 @@
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/kexec.h>
+#include <linux/debugfs.h>
+#include <linux/irq.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -86,424 +87,6 @@ static DEFINE_RWLOCK(devtree_lock);
/* export that to outside world */
struct device_node *of_chosen;
-struct device_node *dflt_interrupt_controller;
-int num_interrupt_controllers;
-
-/*
- * Wrapper for allocating memory for various data that needs to be
- * attached to device nodes as they are processed at boot or when
- * added to the device tree later (e.g. DLPAR). At boot there is
- * already a region reserved so we just increment *mem_start by size;
- * otherwise we call kmalloc.
- */
-static void * prom_alloc(unsigned long size, unsigned long *mem_start)
-{
- unsigned long tmp;
-
- if (!mem_start)
- return kmalloc(size, GFP_KERNEL);
-
- tmp = *mem_start;
- *mem_start += size;
- return (void *)tmp;
-}
-
-/*
- * Find the device_node with a given phandle.
- */
-static struct device_node * find_phandle(phandle ph)
-{
- struct device_node *np;
-
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->linux_phandle == ph)
- return np;
- return NULL;
-}
-
-/*
- * Find the interrupt parent of a node.
- */
-static struct device_node * __devinit intr_parent(struct device_node *p)
-{
- phandle *parp;
-
- parp = (phandle *) get_property(p, "interrupt-parent", NULL);
- if (parp == NULL)
- return p->parent;
- p = find_phandle(*parp);
- if (p != NULL)
- return p;
- /*
- * On a powermac booted with BootX, we don't get to know the
- * phandles for any nodes, so find_phandle will return NULL.
- * Fortunately these machines only have one interrupt controller
- * so there isn't in fact any ambiguity. -- paulus
- */
- if (num_interrupt_controllers == 1)
- p = dflt_interrupt_controller;
- return p;
-}
-
-/*
- * Find out the size of each entry of the interrupts property
- * for a node.
- */
-int __devinit prom_n_intr_cells(struct device_node *np)
-{
- struct device_node *p;
- unsigned int *icp;
-
- for (p = np; (p = intr_parent(p)) != NULL; ) {
- icp = (unsigned int *)
- get_property(p, "#interrupt-cells", NULL);
- if (icp != NULL)
- return *icp;
- if (get_property(p, "interrupt-controller", NULL) != NULL
- || get_property(p, "interrupt-map", NULL) != NULL) {
- printk("oops, node %s doesn't have #interrupt-cells\n",
- p->full_name);
- return 1;
- }
- }
-#ifdef DEBUG_IRQ
- printk("prom_n_intr_cells failed for %s\n", np->full_name);
-#endif
- return 1;
-}
-
-/*
- * Map an interrupt from a device up to the platform interrupt
- * descriptor.
- */
-static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler,
- struct device_node *np, unsigned int *ints,
- int nintrc)
-{
- struct device_node *p, *ipar;
- unsigned int *imap, *imask, *ip;
- int i, imaplen, match;
- int newintrc = 0, newaddrc = 0;
- unsigned int *reg;
- int naddrc;
-
- reg = (unsigned int *) get_property(np, "reg", NULL);
- naddrc = prom_n_addr_cells(np);
- p = intr_parent(np);
- while (p != NULL) {
- if (get_property(p, "interrupt-controller", NULL) != NULL)
- /* this node is an interrupt controller, stop here */
- break;
- imap = (unsigned int *)
- get_property(p, "interrupt-map", &imaplen);
- if (imap == NULL) {
- p = intr_parent(p);
- continue;
- }
- imask = (unsigned int *)
- get_property(p, "interrupt-map-mask", NULL);
- if (imask == NULL) {
- printk("oops, %s has interrupt-map but no mask\n",
- p->full_name);
- return 0;
- }
- imaplen /= sizeof(unsigned int);
- match = 0;
- ipar = NULL;
- while (imaplen > 0 && !match) {
- /* check the child-interrupt field */
- match = 1;
- for (i = 0; i < naddrc && match; ++i)
- match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
- for (; i < naddrc + nintrc && match; ++i)
- match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
- imap += naddrc + nintrc;
- imaplen -= naddrc + nintrc;
- /* grab the interrupt parent */
- ipar = find_phandle((phandle) *imap++);
- --imaplen;
- if (ipar == NULL && num_interrupt_controllers == 1)
- /* cope with BootX not giving us phandles */
- ipar = dflt_interrupt_controller;
- if (ipar == NULL) {
- printk("oops, no int parent %x in map of %s\n",
- imap[-1], p->full_name);
- return 0;
- }
- /* find the parent's # addr and intr cells */
- ip = (unsigned int *)
- get_property(ipar, "#interrupt-cells", NULL);
- if (ip == NULL) {
- printk("oops, no #interrupt-cells on %s\n",
- ipar->full_name);
- return 0;
- }
- newintrc = *ip;
- ip = (unsigned int *)
- get_property(ipar, "#address-cells", NULL);
- newaddrc = (ip == NULL)? 0: *ip;
- imap += newaddrc + newintrc;
- imaplen -= newaddrc + newintrc;
- }
- if (imaplen < 0) {
- printk("oops, error decoding int-map on %s, len=%d\n",
- p->full_name, imaplen);
- return 0;
- }
- if (!match) {
-#ifdef DEBUG_IRQ
- printk("oops, no match in %s int-map for %s\n",
- p->full_name, np->full_name);
-#endif
- return 0;
- }
- p = ipar;
- naddrc = newaddrc;
- nintrc = newintrc;
- ints = imap - nintrc;
- reg = ints - naddrc;
- }
- if (p == NULL) {
-#ifdef DEBUG_IRQ
- printk("hmmm, int tree for %s doesn't have ctrler\n",
- np->full_name);
-#endif
- return 0;
- }
- *irq = ints;
- *ictrler = p;
- return nintrc;
-}
-
-static unsigned char map_isa_senses[4] = {
- IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE,
- IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE,
- IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE,
- IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE
-};
-
-static unsigned char map_mpic_senses[4] = {
- IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE,
- IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE,
- /* 2 seems to be used for the 8259 cascade... */
- IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE,
- IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE,
-};
-
-static int __devinit finish_node_interrupts(struct device_node *np,
- unsigned long *mem_start,
- int measure_only)
-{
- unsigned int *ints;
- int intlen, intrcells, intrcount;
- int i, j, n, sense;
- unsigned int *irq, virq;
- struct device_node *ic;
- int trace = 0;
-
- //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0)
-#define TRACE(fmt...)
-
- if (!strcmp(np->name, "smu-doorbell"))
- trace = 1;
-
- TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n",
- num_interrupt_controllers);
-
- if (num_interrupt_controllers == 0) {
- /*
- * Old machines just have a list of interrupt numbers
- * and no interrupt-controller nodes.
- */
- ints = (unsigned int *) get_property(np, "AAPL,interrupts",
- &intlen);
- /* XXX old interpret_pci_props looked in parent too */
- /* XXX old interpret_macio_props looked for interrupts
- before AAPL,interrupts */
- if (ints == NULL)
- ints = (unsigned int *) get_property(np, "interrupts",
- &intlen);
- if (ints == NULL)
- return 0;
-
- np->n_intrs = intlen / sizeof(unsigned int);
- np->intrs = prom_alloc(np->n_intrs * sizeof(np->intrs[0]),
- mem_start);
- if (!np->intrs)
- return -ENOMEM;
- if (measure_only)
- return 0;
-
- for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = *ints++;
- np->intrs[i].sense = IRQ_SENSE_LEVEL
- | IRQ_POLARITY_NEGATIVE;
- }
- return 0;
- }
-
- ints = (unsigned int *) get_property(np, "interrupts", &intlen);
- TRACE("ints=%p, intlen=%d\n", ints, intlen);
- if (ints == NULL)
- return 0;
- intrcells = prom_n_intr_cells(np);
- intlen /= intrcells * sizeof(unsigned int);
- TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen);
- np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
- if (!np->intrs)
- return -ENOMEM;
-
- if (measure_only)
- return 0;
-
- intrcount = 0;
- for (i = 0; i < intlen; ++i, ints += intrcells) {
- n = map_interrupt(&irq, &ic, np, ints, intrcells);
- TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n);
- if (n <= 0)
- continue;
-
- /* don't map IRQ numbers under a cascaded 8259 controller */
- if (ic && device_is_compatible(ic, "chrp,iic")) {
- np->intrs[intrcount].line = irq[0];
- sense = (n > 1)? (irq[1] & 3): 3;
- np->intrs[intrcount].sense = map_isa_senses[sense];
- } else {
- virq = virt_irq_create_mapping(irq[0]);
- TRACE("virq=%d\n", virq);
-#ifdef CONFIG_PPC64
- if (virq == NO_IRQ) {
- printk(KERN_CRIT "Could not allocate interrupt"
- " number for %s\n", np->full_name);
- continue;
- }
-#endif
- np->intrs[intrcount].line = irq_offset_up(virq);
- sense = (n > 1)? (irq[1] & 3): 1;
-
- /* Apple uses bits in there in a different way, let's
- * only keep the real sense bit on macs
- */
- if (machine_is(powermac))
- sense &= 0x1;
- np->intrs[intrcount].sense = map_mpic_senses[sense];
- }
-
-#ifdef CONFIG_PPC64
- /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
- if (machine_is(powermac) && ic && ic->parent) {
- char *name = get_property(ic->parent, "name", NULL);
- if (name && !strcmp(name, "u3"))
- np->intrs[intrcount].line += 128;
- else if (!(name && (!strcmp(name, "mac-io") ||
- !strcmp(name, "u4"))))
- /* ignore other cascaded controllers, such as
- the k2-sata-root */
- break;
- }
-#endif /* CONFIG_PPC64 */
- if (n > 2) {
- printk("hmmm, got %d intr cells for %s:", n,
- np->full_name);
- for (j = 0; j < n; ++j)
- printk(" %d", irq[j]);
- printk("\n");
- }
- ++intrcount;
- }
- np->n_intrs = intrcount;
-
- return 0;
-}
-
-static int __devinit finish_node(struct device_node *np,
- unsigned long *mem_start,
- int measure_only)
-{
- struct device_node *child;
- int rc = 0;
-
- rc = finish_node_interrupts(np, mem_start, measure_only);
- if (rc)
- goto out;
-
- for (child = np->child; child != NULL; child = child->sibling) {
- rc = finish_node(child, mem_start, measure_only);
- if (rc)
- goto out;
- }
-out:
- return rc;
-}
-
-static void __init scan_interrupt_controllers(void)
-{
- struct device_node *np;
- int n = 0;
- char *name, *ic;
- int iclen;
-
- for (np = allnodes; np != NULL; np = np->allnext) {
- ic = get_property(np, "interrupt-controller", &iclen);
- name = get_property(np, "name", NULL);
- /* checking iclen makes sure we don't get a false
- match on /chosen.interrupt_controller */
- if ((name != NULL
- && strcmp(name, "interrupt-controller") == 0)
- || (ic != NULL && iclen == 0
- && strcmp(name, "AppleKiwi"))) {
- if (n == 0)
- dflt_interrupt_controller = np;
- ++n;
- }
- }
- num_interrupt_controllers = n;
-}
-
-/**
- * finish_device_tree is called once things are running normally
- * (i.e. with text and data mapped to the address they were linked at).
- * It traverses the device tree and fills in some of the additional,
- * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt
- * mapping is also initialized at this point.
- */
-void __init finish_device_tree(void)
-{
- unsigned long start, end, size = 0;
-
- DBG(" -> finish_device_tree\n");
-
-#ifdef CONFIG_PPC64
- /* Initialize virtual IRQ map */
- virt_irq_init();
-#endif
- scan_interrupt_controllers();
-
- /*
- * Finish device-tree (pre-parsing some properties etc...)
- * We do this in 2 passes. One with "measure_only" set, which
- * will only measure the amount of memory needed, then we can
- * allocate that memory, and call finish_node again. However,
- * we must be careful as most routines will fail nowadays when
- * prom_alloc() returns 0, so we must make sure our first pass
- * doesn't start at 0. We pre-initialize size to 16 for that
- * reason and then remove those additional 16 bytes
- */
- size = 16;
- finish_node(allnodes, &size, 1);
- size -= 16;
-
- if (0 == size)
- end = start = 0;
- else
- end = start = (unsigned long)__va(lmb_alloc(size, 128));
-
- finish_node(allnodes, &end, 0);
- BUG_ON(end != start + size);
-
- DBG(" <- finish_device_tree\n");
-}
-
static inline char *find_flat_dt_string(u32 offset)
{
return ((char *)initial_boot_params) +
@@ -952,6 +535,7 @@ static struct ibm_pa_feature {
/* put this back once we know how to test if firmware does 64k IO */
{CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0},
#endif
+ {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
};
static void __init check_cpu_pa_features(unsigned long node)
@@ -1124,24 +708,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
tce_alloc_end = *lprop;
#endif
-#ifdef CONFIG_PPC_RTAS
- /* To help early debugging via the front panel, we retrieve a minimal
- * set of RTAS infos now if available
- */
- {
- u64 *basep, *entryp, *sizep;
-
- basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
- entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
- sizep = of_get_flat_dt_prop(node, "linux,rtas-size", NULL);
- if (basep && entryp && sizep) {
- rtas.base = *basep;
- rtas.entry = *entryp;
- rtas.size = *sizep;
- }
- }
-#endif /* CONFIG_PPC_RTAS */
-
#ifdef CONFIG_KEXEC
lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
if (lprop)
@@ -1191,24 +757,9 @@ static int __init early_init_dt_scan_root(unsigned long node,
static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
{
cell_t *p = *cellp;
- unsigned long r;
- /* Ignore more than 2 cells */
- while (s > sizeof(unsigned long) / 4) {
- p++;
- s--;
- }
- r = *p++;
-#ifdef CONFIG_PPC64
- if (s > 1) {
- r <<= 32;
- r |= *(p++);
- s--;
- }
-#endif
-
- *cellp = p;
- return r;
+ *cellp = p + s;
+ return of_read_ulong(p, s);
}
@@ -1326,6 +877,11 @@ void __init early_init_devtree(void *params)
/* Setup flat device-tree pointer */
initial_boot_params = params;
+#ifdef CONFIG_PPC_RTAS
+ /* Some machines might need RTAS info for debugging, grab it now. */
+ of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
+#endif
+
/* Retrieve various informations from the /chosen node of the
* device-tree, including the platform type, initrd location and
* size, TCE reserve, and more ...
@@ -1371,11 +927,11 @@ void __init early_init_devtree(void *params)
int
prom_n_addr_cells(struct device_node* np)
{
- int* ip;
+ const int *ip;
do {
if (np->parent)
np = np->parent;
- ip = (int *) get_property(np, "#address-cells", NULL);
+ ip = get_property(np, "#address-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
@@ -1387,11 +943,11 @@ EXPORT_SYMBOL(prom_n_addr_cells);
int
prom_n_size_cells(struct device_node* np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
- ip = (int *) get_property(np, "#size-cells", NULL);
+ ip = get_property(np, "#size-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
@@ -1401,27 +957,6 @@ prom_n_size_cells(struct device_node* np)
EXPORT_SYMBOL(prom_n_size_cells);
/**
- * Work out the sense (active-low level / active-high edge)
- * of each interrupt from the device tree.
- */
-void __init prom_get_irq_senses(unsigned char *senses, int off, int max)
-{
- struct device_node *np;
- int i, j;
-
- /* default to level-triggered */
- memset(senses, IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE, max - off);
-
- for (np = allnodes; np != 0; np = np->allnext) {
- for (j = 0; j < np->n_intrs; j++) {
- i = np->intrs[j].line;
- if (i >= off && i < max)
- senses[i-off] = np->intrs[j].sense;
- }
- }
-}
-
-/**
* Construct and return a list of the device_nodes with a given name.
*/
struct device_node *find_devices(const char *name)
@@ -1484,7 +1019,7 @@ int device_is_compatible(struct device_node *device, const char *compat)
const char* cp;
int cplen, l;
- cp = (char *) get_property(device, "compatible", &cplen);
+ cp = get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -1820,7 +1355,6 @@ static void of_node_release(struct kref *kref)
node->deadprops = NULL;
}
}
- kfree(node->intrs);
kfree(node->full_name);
kfree(node->data);
kfree(node);
@@ -1893,20 +1427,14 @@ void of_detach_node(const struct device_node *np)
#ifdef CONFIG_PPC_PSERIES
/*
* Fix up the uninitialized fields in a new device node:
- * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
- *
- * A lot of boot-time code is duplicated here, because functions such
- * as finish_node_interrupts, interpret_pci_props, etc. cannot use the
- * slab allocator.
- *
- * This should probably be split up into smaller chunks.
+ * name, type and pci-specific fields
*/
static int of_finish_dynamic_node(struct device_node *node)
{
struct device_node *parent = of_get_parent(node);
int err = 0;
- phandle *ibm_phandle;
+ const phandle *ibm_phandle;
node->name = get_property(node, "name", NULL);
node->type = get_property(node, "device_type", NULL);
@@ -1923,8 +1451,7 @@ static int of_finish_dynamic_node(struct device_node *node)
return -ENODEV;
/* fix up new node's linux_phandle field */
- if ((ibm_phandle = (unsigned int *)get_property(node,
- "ibm,phandle", NULL)))
+ if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
out:
@@ -1940,8 +1467,6 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
switch (action) {
case PSERIES_RECONFIG_ADD:
err = of_finish_dynamic_node(node);
- if (!err)
- finish_node(node, NULL, 0);
if (err < 0) {
printk(KERN_ERR "finish_node returned %d\n", err);
err = NOTIFY_BAD;
@@ -1987,8 +1512,7 @@ struct property *of_find_property(struct device_node *np, const char *name,
* Find a property with a given name for a given node
* and return the value.
*/
-unsigned char *get_property(struct device_node *np, const char *name,
- int *lenp)
+const void *get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
@@ -2118,16 +1642,16 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
hardid = get_hard_smp_processor_id(cpu);
for_each_node_by_type(np, "cpu") {
- u32 *intserv;
+ const u32 *intserv;
unsigned int plen, t;
/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
* fallback to "reg" property and assume no threads
*/
- intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s",
- &plen);
+ intserv = get_property(np, "ibm,ppc-interrupt-server#s",
+ &plen);
if (intserv == NULL) {
- u32 *reg = (u32 *)get_property(np, "reg", NULL);
+ const u32 *reg = get_property(np, "reg", NULL);
if (reg == NULL)
continue;
if (*reg == hardid) {
@@ -2148,3 +1672,27 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
}
return NULL;
}
+
+#ifdef DEBUG
+static struct debugfs_blob_wrapper flat_dt_blob;
+
+static int __init export_flat_device_tree(void)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir("powerpc", NULL);
+ if (!d)
+ return 1;
+
+ flat_dt_blob.data = initial_boot_params;
+ flat_dt_blob.size = initial_boot_params->totalsize;
+
+ d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
+ d, &flat_dt_blob);
+ if (!d)
+ return 1;
+
+ return 0;
+}
+__initcall(export_flat_device_tree);
+#endif
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 8c28eb0cbdac..b91761639d96 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -16,7 +16,6 @@
#undef DEBUG_PROM
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -558,7 +557,9 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
static void __init early_cmdline_parse(void)
{
struct prom_t *_prom = &RELOC(prom);
+#ifdef CONFIG_PPC64
const char *opt;
+#endif
char *p;
int l = 0;
@@ -645,13 +646,13 @@ static unsigned char ibm_architecture_vec[] = {
5 - 1, /* 5 option vectors */
/* option vector 1: processor architectures supported */
- 3 - 1, /* length */
+ 3 - 2, /* length */
0, /* don't ignore, don't halt */
OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
OV1_PPC_2_04 | OV1_PPC_2_05,
/* option vector 2: Open Firmware options supported */
- 34 - 1, /* length */
+ 34 - 2, /* length */
OV2_REAL_MODE,
0, 0,
W(0xffffffff), /* real_base */
@@ -665,16 +666,16 @@ static unsigned char ibm_architecture_vec[] = {
48, /* max log_2(hash table size) */
/* option vector 3: processor options supported */
- 3 - 1, /* length */
+ 3 - 2, /* length */
0, /* don't ignore, don't halt */
OV3_FP | OV3_VMX,
/* option vector 4: IBM PAPR implementation */
- 2 - 1, /* length */
+ 2 - 2, /* length */
0, /* don't halt */
/* option vector 5: PAPR/OF options */
- 3 - 1, /* length */
+ 3 - 2, /* length */
0, /* don't ignore, don't halt */
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
};
@@ -988,7 +989,7 @@ static void reserve_mem(u64 base, u64 size)
}
/*
- * Initialize memory allocation mecanism, parse "memory" nodes and
+ * Initialize memory allocation mechanism, parse "memory" nodes and
* obtain that way the top of memory and RMO to setup out local allocator
*/
static void __init prom_init_mem(void)
@@ -1991,12 +1992,22 @@ static void __init flatten_device_tree(void)
static void __init fixup_device_tree_maple(void)
{
phandle isa;
+ u32 rloc = 0x01002000; /* IO space; PCI device = 4 */
u32 isa_ranges[6];
-
- isa = call_prom("finddevice", 1, 1, ADDR("/ht@0/isa@4"));
+ char *name;
+
+ name = "/ht@0/isa@4";
+ isa = call_prom("finddevice", 1, 1, ADDR(name));
+ if (!PHANDLE_VALID(isa)) {
+ name = "/ht@0/isa@6";
+ isa = call_prom("finddevice", 1, 1, ADDR(name));
+ rloc = 0x01003000; /* IO space; PCI device = 6 */
+ }
if (!PHANDLE_VALID(isa))
return;
+ if (prom_getproplen(isa, "ranges") != 12)
+ return;
if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges))
== PROM_ERROR)
return;
@@ -2006,21 +2017,60 @@ static void __init fixup_device_tree_maple(void)
isa_ranges[2] != 0x00010000)
return;
- prom_printf("fixing up bogus ISA range on Maple...\n");
+ prom_printf("Fixing up bogus ISA range on Maple/Apache...\n");
isa_ranges[0] = 0x1;
isa_ranges[1] = 0x0;
- isa_ranges[2] = 0x01002000; /* IO space; PCI device = 4 */
+ isa_ranges[2] = rloc;
isa_ranges[3] = 0x0;
isa_ranges[4] = 0x0;
isa_ranges[5] = 0x00010000;
- prom_setprop(isa, "/ht@0/isa@4", "ranges",
+ prom_setprop(isa, name, "ranges",
isa_ranges, sizeof(isa_ranges));
}
#else
#define fixup_device_tree_maple()
#endif
+#ifdef CONFIG_PPC_CHRP
+/* Pegasos and BriQ lacks the "ranges" property in the isa node */
+static void __init fixup_device_tree_chrp(void)
+{
+ phandle isa;
+ u32 isa_ranges[6];
+ u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
+ char *name;
+ int rc;
+
+ name = "/pci@80000000/isa@c";
+ isa = call_prom("finddevice", 1, 1, ADDR(name));
+ if (!PHANDLE_VALID(isa)) {
+ name = "/pci@ff500000/isa@6";
+ isa = call_prom("finddevice", 1, 1, ADDR(name));
+ rloc = 0x01003000; /* IO space; PCI device = 6 */
+ }
+ if (!PHANDLE_VALID(isa))
+ return;
+
+ rc = prom_getproplen(isa, "ranges");
+ if (rc != 0 && rc != PROM_ERROR)
+ return;
+
+ prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+ isa_ranges[0] = 0x1;
+ isa_ranges[1] = 0x0;
+ isa_ranges[2] = rloc;
+ isa_ranges[3] = 0x0;
+ isa_ranges[4] = 0x0;
+ isa_ranges[5] = 0x00010000;
+ prom_setprop(isa, name, "ranges",
+ isa_ranges, sizeof(isa_ranges));
+}
+#else
+#define fixup_device_tree_chrp()
+#endif
+
#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
static void __init fixup_device_tree_pmac(void)
{
@@ -2068,6 +2118,7 @@ static void __init fixup_device_tree_pmac(void)
static void __init fixup_device_tree(void)
{
fixup_device_tree_maple();
+ fixup_device_tree_chrp();
fixup_device_tree_pmac();
}
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 45df420383cc..603dff3ad62a 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -27,7 +27,7 @@
/* Debug utility */
#ifdef DEBUG
-static void of_dump_addr(const char *s, u32 *addr, int na)
+static void of_dump_addr(const char *s, const u32 *addr, int na)
{
printk("%s", s);
while(na--)
@@ -35,17 +35,9 @@ static void of_dump_addr(const char *s, u32 *addr, int na)
printk("\n");
}
#else
-static void of_dump_addr(const char *s, u32 *addr, int na) { }
+static void of_dump_addr(const char *s, const u32 *addr, int na) { }
#endif
-/* Read a big address */
-static inline u64 of_read_addr(u32 *cell, int size)
-{
- u64 r = 0;
- while (size--)
- r = (r << 32) | *(cell++);
- return r;
-}
/* Callbacks for bus specific translators */
struct of_bus {
@@ -54,9 +46,10 @@ struct of_bus {
int (*match)(struct device_node *parent);
void (*count_cells)(struct device_node *child,
int *addrc, int *sizec);
- u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+ u64 (*map)(u32 *addr, const u32 *range,
+ int na, int ns, int pna);
int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(u32 *addr);
+ unsigned int (*get_flags)(const u32 *addr);
};
@@ -73,13 +66,14 @@ static void of_bus_default_count_cells(struct device_node *dev,
*sizec = prom_n_size_cells(dev);
}
-static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static u64 of_bus_default_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
{
u64 cp, s, da;
- cp = of_read_addr(range, na);
- s = of_read_addr(range + na + pna, ns);
- da = of_read_addr(addr, na);
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
cp, s, da);
@@ -91,7 +85,7 @@ static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
static int of_bus_default_translate(u32 *addr, u64 offset, int na)
{
- u64 a = of_read_addr(addr, na);
+ u64 a = of_read_number(addr, na);
memset(addr, 0, na * 4);
a += offset;
if (na > 1)
@@ -101,7 +95,7 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na)
return 0;
}
-static unsigned int of_bus_default_get_flags(u32 *addr)
+static unsigned int of_bus_default_get_flags(const u32 *addr)
{
return IORESOURCE_MEM;
}
@@ -126,7 +120,7 @@ static void of_bus_pci_count_cells(struct device_node *np,
*sizec = 2;
}
-static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
@@ -135,9 +129,9 @@ static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
return OF_BAD_ADDR;
/* Read address values, skipping high cell */
- cp = of_read_addr(range + 1, na - 1);
- s = of_read_addr(range + na + pna, ns);
- da = of_read_addr(addr + 1, na - 1);
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
@@ -151,7 +145,7 @@ static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
return of_bus_default_translate(addr + 1, offset, na - 1);
}
-static unsigned int of_bus_pci_get_flags(u32 *addr)
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
@@ -186,7 +180,7 @@ static void of_bus_isa_count_cells(struct device_node *child,
*sizec = 1;
}
-static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
@@ -195,9 +189,9 @@ static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
return OF_BAD_ADDR;
/* Read address values, skipping high cell */
- cp = of_read_addr(range + 1, na - 1);
- s = of_read_addr(range + na + pna, ns);
- da = of_read_addr(addr + 1, na - 1);
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
@@ -211,7 +205,7 @@ static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
return of_bus_default_translate(addr + 1, offset, na - 1);
}
-static unsigned int of_bus_isa_get_flags(u32 *addr)
+static unsigned int of_bus_isa_get_flags(const u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
@@ -276,7 +270,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
struct of_bus *pbus, u32 *addr,
int na, int ns, int pna)
{
- u32 *ranges;
+ const u32 *ranges;
unsigned int rlen;
int rone;
u64 offset = OF_BAD_ADDR;
@@ -293,9 +287,9 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* to translate addresses that aren't supposed to be translated in
* the first place. --BenH.
*/
- ranges = (u32 *)get_property(parent, "ranges", &rlen);
+ ranges = get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
- offset = of_read_addr(addr, na);
+ offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
DBG("OF: no ranges, 1:1 translation\n");
goto finish;
@@ -336,7 +330,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* that can be mapped to a cpu physical address). This is not really specified
* that way, but this is traditionally the way IBM at least do things
*/
-u64 of_translate_address(struct device_node *dev, u32 *in_addr)
+u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
{
struct device_node *parent = NULL;
struct of_bus *bus, *pbus;
@@ -378,7 +372,7 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr)
/* If root, we have finished */
if (parent == NULL) {
DBG("OF: reached root node\n");
- result = of_read_addr(addr, na);
+ result = of_read_number(addr, na);
break;
}
@@ -413,10 +407,10 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr)
}
EXPORT_SYMBOL(of_translate_address);
-u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
unsigned int *flags)
{
- u32 *prop;
+ const u32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
@@ -433,7 +427,7 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = (u32 *)get_property(dev, bus->addresses, &psize);
+ prop = get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -442,7 +436,7 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size,
for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
if (i == index) {
if (size)
- *size = of_read_addr(prop + na, ns);
+ *size = of_read_number(prop + na, ns);
if (flags)
*flags = bus->get_flags(prop);
return prop;
@@ -451,10 +445,10 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size,
}
EXPORT_SYMBOL(of_get_address);
-u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
unsigned int *flags)
{
- u32 *prop;
+ const u32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
@@ -475,7 +469,7 @@ u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = (u32 *)get_property(dev, bus->addresses, &psize);
+ prop = get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -484,7 +478,7 @@ u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
if (size)
- *size = of_read_addr(prop + na, ns);
+ *size = of_read_number(prop + na, ns);
if (flags)
*flags = bus->get_flags(prop);
return prop;
@@ -493,7 +487,7 @@ u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
}
EXPORT_SYMBOL(of_get_pci_address);
-static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
+static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
u64 size, unsigned int flags,
struct resource *r)
{
@@ -524,7 +518,7 @@ static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
- u32 *addrp;
+ const u32 *addrp;
u64 size;
unsigned int flags;
@@ -538,7 +532,7 @@ EXPORT_SYMBOL_GPL(of_address_to_resource);
int of_pci_address_to_resource(struct device_node *dev, int bar,
struct resource *r)
{
- u32 *addrp;
+ const u32 *addrp;
u64 size;
unsigned int flags;
@@ -549,13 +543,14 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
-void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
+void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
unsigned long *busno, unsigned long *phys, unsigned long *size)
{
- u32 *dma_window, cells;
- unsigned char *prop;
+ const u32 *dma_window;
+ u32 cells;
+ const unsigned char *prop;
- dma_window = (u32 *)dma_window_prop;
+ dma_window = dma_window_prop;
/* busno is always one cell */
*busno = *(dma_window++);
@@ -565,11 +560,425 @@ void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
prop = get_property(dn, "#address-cells", NULL);
cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
- *phys = of_read_addr(dma_window, cells);
+ *phys = of_read_number(dma_window, cells);
dma_window += cells;
prop = get_property(dn, "ibm,#dma-size-cells", NULL);
cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
- *size = of_read_addr(dma_window, cells);
+ *size = of_read_number(dma_window, cells);
+}
+
+/*
+ * Interrupt remapper
+ */
+
+static unsigned int of_irq_workarounds;
+static struct device_node *of_irq_dflt_pic;
+
+static struct device_node *of_irq_find_parent(struct device_node *child)
+{
+ struct device_node *p;
+ const phandle *parp;
+
+ if (!of_node_get(child))
+ return NULL;
+
+ do {
+ parp = get_property(child, "interrupt-parent", NULL);
+ if (parp == NULL)
+ p = of_get_parent(child);
+ else {
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ p = of_node_get(of_irq_dflt_pic);
+ else
+ p = of_find_node_by_phandle(*parp);
+ }
+ of_node_put(child);
+ child = p;
+ } while (p && get_property(p, "#interrupt-cells", NULL) == NULL);
+
+ return p;
+}
+
+/* This doesn't need to be called if you don't have any special workaround
+ * flags to pass
+ */
+void of_irq_map_init(unsigned int flags)
+{
+ of_irq_workarounds = flags;
+
+ /* OldWorld, don't bother looking at other things */
+ if (flags & OF_IMAP_OLDWORLD_MAC)
+ return;
+
+ /* If we don't have phandles, let's try to locate a default interrupt
+ * controller (happens when booting with BootX). We do a first match
+ * here, hopefully, that only ever happens on machines with one
+ * controller.
+ */
+ if (flags & OF_IMAP_NO_PHANDLE) {
+ struct device_node *np;
+
+ for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
+ if (get_property(np, "interrupt-controller", NULL)
+ == NULL)
+ continue;
+ /* Skip /chosen/interrupt-controller */
+ if (strcmp(np->name, "chosen") == 0)
+ continue;
+ /* It seems like at least one person on this planet wants
+ * to use BootX on a machine with an AppleKiwi controller
+ * which happens to pretend to be an interrupt
+ * controller too.
+ */
+ if (strcmp(np->name, "AppleKiwi") == 0)
+ continue;
+ /* I think we found one ! */
+ of_irq_dflt_pic = np;
+ break;
+ }
+ }
+
+}
+
+int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
+ const u32 *addr, struct of_irq *out_irq)
+{
+ struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
+ const u32 *tmp, *imap, *imask;
+ u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
+ int imaplen, match, i;
+
+ DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
+ parent->full_name, intspec[0], intspec[1], ointsize);
+
+ ipar = of_node_get(parent);
+
+ /* First get the #interrupt-cells property of the current cursor
+ * that tells us how to interpret the passed-in intspec. If there
+ * is none, we are nice and just walk up the tree
+ */
+ do {
+ tmp = get_property(ipar, "#interrupt-cells", NULL);
+ if (tmp != NULL) {
+ intsize = *tmp;
+ break;
+ }
+ tnode = ipar;
+ ipar = of_irq_find_parent(ipar);
+ of_node_put(tnode);
+ } while (ipar);
+ if (ipar == NULL) {
+ DBG(" -> no parent found !\n");
+ goto fail;
+ }
+
+ DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
+
+ if (ointsize != intsize)
+ return -EINVAL;
+
+ /* Look for this #address-cells. We have to implement the old linux
+ * trick of looking for the parent here as some device-trees rely on it
+ */
+ old = of_node_get(ipar);
+ do {
+ tmp = get_property(old, "#address-cells", NULL);
+ tnode = of_get_parent(old);
+ of_node_put(old);
+ old = tnode;
+ } while(old && tmp == NULL);
+ of_node_put(old);
+ old = NULL;
+ addrsize = (tmp == NULL) ? 2 : *tmp;
+
+ DBG(" -> addrsize=%d\n", addrsize);
+
+ /* Now start the actual "proper" walk of the interrupt tree */
+ while (ipar != NULL) {
+ /* Now check if cursor is an interrupt-controller and if it is
+ * then we are done
+ */
+ if (get_property(ipar, "interrupt-controller", NULL) != NULL) {
+ DBG(" -> got it !\n");
+ memcpy(out_irq->specifier, intspec,
+ intsize * sizeof(u32));
+ out_irq->size = intsize;
+ out_irq->controller = ipar;
+ of_node_put(old);
+ return 0;
+ }
+
+ /* Now look for an interrupt-map */
+ imap = get_property(ipar, "interrupt-map", &imaplen);
+ /* No interrupt map, check for an interrupt parent */
+ if (imap == NULL) {
+ DBG(" -> no map, getting parent\n");
+ newpar = of_irq_find_parent(ipar);
+ goto skiplevel;
+ }
+ imaplen /= sizeof(u32);
+
+ /* Look for a mask */
+ imask = get_property(ipar, "interrupt-map-mask", NULL);
+
+ /* If we were passed no "reg" property and we attempt to parse
+ * an interrupt-map, then #address-cells must be 0.
+ * Fail if it's not.
+ */
+ if (addr == NULL && addrsize != 0) {
+ DBG(" -> no reg passed in when needed !\n");
+ goto fail;
+ }
+
+ /* Parse interrupt-map */
+ match = 0;
+ while (imaplen > (addrsize + intsize + 1) && !match) {
+ /* Compare specifiers */
+ match = 1;
+ for (i = 0; i < addrsize && match; ++i) {
+ u32 mask = imask ? imask[i] : 0xffffffffu;
+ match = ((addr[i] ^ imap[i]) & mask) == 0;
+ }
+ for (; i < (addrsize + intsize) && match; ++i) {
+ u32 mask = imask ? imask[i] : 0xffffffffu;
+ match =
+ ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
+ }
+ imap += addrsize + intsize;
+ imaplen -= addrsize + intsize;
+
+ DBG(" -> match=%d (imaplen=%d)\n", match, imaplen);
+
+ /* Get the interrupt parent */
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ newpar = of_node_get(of_irq_dflt_pic);
+ else
+ newpar = of_find_node_by_phandle((phandle)*imap);
+ imap++;
+ --imaplen;
+
+ /* Check if not found */
+ if (newpar == NULL) {
+ DBG(" -> imap parent not found !\n");
+ goto fail;
+ }
+
+ /* Get #interrupt-cells and #address-cells of new
+ * parent
+ */
+ tmp = get_property(newpar, "#interrupt-cells",
+ NULL);
+ if (tmp == NULL) {
+ DBG(" -> parent lacks #interrupt-cells !\n");
+ goto fail;
+ }
+ newintsize = *tmp;
+ tmp = get_property(newpar, "#address-cells",
+ NULL);
+ newaddrsize = (tmp == NULL) ? 0 : *tmp;
+
+ DBG(" -> newintsize=%d, newaddrsize=%d\n",
+ newintsize, newaddrsize);
+
+ /* Check for malformed properties */
+ if (imaplen < (newaddrsize + newintsize))
+ goto fail;
+
+ imap += newaddrsize + newintsize;
+ imaplen -= newaddrsize + newintsize;
+
+ DBG(" -> imaplen=%d\n", imaplen);
+ }
+ if (!match)
+ goto fail;
+
+ of_node_put(old);
+ old = of_node_get(newpar);
+ addrsize = newaddrsize;
+ intsize = newintsize;
+ intspec = imap - intsize;
+ addr = intspec - addrsize;
+
+ skiplevel:
+ /* Iterate again with new parent */
+ DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
+ of_node_put(ipar);
+ ipar = newpar;
+ newpar = NULL;
+ }
+ fail:
+ of_node_put(ipar);
+ of_node_put(old);
+ of_node_put(newpar);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(of_irq_map_raw);
+
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
+static int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq)
+{
+ const u32 *ints;
+ int intlen;
+
+ /*
+ * Old machines just have a list of interrupt numbers
+ * and no interrupt-controller nodes.
+ */
+ ints = get_property(device, "AAPL,interrupts", &intlen);
+ if (ints == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+
+ if (index >= intlen)
+ return -EINVAL;
+
+ out_irq->controller = NULL;
+ out_irq->specifier[0] = ints[index];
+ out_irq->size = 1;
+
+ return 0;
+}
+#else /* defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) */
+static int of_irq_map_oldworld(struct device_node *device, int index,
+ struct of_irq *out_irq)
+{
+ return -EINVAL;
+}
+#endif /* !(defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)) */
+
+int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
+{
+ struct device_node *p;
+ const u32 *intspec, *tmp, *addr;
+ u32 intsize, intlen;
+ int res;
+
+ DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
+
+ /* OldWorld mac stuff is "special", handle out of line */
+ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+ return of_irq_map_oldworld(device, index, out_irq);
+
+ /* Get the interrupts property */
+ intspec = get_property(device, "interrupts", &intlen);
+ if (intspec == NULL)
+ return -EINVAL;
+ intlen /= sizeof(u32);
+
+ /* Get the reg property (if any) */
+ addr = get_property(device, "reg", NULL);
+
+ /* Look for the interrupt parent. */
+ p = of_irq_find_parent(device);
+ if (p == NULL)
+ return -EINVAL;
+
+ /* Get size of interrupt specifier */
+ tmp = get_property(p, "#interrupt-cells", NULL);
+ if (tmp == NULL) {
+ of_node_put(p);
+ return -EINVAL;
+ }
+ intsize = *tmp;
+
+ DBG(" intsize=%d intlen=%d\n", intsize, intlen);
+
+ /* Check index */
+ if ((index + 1) * intsize > intlen)
+ return -EINVAL;
+
+ /* Get new specifier and map it */
+ res = of_irq_map_raw(p, intspec + index * intsize, intsize,
+ addr, out_irq);
+ of_node_put(p);
+ return res;
+}
+EXPORT_SYMBOL_GPL(of_irq_map_one);
+
+#ifdef CONFIG_PCI
+static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
+{
+ return (((pin - 1) + slot) % 4) + 1;
+}
+
+int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
+{
+ struct device_node *dn, *ppnode;
+ struct pci_dev *ppdev;
+ u32 lspec;
+ u32 laddr[3];
+ u8 pin;
+ int rc;
+
+ /* Check if we have a device node, if yes, fallback to standard OF
+ * parsing
+ */
+ dn = pci_device_to_OF_node(pdev);
+ if (dn)
+ return of_irq_map_one(dn, 0, out_irq);
+
+ /* Ok, we don't, time to have fun. Let's start by building up an
+ * interrupt spec. we assume #interrupt-cells is 1, which is standard
+ * for PCI. If you do different, then don't use that routine.
+ */
+ rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
+ if (rc != 0)
+ return rc;
+ /* No pin, exit */
+ if (pin == 0)
+ return -ENODEV;
+
+ /* Now we walk up the PCI tree */
+ lspec = pin;
+ for (;;) {
+ /* Get the pci_dev of our parent */
+ ppdev = pdev->bus->self;
+
+ /* Ouch, it's a host bridge... */
+ if (ppdev == NULL) {
+#ifdef CONFIG_PPC64
+ ppnode = pci_bus_to_OF_node(pdev->bus);
+#else
+ struct pci_controller *host;
+ host = pci_bus_to_host(pdev->bus);
+ ppnode = host ? host->arch_data : NULL;
+#endif
+ /* No node for host bridge ? give up */
+ if (ppnode == NULL)
+ return -EINVAL;
+ } else
+ /* We found a P2P bridge, check if it has a node */
+ ppnode = pci_device_to_OF_node(ppdev);
+
+ /* Ok, we have found a parent with a device-node, hand over to
+ * the OF parsing code.
+ * We build a unit address from the linux device to be used for
+ * resolution. Note that we use the linux bus number which may
+ * not match your firmware bus numbering.
+ * Fortunately, in most cases, interrupt-map-mask doesn't include
+ * the bus number as part of the matching.
+ * You should still be careful about that though if you intend
+ * to rely on this function (you ship a firmware that doesn't
+ * create device nodes for all PCI devices).
+ */
+ if (ppnode)
+ break;
+
+ /* We can only get here if we hit a P2P bridge with no node,
+ * let's do standard swizzling and try again
+ */
+ lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec);
+ pdev = ppdev;
+ }
+
+ laddr[0] = (pdev->bus->number << 16)
+ | (pdev->devfn << 8);
+ laddr[1] = laddr[2] = 0;
+ return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq);
}
+EXPORT_SYMBOL_GPL(of_irq_map_pci);
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h
index c42a860c8d25..8797ae737a7b 100644
--- a/arch/powerpc/kernel/ptrace-common.h
+++ b/arch/powerpc/kernel/ptrace-common.h
@@ -10,7 +10,6 @@
#ifndef _PPC64_PTRACE_COMMON_H
#define _PPC64_PTRACE_COMMON_H
-#include <linux/config.h>
#include <asm/system.h>
/*
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 5563e2e7d89c..dea75d73f983 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -15,7 +15,6 @@
* this archive for more details.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 826ee3d056de..9b9a230349bc 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -17,7 +17,6 @@
* this archive for more details.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 9c9ad1fa9cce..2fe82abf1c52 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -246,12 +246,12 @@ struct file_operations ppc_rtas_rmo_buf_ops = {
static int ppc_rtas_find_all_sensors(void);
static void ppc_rtas_process_sensor(struct seq_file *m,
- struct individual_sensor *s, int state, int error, char *loc);
+ struct individual_sensor *s, int state, int error, const char *loc);
static char *ppc_rtas_process_error(int error);
static void get_location_code(struct seq_file *m,
- struct individual_sensor *s, char *loc);
-static void check_location_string(struct seq_file *m, char *c);
-static void check_location(struct seq_file *m, char *c);
+ struct individual_sensor *s, const char *loc);
+static void check_location_string(struct seq_file *m, const char *c);
+static void check_location(struct seq_file *m, const char *c);
static int __init proc_rtas_init(void)
{
@@ -446,11 +446,11 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
for (i=0; i<sensors.quant; i++) {
struct individual_sensor *p = &sensors.sensor[i];
char rstr[64];
- char *loc;
+ const char *loc;
int llen, offs;
sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
- loc = (char *) get_property(rtas_node, rstr, &llen);
+ loc = get_property(rtas_node, rstr, &llen);
/* A sensor may have multiple instances */
for (j = 0, offs = 0; j <= p->quant; j++) {
@@ -474,10 +474,10 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
static int ppc_rtas_find_all_sensors(void)
{
- unsigned int *utmp;
+ const unsigned int *utmp;
int len, i;
- utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len);
+ utmp = get_property(rtas_node, "rtas-sensors", &len);
if (utmp == NULL) {
printk (KERN_ERR "error: could not get rtas-sensors\n");
return 1;
@@ -530,7 +530,7 @@ static char *ppc_rtas_process_error(int error)
*/
static void ppc_rtas_process_sensor(struct seq_file *m,
- struct individual_sensor *s, int state, int error, char *loc)
+ struct individual_sensor *s, int state, int error, const char *loc)
{
/* Defined return vales */
const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t",
@@ -682,7 +682,7 @@ static void ppc_rtas_process_sensor(struct seq_file *m,
/* ****************************************************************** */
-static void check_location(struct seq_file *m, char *c)
+static void check_location(struct seq_file *m, const char *c)
{
switch (c[0]) {
case LOC_PLANAR:
@@ -719,7 +719,7 @@ static void check_location(struct seq_file *m, char *c)
* ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ]
* the '.' may be an abbrevation
*/
-static void check_location_string(struct seq_file *m, char *c)
+static void check_location_string(struct seq_file *m, const char *c)
{
while (*c) {
if (isalpha(*c) || *c == '.')
@@ -733,7 +733,8 @@ static void check_location_string(struct seq_file *m, char *c)
/* ****************************************************************** */
-static void get_location_code(struct seq_file *m, struct individual_sensor *s, char *loc)
+static void get_location_code(struct seq_file *m, struct individual_sensor *s,
+ const char *loc)
{
if (!loc || !*loc) {
seq_printf(m, "---");/* does not have a location */
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 17dc79198515..6ef80d4e38d3 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -38,16 +38,19 @@
struct rtas_t rtas = {
.lock = SPIN_LOCK_UNLOCKED
};
+EXPORT_SYMBOL(rtas);
struct rtas_suspend_me_data {
long waiting;
struct rtas_args *args;
};
-EXPORT_SYMBOL(rtas);
-
DEFINE_SPINLOCK(rtas_data_buf_lock);
+EXPORT_SYMBOL(rtas_data_buf_lock);
+
char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
+EXPORT_SYMBOL(rtas_data_buf);
+
unsigned long rtas_rmo_buf;
/*
@@ -106,18 +109,80 @@ static void call_rtas_display_status_delay(char c)
}
}
-void __init udbg_init_rtas(void)
+void __init udbg_init_rtas_panel(void)
{
udbg_putc = call_rtas_display_status_delay;
}
+#ifdef CONFIG_UDBG_RTAS_CONSOLE
+
+/* If you think you're dying before early_init_dt_scan_rtas() does its
+ * work, you can hard code the token values for your firmware here and
+ * hardcode rtas.base/entry etc.
+ */
+static unsigned int rtas_putchar_token = RTAS_UNKNOWN_SERVICE;
+static unsigned int rtas_getchar_token = RTAS_UNKNOWN_SERVICE;
+
+static void udbg_rtascon_putc(char c)
+{
+ int tries;
+
+ if (!rtas.base)
+ return;
+
+ /* Add CRs before LFs */
+ if (c == '\n')
+ udbg_rtascon_putc('\r');
+
+ /* if there is more than one character to be displayed, wait a bit */
+ for (tries = 0; tries < 16; tries++) {
+ if (rtas_call(rtas_putchar_token, 1, 1, NULL, c) == 0)
+ break;
+ udelay(1000);
+ }
+}
+
+static int udbg_rtascon_getc_poll(void)
+{
+ int c;
+
+ if (!rtas.base)
+ return -1;
+
+ if (rtas_call(rtas_getchar_token, 0, 2, &c))
+ return -1;
+
+ return c;
+}
+
+static int udbg_rtascon_getc(void)
+{
+ int c;
+
+ while ((c = udbg_rtascon_getc_poll()) == -1)
+ ;
+
+ return c;
+}
+
+
+void __init udbg_init_rtas_console(void)
+{
+ udbg_putc = udbg_rtascon_putc;
+ udbg_getc = udbg_rtascon_getc;
+ udbg_getc_poll = udbg_rtascon_getc_poll;
+}
+#endif /* CONFIG_UDBG_RTAS_CONSOLE */
+
void rtas_progress(char *s, unsigned short hex)
{
struct device_node *root;
- int width, *p;
+ int width;
+ const int *p;
char *os;
static int display_character, set_indicator;
- static int display_width, display_lines, *row_width, form_feed;
+ static int display_width, display_lines, form_feed;
+ const static int *row_width;
static DEFINE_SPINLOCK(progress_lock);
static int current_line;
static int pending_newline = 0; /* did last write end with unprinted newline? */
@@ -128,16 +193,16 @@ void rtas_progress(char *s, unsigned short hex)
if (display_width == 0) {
display_width = 0x10;
if ((root = find_path_device("/rtas"))) {
- if ((p = (unsigned int *)get_property(root,
+ if ((p = get_property(root,
"ibm,display-line-length", NULL)))
display_width = *p;
- if ((p = (unsigned int *)get_property(root,
+ if ((p = get_property(root,
"ibm,form-feed", NULL)))
form_feed = *p;
- if ((p = (unsigned int *)get_property(root,
+ if ((p = get_property(root,
"ibm,display-number-of-lines", NULL)))
display_lines = *p;
- row_width = (unsigned int *)get_property(root,
+ row_width = get_property(root,
"ibm,display-truncation-length", NULL);
}
display_character = rtas_token("display-character");
@@ -230,12 +295,13 @@ EXPORT_SYMBOL(rtas_progress); /* needed by rtas_flash module */
int rtas_token(const char *service)
{
- int *tokp;
+ const int *tokp;
if (rtas.dev == NULL)
return RTAS_UNKNOWN_SERVICE;
- tokp = (int *) get_property(rtas.dev, service, NULL);
+ tokp = get_property(rtas.dev, service, NULL);
return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
}
+EXPORT_SYMBOL(rtas_token);
#ifdef CONFIG_RTAS_ERROR_LOGGING
/*
@@ -328,7 +394,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
char *buff_copy = NULL;
int ret;
- if (token == RTAS_UNKNOWN_SERVICE)
+ if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
return -1;
/* Gotta do something different here, use global lock for now... */
@@ -369,6 +435,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
}
return ret;
}
+EXPORT_SYMBOL(rtas_call);
/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status
* code of 990n, perform the hinted delay of 10^n (last digit) milliseconds.
@@ -388,6 +455,7 @@ unsigned int rtas_busy_delay_time(int status)
return ms;
}
+EXPORT_SYMBOL(rtas_busy_delay_time);
/* For an RTAS busy status code, perform the hinted delay. */
unsigned int rtas_busy_delay(int status)
@@ -401,6 +469,7 @@ unsigned int rtas_busy_delay(int status)
return ms;
}
+EXPORT_SYMBOL(rtas_busy_delay);
int rtas_error_rc(int rtas_rc)
{
@@ -446,6 +515,7 @@ int rtas_get_power_level(int powerdomain, int *level)
return rtas_error_rc(rc);
return rc;
}
+EXPORT_SYMBOL(rtas_get_power_level);
int rtas_set_power_level(int powerdomain, int level, int *setlevel)
{
@@ -463,6 +533,7 @@ int rtas_set_power_level(int powerdomain, int level, int *setlevel)
return rtas_error_rc(rc);
return rc;
}
+EXPORT_SYMBOL(rtas_set_power_level);
int rtas_get_sensor(int sensor, int index, int *state)
{
@@ -480,6 +551,7 @@ int rtas_get_sensor(int sensor, int index, int *state)
return rtas_error_rc(rc);
return rc;
}
+EXPORT_SYMBOL(rtas_get_sensor);
int rtas_set_indicator(int indicator, int index, int new_value)
{
@@ -497,6 +569,28 @@ int rtas_set_indicator(int indicator, int index, int new_value)
return rtas_error_rc(rc);
return rc;
}
+EXPORT_SYMBOL(rtas_set_indicator);
+
+/*
+ * Ignoring RTAS extended delay
+ */
+int rtas_set_indicator_fast(int indicator, int index, int new_value)
+{
+ int rc;
+ int token = rtas_token("set-indicator");
+
+ if (token == RTAS_UNKNOWN_SERVICE)
+ return -ENOENT;
+
+ rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
+
+ WARN_ON(rc == -2 || (rc >= 9900 && rc <= 9905));
+
+ if (rc < 0)
+ return rtas_error_rc(rc);
+
+ return rc;
+}
void rtas_restart(char *cmd)
{
@@ -534,6 +628,9 @@ void rtas_os_term(char *str)
{
int status;
+ if (panic_timeout)
+ return;
+
if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term"))
return;
@@ -595,15 +692,14 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
int i;
long state;
long rc;
- unsigned long dummy;
-
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
struct rtas_suspend_me_data data;
/* Make sure the state is valid */
- rc = plpar_hcall(H_VASI_STATE,
- ((u64)args->args[0] << 32) | args->args[1],
- 0, 0, 0,
- &state, &dummy, &dummy);
+ rc = plpar_hcall(H_VASI_STATE, retbuf,
+ ((u64)args->args[0] << 32) | args->args[1]);
+
+ state = retbuf[0];
if (rc) {
printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
@@ -753,15 +849,15 @@ void __init rtas_initialize(void)
*/
rtas.dev = of_find_node_by_name(NULL, "rtas");
if (rtas.dev) {
- u32 *basep, *entryp;
- u32 *sizep;
+ const u32 *basep, *entryp, *sizep;
- basep = (u32 *)get_property(rtas.dev, "linux,rtas-base", NULL);
- sizep = (u32 *)get_property(rtas.dev, "rtas-size", NULL);
+ basep = get_property(rtas.dev, "linux,rtas-base", NULL);
+ sizep = get_property(rtas.dev, "rtas-size", NULL);
if (basep != NULL && sizep != NULL) {
rtas.base = *basep;
rtas.size = *sizep;
- entryp = (u32 *)get_property(rtas.dev, "linux,rtas-entry", NULL);
+ entryp = get_property(rtas.dev,
+ "linux,rtas-entry", NULL);
if (entryp == NULL) /* Ugh */
rtas.entry = rtas.base;
else
@@ -791,14 +887,39 @@ void __init rtas_initialize(void)
#endif
}
+int __init early_init_dt_scan_rtas(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ u32 *basep, *entryp, *sizep;
-EXPORT_SYMBOL(rtas_token);
-EXPORT_SYMBOL(rtas_call);
-EXPORT_SYMBOL(rtas_data_buf);
-EXPORT_SYMBOL(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_busy_delay_time);
-EXPORT_SYMBOL(rtas_busy_delay);
-EXPORT_SYMBOL(rtas_get_sensor);
-EXPORT_SYMBOL(rtas_get_power_level);
-EXPORT_SYMBOL(rtas_set_power_level);
-EXPORT_SYMBOL(rtas_set_indicator);
+ if (depth != 1 || strcmp(uname, "rtas") != 0)
+ return 0;
+
+ basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
+ entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
+ sizep = of_get_flat_dt_prop(node, "rtas-size", NULL);
+
+ if (basep && entryp && sizep) {
+ rtas.base = *basep;
+ rtas.entry = *entryp;
+ rtas.size = *sizep;
+ }
+
+#ifdef CONFIG_UDBG_RTAS_CONSOLE
+ basep = of_get_flat_dt_prop(node, "put-term-char", NULL);
+ if (basep)
+ rtas_putchar_token = *basep;
+
+ basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
+ if (basep)
+ rtas_getchar_token = *basep;
+
+ if (rtas_putchar_token != RTAS_UNKNOWN_SERVICE &&
+ rtas_getchar_token != RTAS_UNKNOWN_SERVICE)
+ udbg_init_rtas_console();
+
+#endif
+
+ /* break now */
+ return 1;
+}
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 6eb7e49b394a..b4a0de79c060 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -57,7 +57,7 @@ static inline int config_access_valid(struct pci_dn *dn, int where)
static int of_device_available(struct device_node * dn)
{
- char * status;
+ const char *status;
status = get_property(dn, "status", NULL);
@@ -81,8 +81,7 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
if (!config_access_valid(pdn, where))
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
- (pdn->devfn << 8) | (where & 0xff);
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
buid = pdn->phb->buid;
if (buid) {
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
@@ -134,8 +133,7 @@ int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val)
if (!config_access_valid(pdn, where))
return PCIBIOS_BAD_REGISTER_NUMBER;
- addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
- (pdn->devfn << 8) | (where & 0xff);
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, where);
buid = pdn->phb->buid;
if (buid) {
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr,
@@ -178,7 +176,7 @@ struct pci_ops rtas_pci_ops = {
int is_python(struct device_node *dev)
{
- char *model = (char *)get_property(dev, "model", NULL);
+ const char *model = get_property(dev, "model", NULL);
if (model && strstr(model, "Python"))
return 1;
@@ -234,7 +232,7 @@ void __init init_pci_config_tokens (void)
unsigned long __devinit get_phb_buid (struct device_node *phb)
{
int addr_cells;
- unsigned int *buid_vals;
+ const unsigned int *buid_vals;
unsigned int len;
unsigned long buid;
@@ -247,7 +245,7 @@ unsigned long __devinit get_phb_buid (struct device_node *phb)
if (phb->parent->parent)
return 0;
- buid_vals = (unsigned int *) get_property(phb, "reg", &len);
+ buid_vals = get_property(phb, "reg", &len);
if (buid_vals == NULL)
return 0;
@@ -264,10 +262,10 @@ unsigned long __devinit get_phb_buid (struct device_node *phb)
static int phb_set_bus_ranges(struct device_node *dev,
struct pci_controller *phb)
{
- int *bus_range;
+ const int *bus_range;
unsigned int len;
- bus_range = (int *) get_property(dev, "bus-range", &len);
+ bus_range = get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
return 1;
}
@@ -297,19 +295,9 @@ unsigned long __init find_and_init_phbs(void)
struct device_node *node;
struct pci_controller *phb;
unsigned int index;
- unsigned int root_size_cells = 0;
- unsigned int *opprop = NULL;
struct device_node *root = of_find_node_by_path("/");
- if (ppc64_interrupt_controller == IC_OPEN_PIC) {
- opprop = (unsigned int *)get_property(root,
- "platform-open-pic", NULL);
- }
-
- root_size_cells = prom_n_size_cells(root);
-
index = 0;
-
for (node = of_get_next_child(root, NULL);
node != NULL;
node = of_get_next_child(root, node)) {
@@ -324,13 +312,6 @@ unsigned long __init find_and_init_phbs(void)
setup_phb(node, phb);
pci_process_bridge_OF_ranges(phb, node, 0);
pci_setup_phb_io(phb, index == 0);
-#ifdef CONFIG_PPC_PSERIES
- /* XXX This code need serious fixing ... --BenH */
- if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
- int addr = root_size_cells * (index + 2) - 1;
- mpic_assign_isu(pSeries_mpic, index, opprop[addr]);
- }
-#endif
index++;
}
@@ -342,15 +323,15 @@ unsigned long __init find_and_init_phbs(void)
* in chosen.
*/
if (of_chosen) {
- int *prop;
+ const int *prop;
- prop = (int *)get_property(of_chosen, "linux,pci-probe-only",
- NULL);
+ prop = get_property(of_chosen,
+ "linux,pci-probe-only", NULL);
if (prop)
pci_probe_only = *prop;
- prop = (int *)get_property(of_chosen,
- "linux,pci-assign-all-buses", NULL);
+ prop = get_property(of_chosen,
+ "linux,pci-assign-all-buses", NULL);
if (prop)
pci_assign_all_buses = *prop;
}
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index bd328123af75..0af3fc1bdcc9 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -12,7 +12,6 @@
#undef DEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sched.h>
@@ -27,7 +26,7 @@
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/utsname.h>
-#include <linux/tty.h>
+#include <linux/screen_info.h>
#include <linux/root_dev.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
@@ -305,19 +304,21 @@ struct seq_operations cpuinfo_op = {
void __init check_for_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
- unsigned long *prop;
+ const unsigned int *prop;
+ int len;
DBG(" -> check_for_initrd()\n");
if (of_chosen) {
- prop = (unsigned long *)get_property(of_chosen,
- "linux,initrd-start", NULL);
+ prop = get_property(of_chosen, "linux,initrd-start", &len);
if (prop != NULL) {
- initrd_start = (unsigned long)__va(*prop);
- prop = (unsigned long *)get_property(of_chosen,
- "linux,initrd-end", NULL);
+ initrd_start = (unsigned long)
+ __va(of_read_ulong(prop, len / 4));
+ prop = get_property(of_chosen,
+ "linux,initrd-end", &len);
if (prop != NULL) {
- initrd_end = (unsigned long)__va(*prop);
+ initrd_end = (unsigned long)
+ __va(of_read_ulong(prop, len / 4));
initrd_below_start_ok = 1;
} else
initrd_start = 0;
@@ -367,15 +368,14 @@ void __init smp_setup_cpu_maps(void)
int cpu = 0;
while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
- int *intserv;
+ const int *intserv;
int j, len = sizeof(u32), nthreads = 1;
- intserv = (int *)get_property(dn, "ibm,ppc-interrupt-server#s",
- &len);
+ intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
if (intserv)
nthreads = len / sizeof(int);
else {
- intserv = (int *) get_property(dn, "reg", NULL);
+ intserv = get_property(dn, "reg", NULL);
if (!intserv)
intserv = &cpu; /* assume logical == phys */
}
@@ -396,13 +396,12 @@ void __init smp_setup_cpu_maps(void)
if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR) &&
(dn = of_find_node_by_path("/rtas"))) {
int num_addr_cell, num_size_cell, maxcpus;
- unsigned int *ireg;
+ const unsigned int *ireg;
num_addr_cell = prom_n_addr_cells(dn);
num_size_cell = prom_n_size_cells(dn);
- ireg = (unsigned int *)
- get_property(dn, "ibm,lrdr-capacity", NULL);
+ ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
if (!ireg)
goto out;
@@ -445,6 +444,8 @@ void __init smp_setup_cpu_maps(void)
int __initdata do_early_xmon;
#ifdef CONFIG_XMON
+extern int xmon_no_auto_backtrace;
+
static int __init early_xmon(char *p)
{
/* ensure xmon is enabled */
@@ -453,6 +454,8 @@ static int __init early_xmon(char *p)
xmon_init(1);
if (strncmp(p, "off", 3) == 0)
xmon_init(0);
+ if (strncmp(p, "nobt", 4) == 0)
+ xmon_no_auto_backtrace = 1;
if (strncmp(p, "early", 5) != 0)
return 0;
}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index e5a44812441a..e0df2ba1ab9f 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -2,7 +2,6 @@
* Common prep/pmac/chrp boot and setup code.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sched.h>
@@ -52,7 +51,6 @@
extern void bootx_init(unsigned long r4, unsigned long phys);
-boot_infos_t *boot_infos;
struct ide_machdep_calls ppc_ide_md;
int boot_cpuid;
@@ -215,7 +213,7 @@ int __init ppc_init(void)
/* register CPU devices */
for_each_possible_cpu(i)
- register_cpu(&cpu_devices[i], i, NULL);
+ register_cpu(&cpu_devices[i], i);
/* call platform init */
if (ppc_md.init != NULL) {
@@ -241,7 +239,6 @@ void __init setup_arch(char **cmdline_p)
ppc_md.init_early();
find_legacy_serial_ports();
- finish_device_tree();
smp_setup_cpu_maps();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 78f3a5fd43f6..00d6b8addd78 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -12,7 +12,6 @@
#undef DEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sched.h>
@@ -57,7 +56,6 @@
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/lmb.h>
-#include <asm/iseries/it_lp_naca.h>
#include <asm/firmware.h>
#include <asm/xmon.h>
#include <asm/udbg.h>
@@ -80,10 +78,10 @@ u64 ppc64_pft_size;
* before we've read this from the device tree.
*/
struct ppc64_caches ppc64_caches = {
- .dline_size = 0x80,
- .log_dline_size = 7,
- .iline_size = 0x80,
- .log_iline_size = 7
+ .dline_size = 0x40,
+ .log_dline_size = 6,
+ .iline_size = 0x40,
+ .log_iline_size = 6
};
EXPORT_SYMBOL_GPL(ppc64_caches);
@@ -108,7 +106,7 @@ static int smt_enabled_cmdline;
static void check_smt_enabled(void)
{
struct device_node *dn;
- char *smt_option;
+ const char *smt_option;
/* Allow the command line to overrule the OF option */
if (smt_enabled_cmdline)
@@ -117,7 +115,7 @@ static void check_smt_enabled(void)
dn = of_find_node_by_path("/options");
if (dn) {
- smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL);
+ smt_option = get_property(dn, "ibm,smt-enabled", NULL);
if (smt_option) {
if (!strcmp(smt_option, "on"))
@@ -149,6 +147,13 @@ early_param("smt-enabled", early_smt_enabled);
#define check_smt_enabled()
#endif /* CONFIG_SMP */
+/* Put the paca pointer into r13 and SPRG3 */
+void __init setup_paca(int cpu)
+{
+ local_paca = &paca[cpu];
+ mtspr(SPRN_SPRG3, local_paca);
+}
+
/*
* Early initialization entry point. This is called by head.S
* with MMU translation disabled. We rely on the "feature" of
@@ -170,6 +175,9 @@ early_param("smt-enabled", early_smt_enabled);
void __init early_setup(unsigned long dt_ptr)
{
+ /* Assume we're on cpu 0 for now. Don't write to the paca yet! */
+ setup_paca(0);
+
/* Enable early debugging if any specified (see udbg.h) */
udbg_early_init();
@@ -183,7 +191,7 @@ void __init early_setup(unsigned long dt_ptr)
early_init_devtree(__va(dt_ptr));
/* Now we know the logical id of our boot cpu, setup the paca. */
- setup_boot_paca();
+ setup_paca(boot_cpuid);
/* Fix up paca fields required for the boot cpu */
get_paca()->cpu_start = 1;
@@ -284,7 +292,7 @@ static void __init initialize_cache_info(void)
*/
if ( num_cpus == 1 ) {
- u32 *sizep, *lsizep;
+ const u32 *sizep, *lsizep;
u32 size, lsize;
const char *dc, *ic;
@@ -299,10 +307,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->dcache_bsize;
- sizep = (u32 *)get_property(np, "d-cache-size", NULL);
+ sizep = get_property(np, "d-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = (u32 *) get_property(np, dc, NULL);
+ lsizep = get_property(np, dc, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
@@ -316,10 +324,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->icache_bsize;
- sizep = (u32 *)get_property(np, "i-cache-size", NULL);
+ sizep = get_property(np, "i-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = (u32 *)get_property(np, ic, NULL);
+ lsizep = get_property(np, ic, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
@@ -350,22 +358,17 @@ void __init setup_system(void)
*/
unflatten_device_tree();
-#ifdef CONFIG_KEXEC
- kexec_setup(); /* requires unflattened device tree. */
-#endif
-
/*
* Fill the ppc64_caches & systemcfg structures with informations
- * retrieved from the device-tree. Need to be called before
- * finish_device_tree() since the later requires some of the
- * informations filled up here to properly parse the interrupt
- * tree.
- * It also sets up the cache line sizes which allows to call
- * routines like flush_icache_range (used by the hash init
- * later on).
+ * retrieved from the device-tree.
*/
initialize_cache_info();
+ /*
+ * Initialize irq remapping subsystem
+ */
+ irq_early_init();
+
#ifdef CONFIG_PPC_RTAS
/*
* Initialize RTAS if available
@@ -393,12 +396,6 @@ void __init setup_system(void)
find_legacy_serial_ports();
/*
- * "Finish" the device-tree, that is do the actual parsing of
- * some of the properties like the interrupt map
- */
- finish_device_tree();
-
- /*
* Initialize xmon
*/
#ifdef CONFIG_XMON_DEFAULT
@@ -426,8 +423,6 @@ void __init setup_system(void)
printk("-----------------------------------------------------\n");
printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
- printk("ppc64_interrupt_controller = 0x%ld\n",
- ppc64_interrupt_controller);
printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size());
printk("ppc64_caches.dcache_line_size = 0x%x\n",
ppc64_caches.dline_size);
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d73b25e22fca..320353f0926f 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -17,7 +17,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 6e75d7ab6d4d..f72e8e823d78 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -12,7 +12,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c
index 9adef3bddad4..de59c6c31a5b 100644
--- a/arch/powerpc/kernel/smp-tbsync.c
+++ b/arch/powerpc/kernel/smp-tbsync.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
@@ -46,8 +45,9 @@ void __devinit smp_generic_take_timebase(void)
{
int cmd;
u64 tb;
+ unsigned long flags;
- local_irq_disable();
+ local_irq_save(flags);
while (!running)
barrier();
rmb();
@@ -71,7 +71,7 @@ void __devinit smp_generic_take_timebase(void)
set_tb(tb >> 32, tb & 0xfffffffful);
enter_contest(tbsync->mark, -1);
}
- local_irq_enable();
+ local_irq_restore(flags);
}
static int __devinit start_contest(int cmd, long offset, int num)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index c5d179d4f818..6a9bc9ce54e0 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -17,7 +17,6 @@
#undef DEBUG
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -145,13 +144,15 @@ void smp_message_recv(int msg, struct pt_regs *regs)
void smp_send_reschedule(int cpu)
{
- smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE);
+ if (likely(smp_ops))
+ smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE);
}
#ifdef CONFIG_DEBUGGER
void smp_send_debugger_break(int cpu)
{
- smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
+ if (likely(smp_ops))
+ smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
}
#endif
@@ -159,7 +160,7 @@ void smp_send_debugger_break(int cpu)
void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
{
crash_ipi_function_ptr = crash_ipi_callback;
- if (crash_ipi_callback) {
+ if (crash_ipi_callback && smp_ops) {
mb();
smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
}
@@ -221,6 +222,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
+ if (unlikely(smp_ops == NULL))
+ return -1;
+
data.func = func;
data.info = info;
atomic_set(&data.started, 0);
@@ -358,7 +362,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
smp_store_cpu_info(boot_cpuid);
cpu_callin_map[boot_cpuid] = 1;
- max_cpus = smp_ops->probe();
+ if (smp_ops)
+ max_cpus = smp_ops->probe();
+ else
+ max_cpus = 1;
smp_space_timers(max_cpus);
@@ -454,7 +461,7 @@ void generic_mach_cpu_die(void)
static int __devinit cpu_enable(unsigned int cpu)
{
- if (smp_ops->cpu_enable)
+ if (smp_ops && smp_ops->cpu_enable)
return smp_ops->cpu_enable(cpu);
return -ENOSYS;
@@ -468,7 +475,8 @@ int __devinit __cpu_up(unsigned int cpu)
if (!cpu_enable(cpu))
return 0;
- if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
+ if (smp_ops == NULL ||
+ (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)))
return -EINVAL;
/* Make sure callin-map entry is 0 (can be leftover a CPU
@@ -569,7 +577,8 @@ void __init smp_cpus_done(unsigned int max_cpus)
old_mask = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
- smp_ops->setup_cpu(boot_cpuid);
+ if (smp_ops)
+ smp_ops->setup_cpu(boot_cpuid);
set_cpus_allowed(current, old_mask);
diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S
index 69773cc1a85f..69e8f86aa4f8 100644
--- a/arch/powerpc/kernel/swsusp_32.S
+++ b/arch/powerpc/kernel/swsusp_32.S
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
@@ -160,8 +159,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
isync
/* Load ptr the list of pages to copy in r3 */
- lis r11,(pagedir_nosave - KERNELBASE)@h
- ori r11,r11,pagedir_nosave@l
+ lis r11,(restore_pblist - KERNELBASE)@h
+ ori r11,r11,restore_pblist@l
lwz r10,0(r11)
/* Copy the pages. This is a very basic implementation, to
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index ec274e688816..5e391fc25340 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -14,7 +14,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
@@ -741,7 +740,7 @@ asmlinkage long compat_sys_umask(u32 mask)
return sys_umask((int)mask);
}
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
struct __sysctl_args32 {
u32 name;
int nlen;
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 5bc2585c8036..406f308ddead 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
#include <linux/smp.h>
@@ -61,7 +60,7 @@ static int smt_snooze_cmdline;
static int __init smt_setup(void)
{
struct device_node *options;
- unsigned int *val;
+ const unsigned int *val;
unsigned int cpu;
if (!cpu_has_feature(CPU_FTR_SMT))
@@ -71,8 +70,7 @@ static int __init smt_setup(void)
if (!options)
return -ENODEV;
- val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay",
- NULL);
+ val = get_property(options, "ibm,smt-snooze-delay", NULL);
if (!smt_snooze_cmdline && val) {
for_each_possible_cpu(cpu)
per_cpu(smt_snooze_delay, cpu) = *val;
@@ -232,7 +230,7 @@ static void register_cpu_online(unsigned int cpu)
if (cur_cpu_spec->num_pmcs >= 8)
sysdev_create_file(s, &attr_pmc8);
- if (cpu_has_feature(CPU_FTR_SMT))
+ if (cpu_has_feature(CPU_FTR_PURR))
sysdev_create_file(s, &attr_purr);
}
@@ -274,12 +272,12 @@ static void unregister_cpu_online(unsigned int cpu)
if (cur_cpu_spec->num_pmcs >= 8)
sysdev_remove_file(s, &attr_pmc8);
- if (cpu_has_feature(CPU_FTR_SMT))
+ if (cpu_has_feature(CPU_FTR_PURR))
sysdev_remove_file(s, &attr_purr);
}
#endif /* CONFIG_HOTPLUG_CPU */
-static int sysfs_cpu_notify(struct notifier_block *self,
+static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;
@@ -297,30 +295,19 @@ static int sysfs_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block sysfs_cpu_nb = {
+static struct notifier_block __cpuinitdata sysfs_cpu_nb = {
.notifier_call = sysfs_cpu_notify,
};
/* NUMA stuff */
#ifdef CONFIG_NUMA
-static struct node node_devices[MAX_NUMNODES];
-
static void register_nodes(void)
{
int i;
- for (i = 0; i < MAX_NUMNODES; i++) {
- if (node_online(i)) {
- int p_node = parent_node(i);
- struct node *parent = NULL;
-
- if (p_node != i)
- parent = &node_devices[p_node];
-
- register_node(&node_devices[i], i, parent);
- }
- }
+ for (i = 0; i < MAX_NUMNODES; i++)
+ register_one_node(i);
}
int sysfs_add_device_to_node(struct sys_device *dev, int nid)
@@ -359,23 +346,13 @@ static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL);
static int __init topology_init(void)
{
int cpu;
- struct node *parent = NULL;
register_nodes();
-
register_cpu_notifier(&sysfs_cpu_nb);
for_each_possible_cpu(cpu) {
struct cpu *c = &per_cpu(cpu_devices, cpu);
-#ifdef CONFIG_NUMA
- /* The node to which a cpu belongs can't be known
- * until the cpu is made present.
- */
- parent = NULL;
- if (cpu_present(cpu))
- parent = &node_devices[cpu_to_node(cpu)];
-#endif
/*
* For now, we just see if the system supports making
* the RTAS calls for CPU hotplug. But, there may be a
@@ -387,7 +364,7 @@ static int __init topology_init(void)
c->no_control = 1;
if (cpu_online(cpu) || (c->no_control == 0)) {
- register_cpu(c, cpu, parent);
+ register_cpu(c, cpu);
sysdev_create_file(&c->sysdev, &attr_physical_id);
}
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S
index ee75ccf1a802..579de70e0b4d 100644
--- a/arch/powerpc/kernel/systbl.S
+++ b/arch/powerpc/kernel/systbl.S
@@ -14,7 +14,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/ppc_asm.h>
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/tau_6xx.c b/arch/powerpc/kernel/tau_6xx.c
index 26bd8ea35a4e..368a4934f7ee 100644
--- a/arch/powerpc/kernel/tau_6xx.c
+++ b/arch/powerpc/kernel/tau_6xx.c
@@ -11,7 +11,6 @@
* life in portables, and add a 'performance/watt' metric somewhere in /proc
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index d20907561f46..71f71da98e7d 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -32,7 +32,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -102,7 +101,7 @@ EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */
u64 tb_to_xs;
unsigned tb_to_us;
-#define TICKLEN_SCALE (SHIFT_SCALE - 10)
+#define TICKLEN_SCALE TICK_LENGTH_SHIFT
u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */
u64 ticklen_to_xs; /* 0.64 fraction */
@@ -126,15 +125,8 @@ static long timezone_offset;
unsigned long ppc_proc_freq;
unsigned long ppc_tb_freq;
-u64 tb_last_jiffy __cacheline_aligned_in_smp;
-unsigned long tb_last_stamp;
-
-/*
- * Note that on ppc32 this only stores the bottom 32 bits of
- * the timebase value, but that's enough to tell when a jiffy
- * has passed.
- */
-DEFINE_PER_CPU(unsigned long, last_jiffy);
+static u64 tb_last_jiffy __cacheline_aligned_in_smp;
+static DEFINE_PER_CPU(u64, last_jiffy);
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
/*
@@ -418,7 +410,7 @@ static __inline__ void timer_check_rtc(void)
/*
* This version of gettimeofday has microsecond resolution.
*/
-static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val)
+static inline void __do_gettimeofday(struct timeval *tv)
{
unsigned long sec, usec;
u64 tb_ticks, xsec;
@@ -432,7 +424,12 @@ static inline void __do_gettimeofday(struct timeval *tv, u64 tb_val)
* without a divide (and in fact, without a multiply)
*/
temp_varp = do_gtod.varp;
- tb_ticks = tb_val - temp_varp->tb_orig_stamp;
+
+ /* Sampling the time base must be done after loading
+ * do_gtod.varp in order to avoid racing with update_gtod.
+ */
+ data_barrier(temp_varp);
+ tb_ticks = get_tb() - temp_varp->tb_orig_stamp;
temp_tb_to_xs = temp_varp->tb_to_xs;
temp_stamp_xsec = temp_varp->stamp_xsec;
xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs);
@@ -454,7 +451,7 @@ void do_gettimeofday(struct timeval *tv)
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
sec = xtime.tv_sec;
- nsec = xtime.tv_nsec + tb_ticks_since(tb_last_stamp);
+ nsec = xtime.tv_nsec + tb_ticks_since(tb_last_jiffy);
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
usec = nsec / 1000;
while (usec >= 1000000) {
@@ -465,7 +462,7 @@ void do_gettimeofday(struct timeval *tv)
tv->tv_usec = usec;
return;
}
- __do_gettimeofday(tv, get_tb());
+ __do_gettimeofday(tv);
}
EXPORT_SYMBOL(do_gettimeofday);
@@ -651,6 +648,7 @@ void timer_interrupt(struct pt_regs * regs)
int next_dec;
int cpu = smp_processor_id();
unsigned long ticks;
+ u64 tb_next_jiffy;
#ifdef CONFIG_PPC32
if (atomic_read(&ppc_n_lost_interrupts) != 0)
@@ -692,11 +690,13 @@ void timer_interrupt(struct pt_regs * regs)
continue;
write_seqlock(&xtime_lock);
- tb_last_jiffy += tb_ticks_per_jiffy;
- tb_last_stamp = per_cpu(last_jiffy, cpu);
- do_timer(regs);
- timer_recalc_offset(tb_last_jiffy);
- timer_check_rtc();
+ tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
+ if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
+ tb_last_jiffy = tb_next_jiffy;
+ do_timer(1);
+ timer_recalc_offset(tb_last_jiffy);
+ timer_check_rtc();
+ }
write_sequnlock(&xtime_lock);
}
@@ -741,7 +741,7 @@ void __init smp_space_timers(unsigned int max_cpus)
int i;
unsigned long half = tb_ticks_per_jiffy / 2;
unsigned long offset = tb_ticks_per_jiffy / max_cpus;
- unsigned long previous_tb = per_cpu(last_jiffy, boot_cpuid);
+ u64 previous_tb = per_cpu(last_jiffy, boot_cpuid);
/* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */
previous_tb -= tb_ticks_per_jiffy;
@@ -822,7 +822,7 @@ int do_settimeofday(struct timespec *tv)
* and therefore the (jiffies - wall_jiffies) computation
* has been removed.
*/
- tb_delta = tb_ticks_since(tb_last_stamp);
+ tb_delta = tb_ticks_since(tb_last_jiffy);
tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */
new_nsec -= SCALE_XSEC(tb_delta, 1000000000);
@@ -860,19 +860,17 @@ EXPORT_SYMBOL(do_settimeofday);
static int __init get_freq(char *name, int cells, unsigned long *val)
{
struct device_node *cpu;
- unsigned int *fp;
+ const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = (unsigned int *)get_property(cpu, name, NULL);
+ fp = get_property(cpu, name, NULL);
if (fp) {
found = 1;
- *val = 0;
- while (cells--)
- *val = (*val << 32) | *fp++;
+ *val = of_read_ulong(fp, cells);
}
of_node_put(cpu);
@@ -942,8 +940,7 @@ void __init time_init(void)
if (__USE_RTC()) {
/* 601 processor: dec counts down by 128 every 128ns */
ppc_tb_freq = 1000000000;
- tb_last_stamp = get_rtcl();
- tb_last_jiffy = tb_last_stamp;
+ tb_last_jiffy = get_rtcl();
} else {
/* Normal PowerPC with timebase register */
ppc_md.calibrate_decr();
@@ -951,7 +948,7 @@ void __init time_init(void)
ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n",
ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
- tb_last_stamp = tb_last_jiffy = get_tb();
+ tb_last_jiffy = get_tb();
}
tb_ticks_per_jiffy = ppc_tb_freq / HZ;
@@ -1028,7 +1025,7 @@ void __init time_init(void)
do_gtod.varp = &do_gtod.vars[0];
do_gtod.var_idx = 0;
do_gtod.varp->tb_orig_stamp = tb_last_jiffy;
- __get_cpu_var(last_jiffy) = tb_last_stamp;
+ __get_cpu_var(last_jiffy) = tb_last_jiffy;
do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
do_gtod.varp->tb_to_xs = tb_to_xs;
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 91a6e04d9741..d9f10f2fc372 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -14,7 +14,6 @@
* This file handles the architecture-dependent parts of hardware exceptions
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -32,6 +31,7 @@
#include <linux/delay.h>
#include <linux/kprobes.h>
#include <linux/kexec.h>
+#include <linux/backlight.h>
#include <asm/kdebug.h>
#include <asm/pgtable.h>
@@ -51,6 +51,7 @@
#include <asm/firmware.h>
#include <asm/processor.h>
#endif
+#include <asm/kexec.h>
#ifdef CONFIG_PPC64 /* XXX */
#define _IO_BASE pci_io_base
@@ -96,7 +97,7 @@ static DEFINE_SPINLOCK(die_lock);
int die(const char *str, struct pt_regs *regs, long err)
{
- static int die_counter, crash_dump_start = 0;
+ static int die_counter;
if (debugger(regs))
return 1;
@@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err)
spin_lock_irq(&die_lock);
bust_spinlocks(1);
#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac)) {
- set_backlight_enable(1);
- set_backlight_level(BACKLIGHT_MAX);
+ mutex_lock(&pmac_backlight_mutex);
+ if (machine_is(powermac) && pmac_backlight) {
+ struct backlight_properties *props;
+
+ down(&pmac_backlight->sem);
+ props = pmac_backlight->props;
+ props->brightness = props->max_brightness;
+ props->power = FB_BLANK_UNBLANK;
+ props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
}
+ mutex_unlock(&pmac_backlight_mutex);
#endif
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
@@ -128,32 +137,19 @@ int die(const char *str, struct pt_regs *regs, long err)
print_modules();
show_regs(regs);
bust_spinlocks(0);
+ spin_unlock_irq(&die_lock);
- if (!crash_dump_start && kexec_should_crash(current)) {
- crash_dump_start = 1;
- spin_unlock_irq(&die_lock);
+ if (kexec_should_crash(current) ||
+ kexec_sr_activated(smp_processor_id()))
crash_kexec(regs);
- /* NOTREACHED */
- }
- spin_unlock_irq(&die_lock);
- if (crash_dump_start)
- /*
- * Only for soft-reset: Other CPUs will be responded to an IPI
- * sent by first kexec CPU.
- */
- for(;;)
- ;
+ crash_kexec_secondary(regs);
if (in_interrupt())
panic("Fatal exception in interrupt");
- if (panic_on_oops) {
-#ifdef CONFIG_PPC64
- printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
- ssleep(5);
-#endif
+ if (panic_on_oops)
panic("Fatal exception");
- }
+
do_exit(err);
return 0;
@@ -206,8 +202,25 @@ void system_reset_exception(struct pt_regs *regs)
return;
}
+#ifdef CONFIG_KEXEC
+ cpu_set(smp_processor_id(), cpus_in_sr);
+#endif
+
die("System Reset", regs, SIGABRT);
+ /*
+ * Some CPUs when released from the debugger will execute this path.
+ * These CPUs entered the debugger via a soft-reset. If the CPU was
+ * hung before entering the debugger it will return to the hung
+ * state when exiting this function. This causes a problem in
+ * kdump since the hung CPU(s) will not respond to the IPI sent
+ * from kdump. To prevent the problem we call crash_kexec_secondary()
+ * here. If a kdump had not been initiated or we exit the debugger
+ * with the "exit and recover" command (x) crash_kexec_secondary()
+ * will return after 5ms and the CPU returns to its previous state.
+ */
+ crash_kexec_secondary(regs);
+
/* Must die if the interrupt is not recoverable */
if (!(regs->msr & MSR_RI))
panic("Unrecoverable System Reset");
@@ -572,19 +585,22 @@ static void parse_fpe(struct pt_regs *regs)
#define INST_MFSPR_PVR_MASK 0xfc1fffff
#define INST_DCBA 0x7c0005ec
-#define INST_DCBA_MASK 0x7c0007fe
+#define INST_DCBA_MASK 0xfc0007fe
#define INST_MCRXR 0x7c000400
-#define INST_MCRXR_MASK 0x7c0007fe
+#define INST_MCRXR_MASK 0xfc0007fe
#define INST_STRING 0x7c00042a
-#define INST_STRING_MASK 0x7c0007fe
-#define INST_STRING_GEN_MASK 0x7c00067e
+#define INST_STRING_MASK 0xfc0007fe
+#define INST_STRING_GEN_MASK 0xfc00067e
#define INST_LSWI 0x7c0004aa
#define INST_LSWX 0x7c00042a
#define INST_STSWI 0x7c0005aa
#define INST_STSWX 0x7c00052a
+#define INST_POPCNTB 0x7c0000f4
+#define INST_POPCNTB_MASK 0xfc0007fe
+
static int emulate_string_inst(struct pt_regs *regs, u32 instword)
{
u8 rT = (instword >> 21) & 0x1f;
@@ -653,6 +669,23 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
return 0;
}
+static int emulate_popcntb_inst(struct pt_regs *regs, u32 instword)
+{
+ u32 ra,rs;
+ unsigned long tmp;
+
+ ra = (instword >> 16) & 0x1f;
+ rs = (instword >> 21) & 0x1f;
+
+ tmp = regs->gpr[rs];
+ tmp = tmp - ((tmp >> 1) & 0x5555555555555555ULL);
+ tmp = (tmp & 0x3333333333333333ULL) + ((tmp >> 2) & 0x3333333333333333ULL);
+ tmp = (tmp + (tmp >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+ regs->gpr[ra] = tmp;
+
+ return 0;
+}
+
static int emulate_instruction(struct pt_regs *regs)
{
u32 instword;
@@ -690,6 +723,11 @@ static int emulate_instruction(struct pt_regs *regs)
if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
return emulate_string_inst(regs, instword);
+ /* Emulate the popcntb (Population Count Bytes) instruction. */
+ if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
+ return emulate_popcntb_inst(regs, instword);
+ }
+
return -EINVAL;
}
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 67d9fd9ae2b5..5730906b23d5 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -10,7 +10,6 @@
*/
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/console.h>
@@ -34,9 +33,12 @@ void __init udbg_early_init(void)
#elif defined(CONFIG_PPC_EARLY_DEBUG_G5)
/* For use on Apple G5 machines */
udbg_init_pmac_realmode();
-#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS)
+#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL)
/* RTAS panel debug */
- udbg_init_rtas();
+ udbg_init_rtas_panel();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE)
+ /* RTAS console debug */
+ udbg_init_rtas_console();
#elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
/* Maple real mode debug */
udbg_init_maple_realmode();
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 5d29dcca523c..2d17f2b8eda7 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -8,7 +8,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/udbg.h>
#include <asm/io.h>
@@ -82,10 +81,14 @@ static int udbg_550_getc(void)
void udbg_init_uart(void __iomem *comport, unsigned int speed,
unsigned int clock)
{
- unsigned int dll, base_bauds = clock / 16;
+ unsigned int dll, base_bauds;
+ if (clock == 0)
+ clock = 1843200;
if (speed == 0)
speed = 9600;
+
+ base_bauds = clock / 16;
dll = base_bauds / speed;
if (comport) {
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index bc3e15be3087..1a7e19cdab39 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -8,7 +8,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
diff --git a/arch/powerpc/kernel/vdso32/Makefile b/arch/powerpc/kernel/vdso32/Makefile
index 8a3bed5f143a..3726358faae8 100644
--- a/arch/powerpc/kernel/vdso32/Makefile
+++ b/arch/powerpc/kernel/vdso32/Makefile
@@ -14,7 +14,8 @@ obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1
+EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
EXTRA_AFLAGS := -D__VDSO32__ -s
obj-y += vdso32_wrapper.o
diff --git a/arch/powerpc/kernel/vdso32/cacheflush.S b/arch/powerpc/kernel/vdso32/cacheflush.S
index 09629aea3e47..9cb319992c38 100644
--- a/arch/powerpc/kernel/vdso32/cacheflush.S
+++ b/arch/powerpc/kernel/vdso32/cacheflush.S
@@ -9,7 +9,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/vdso.h>
diff --git a/arch/powerpc/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S
index 4709f1d9542c..dc21e891d2e7 100644
--- a/arch/powerpc/kernel/vdso32/datapage.S
+++ b/arch/powerpc/kernel/vdso32/datapage.S
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index 7eebff03a041..05909f754307 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -10,7 +10,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/vdso.h>
diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S
index 0c6a37b29dde..68d49dd71dcc 100644
--- a/arch/powerpc/kernel/vdso32/sigtramp.S
+++ b/arch/powerpc/kernel/vdso32/sigtramp.S
@@ -10,7 +10,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/unistd.h>
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
index f4bad720cb0a..6187af2d54c3 100644
--- a/arch/powerpc/kernel/vdso32/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -14,6 +14,7 @@ SECTIONS
{
. = VDSO32_LBASE + SIZEOF_HEADERS;
.hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
diff --git a/arch/powerpc/kernel/vdso64/Makefile b/arch/powerpc/kernel/vdso64/Makefile
index ab39988452cc..43af9b2a6f3b 100644
--- a/arch/powerpc/kernel/vdso64/Makefile
+++ b/arch/powerpc/kernel/vdso64/Makefile
@@ -8,7 +8,8 @@ targets := $(obj-vdso64) vdso64.so
obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1
+EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
EXTRA_AFLAGS := -D__VDSO64__ -s
obj-y += vdso64_wrapper.o
diff --git a/arch/powerpc/kernel/vdso64/cacheflush.S b/arch/powerpc/kernel/vdso64/cacheflush.S
index cb4ae0a5edd0..66a36d3cc6ad 100644
--- a/arch/powerpc/kernel/vdso64/cacheflush.S
+++ b/arch/powerpc/kernel/vdso64/cacheflush.S
@@ -9,7 +9,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/vdso.h>
diff --git a/arch/powerpc/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S
index 3b2dd7d0c1eb..79796de11737 100644
--- a/arch/powerpc/kernel/vdso64/datapage.S
+++ b/arch/powerpc/kernel/vdso64/datapage.S
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
index 4ee871f1cadb..56e76ff5498f 100644
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -11,7 +11,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/vdso.h>
diff --git a/arch/powerpc/kernel/vdso64/sigtramp.S b/arch/powerpc/kernel/vdso64/sigtramp.S
index 7479edb101b8..17a83fa6dc52 100644
--- a/arch/powerpc/kernel/vdso64/sigtramp.S
+++ b/arch/powerpc/kernel/vdso64/sigtramp.S
@@ -10,7 +10,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/unistd.h>
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S
index 4bdf224464ab..4a2b6dc0960c 100644
--- a/arch/powerpc/kernel/vdso64/vdso64.lds.S
+++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S
@@ -12,6 +12,7 @@ SECTIONS
{
. = VDSO64_LBASE + SIZEOF_HEADERS;
.hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 9416b4ab92ec..49ac3d6e1399 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <asm/ppc_asm.h>
#include <asm/reg.h>
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index cdf5867838a6..cb87e71eec66 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -77,7 +77,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
} else
#endif
{
- unsigned char *dma_window;
+ const unsigned char *dma_window;
struct iommu_table *tbl;
unsigned long offset, size;
@@ -217,8 +217,7 @@ static void __devinit vio_dev_release(struct device *dev)
struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
{
struct vio_dev *viodev;
- unsigned int *unit_address;
- unsigned int *irq_p;
+ const unsigned int *unit_address;
/* we need the 'device_type' property, in order to match with drivers */
if (of_node->type == NULL) {
@@ -228,7 +227,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
return NULL;
}
- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
+ unit_address = get_property(of_node, "reg", NULL);
if (unit_address == NULL) {
printk(KERN_WARNING "%s: node %s missing 'reg'\n",
__FUNCTION__,
@@ -243,23 +242,14 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
viodev->dev.platform_data = of_node_get(of_node);
- viodev->irq = NO_IRQ;
- irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
- if (irq_p) {
- int virq = virt_irq_create_mapping(*irq_p);
- if (virq == NO_IRQ) {
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", of_node->full_name);
- } else
- viodev->irq = irq_offset_up(virq);
- }
+ viodev->irq = irq_of_parse_and_map(of_node, 0);
snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
viodev->name = of_node->name;
viodev->type = of_node->type;
viodev->unit_address = *unit_address;
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- unit_address = (unsigned int *)get_property(of_node,
+ unit_address = get_property(of_node,
"linux,unit_address", NULL);
if (unit_address != NULL)
viodev->unit_address = *unit_address;
@@ -433,7 +423,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
{
const struct vio_dev *vio_dev = to_vio_dev(dev);
struct device_node *dn = dev->platform_data;
- char *cp;
+ const char *cp;
int length;
if (!num_envp)
@@ -441,7 +431,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
if (!dn)
return -ENODEV;
- cp = (char *)get_property(dn, "compatible", &length);
+ cp = get_property(dn, "compatible", &length);
if (!cp)
return -ENODEV;
@@ -503,11 +493,11 @@ static struct vio_dev *vio_find_name(const char *kobj_name)
*/
struct vio_dev *vio_find_node(struct device_node *vnode)
{
- uint32_t *unit_address;
+ const uint32_t *unit_address;
char kobj_name[BUS_ID_SIZE];
/* construct the kobject name from the device node */
- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
+ unit_address = get_property(vnode, "reg", NULL);
if (!unit_address)
return NULL;
snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 8b25953dc4f0..02665a02130d 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#ifdef CONFIG_PPC64
#include <asm/page.h>
#define PROVIDE32(x) PROVIDE(__unused__##x)
OpenPOWER on IntegriCloud