diff options
Diffstat (limited to 'arch/powerpc/kernel')
42 files changed, 728 insertions, 248 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index aa693d0f151a..3e779f07f21b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -36,8 +36,9 @@ obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o +obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o obj32-$(CONFIG_MODULES) += module_32.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -67,6 +68,7 @@ obj-$(CONFIG_MODULES) += $(module-y) pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci32-$(CONFIG_PPC32) := pci_32.o obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) +obj-$(CONFIG_PCI_MSI) += msi.o kexec-$(CONFIG_PPC64) := machine_kexec_64.o kexec-$(CONFIG_PPC32) := machine_kexec_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0c5150c69175..2cb1d9487796 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -21,12 +21,12 @@ #include <linux/types.h> #include <linux/mman.h> #include <linux/mm.h> +#include <linux/suspend.h> #ifdef CONFIG_PPC64 #include <linux/time.h> #include <linux/hardirq.h> #else #include <linux/ptrace.h> -#include <linux/suspend.h> #endif #include <asm/io.h> @@ -58,7 +58,7 @@ int main(void) #ifdef CONFIG_PPC64 DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); #else - DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); #endif /* CONFIG_PPC64 */ @@ -122,12 +122,18 @@ int main(void) DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); - DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp)); DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp)); -#ifdef CONFIG_HUGETLB_PAGE - DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); - DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); -#endif /* CONFIG_HUGETLB_PAGE */ +#ifdef CONFIG_PPC_MM_SLICES + DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, + context.low_slices_psize)); + DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct, + context.high_slices_psize)); + DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def)); + DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp)); +#else + DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp)); + +#endif /* CONFIG_PPC_MM_SLICES */ DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); @@ -257,11 +263,11 @@ int main(void) 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)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); DEFINE(pbe_next, offsetof(struct pbe, next)); +#ifndef CONFIG_PPC64 DEFINE(TASK_SIZE, TASK_SIZE); DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); #endif /* ! CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c index 7fe5e6300e9a..a4dab7cab348 100644 --- a/arch/powerpc/kernel/audit.c +++ b/arch/powerpc/kernel/audit.c @@ -23,6 +23,20 @@ static unsigned chattr_class[] = { ~0U }; +static unsigned signal_class[] = { +#include <asm-generic/audit_signal.h> +~0U +}; + +int audit_classify_arch(int arch) +{ +#ifdef CONFIG_PPC64 + if (arch == AUDIT_ARCH_PPC) + return 1; +#endif + return 0; +} + int audit_classify_syscall(int abi, unsigned syscall) { #ifdef CONFIG_PPC64 @@ -51,15 +65,18 @@ static int __init audit_classes_init(void) extern __u32 ppc32_write_class[]; extern __u32 ppc32_read_class[]; extern __u32 ppc32_chattr_class[]; + extern __u32 ppc32_signal_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); + audit_register_class(AUDIT_CLASS_SIGNAL_32, ppc32_signal_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); + audit_register_class(AUDIT_CLASS_SIGNAL, signal_class); return 0; } diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c index 640d4bb29321..108ff14e2122 100644 --- a/arch/powerpc/kernel/compat_audit.c +++ b/arch/powerpc/kernel/compat_audit.c @@ -21,6 +21,11 @@ unsigned ppc32_read_class[] = { ~0U }; +unsigned ppc32_signal_class[] = { +#include <asm-generic/audit_signal.h> +~0U +}; + int ppc32_classify_syscall(unsigned syscall) { switch(syscall) { diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 9cb24d20f0f9..b2b5d664d328 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -235,6 +235,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970MP", @@ -251,6 +252,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970MP, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970MP", @@ -317,6 +319,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, @@ -335,6 +338,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, @@ -836,7 +840,7 @@ static struct cpu_spec cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80040000, .cpu_name = "7448", - .cpu_features = CPU_FTRS_7447A, + .cpu_features = CPU_FTRS_7448, .cpu_user_features = COMMON_USER | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_PPC_LE, .icache_bsize = 32, diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index c29d1652a421..4074c0b31453 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -596,7 +596,11 @@ fast_exception_return: mr r12,r4 /* restart at exc_exit_restart */ b 2b - .comm fee_restarts,4 + .section .bss + .align 2 +fee_restarts: + .space 4 + .previous /* aargh, a nonrecoverable interrupt, panic */ /* aargh, we don't know which trap this is */ @@ -851,7 +855,11 @@ load_dbcr0: mtspr SPRN_DBSR,r11 /* clear all pending debug events */ blr - .comm global_dbcr0,8 + .section .bss + .align 4 +global_dbcr0: + .space 8 + .previous #endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ do_work: /* r10 contains MSR_KERNEL here */ @@ -926,7 +934,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) /* shouldn't return */ b 4b - .comm ee_restarts,4 + .section .bss + .align 2 +ee_restarts: + .space 4 + .previous /* * PROM code for specific machines follows. Put it diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index a15d4b8cce48..88695963f587 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -120,8 +120,8 @@ skpinv: addi r4,r4,1 /* Increment */ * Configure and load pinned entry into TLB slot 63. */ - lis r3,KERNELBASE@h /* Load the kernel virtual address */ - ori r3,r3,KERNELBASE@l + lis r3,PAGE_OFFSET@h + ori r3,r3,PAGE_OFFSET@l /* Kernel is at the base of RAM */ li r4, 0 /* Load the kernel physical address */ @@ -172,36 +172,28 @@ skpinv: addi r4,r4,1 /* Increment */ isync 4: -#ifdef CONFIG_SERIAL_TEXT_DEBUG - /* - * Add temporary UART mapping for early debug. - * We can map UART registers wherever we want as long as they don't - * interfere with other system mappings (e.g. with pinned entries). - * For an example of how we handle this - see ocotea.h. --ebs - */ +#ifdef CONFIG_PPC_EARLY_DEBUG_44x + /* Add UART mapping for early debug. */ + /* pageid fields */ - lis r3,UART0_IO_BASE@h - ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K + lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h + ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K /* xlat fields */ - lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */ -#ifndef CONFIG_440EP - ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */ -#endif + lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h + ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH /* attrib fields */ - li r5,0 - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) + li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G) + li r0,62 /* TLB slot 0 */ - li r0,0 /* TLB slot 0 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ - tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ - tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ + tlbwe r3,r0,PPC44x_TLB_PAGEID + tlbwe r4,r0,PPC44x_TLB_XLAT + tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Force context change */ isync -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ /* Establish the interrupt vector offsets */ SET_IVOR(0, CriticalInput); @@ -709,16 +701,6 @@ _GLOBAL(giveup_fpu) blr #endif -/* - * extern void abort(void) - * - * At present, this routine just applies a system reset. - */ -_GLOBAL(abort) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 - _GLOBAL(set_context) #ifdef CONFIG_BDI_SWITCH diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 6e7f50967bab..a9e9cbd32975 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -33,8 +33,11 @@ #include <asm/smp.h> #ifdef CONFIG_HOTPLUG_CPU +/* this is used for software suspend, and that shuts down + * CPUs even while the system is still booting... */ #define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ - system_state == SYSTEM_RUNNING) + (system_state == SYSTEM_RUNNING \ + || system_state == SYSTEM_BOOTING)) #else #define cpu_should_die() 0 #endif diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index ba3195478600..5328709eeedc 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) isync b 1b +_GLOBAL(power4_cpu_offline_powersave) + /* Go to NAP now */ + mfmsr r7 + rldicl r0,r7,48,1 + rotldi r0,r0,16 + mtmsrd r0,1 /* hard-disable interrupts */ + li r0,1 + li r6,0 + stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */ + stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */ +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + ori r7,r7,MSR_EE + oris r7,r7,MSR_POW@h + sync + isync + mtmsrd r7 + isync + blr diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 6c83fe229e60..068377a2a8dc 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -67,6 +67,7 @@ #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/firmware.h> +#include <asm/lv1call.h> #endif int __irq_offset_value; @@ -162,7 +163,17 @@ void local_irq_restore(unsigned long en) local_paca->hard_enabled = en; if ((int)mfspr(SPRN_DEC) < 0) mtspr(SPRN_DEC, 1); - hard_irq_enable(); + + /* + * Force the delivery of pending soft-disabled interrupts on PS3. + * Any HV call will have this side effect. + */ + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + u64 tmp; + lv1_get_version_info(&tmp); + } + + __hard_irq_enable(); } #endif /* CONFIG_PPC64 */ @@ -947,33 +958,6 @@ arch_initcall(irq_late_init); #endif /* CONFIG_PPC_MERGE */ -#ifdef CONFIG_PCI_MSI -int pci_enable_msi(struct pci_dev * pdev) -{ - if (ppc_md.enable_msi) - return ppc_md.enable_msi(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;} -void pci_disable_msix(struct pci_dev *dev) {} -void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} -void pci_no_msi(void) {} -EXPORT_SYMBOL(pci_enable_msix); -EXPORT_SYMBOL(pci_disable_msix); - -#endif - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index ef647e7a9dc3..0c96611f02f4 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -30,8 +30,8 @@ #include <linux/ptrace.h> #include <linux/preempt.h> #include <linux/module.h> +#include <linux/kdebug.h> #include <asm/cacheflush.h> -#include <asm/kdebug.h> #include <asm/sstep.h> #include <asm/uaccess.h> @@ -126,22 +126,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, } /* Called with kretprobe_lock held */ -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) { - struct kretprobe_instance *ri; - - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *)regs->link; - - /* Replace the return addr with trampoline addr */ - regs->link = (unsigned long)kretprobe_trampoline; - add_rp_inst(ri); - } else { - rp->nmissed++; - } + ri->ret_addr = (kprobe_opcode_t *)regs->link; + + /* Replace the return addr with trampoline addr */ + regs->link = (unsigned long)kretprobe_trampoline; } static int __kprobes kprobe_handler(struct pt_regs *regs) @@ -336,7 +327,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) break; } - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); + kretprobe_assert(ri, orig_ret_address, trampoline_address); regs->nip = orig_ret_address; reset_current_kprobe(); @@ -410,7 +401,7 @@ out: return 1; } -static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -495,14 +486,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, if (post_kprobe_handler(args->regs)) ret = NOTIFY_STOP; break; - case DIE_PAGE_FAULT: - /* kprobe_running() needs smp_processor_id() */ - preempt_disable(); - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - ret = NOTIFY_STOP; - preempt_enable(); - break; default: break; } @@ -559,3 +542,11 @@ int __init arch_init_kprobes(void) { return register_kprobe(&trampoline_p); } + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline) + return 1; + + return 0; +} diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index ae4836ea7442..cea8045ba40b 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -244,9 +244,9 @@ static int __init add_legacy_pci_port(struct device_node *np, * doesn't work for these settings, you'll have to add your own special * cases here */ - if (device_is_compatible(pci_dev, "pci13a8,152") || - device_is_compatible(pci_dev, "pci13a8,154") || - device_is_compatible(pci_dev, "pci13a8,158")) { + if (of_device_is_compatible(pci_dev, "pci13a8,152") || + of_device_is_compatible(pci_dev, "pci13a8,154") || + of_device_is_compatible(pci_dev, "pci13a8,158")) { addr += 0x200 * lindex; base += 0x200 * lindex; } else { @@ -365,11 +365,11 @@ void __init find_legacy_serial_ports(void) /* Check for known pciclass, and also check wether we have * a device with child nodes for ports or not */ - if (device_is_compatible(np, "pciclass,0700") || - device_is_compatible(np, "pciclass,070002")) + if (of_device_is_compatible(np, "pciclass,0700") || + of_device_is_compatible(np, "pciclass,070002")) pci = np; - else if (device_is_compatible(parent, "pciclass,0700") || - device_is_compatible(parent, "pciclass,070002")) + else if (of_device_is_compatible(parent, "pciclass,0700") || + of_device_is_compatible(parent, "pciclass,070002")) pci = parent; else { of_node_put(parent); diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c index 584d1e3c013d..af11285ffbd1 100644 --- a/arch/powerpc/kernel/lparmap.c +++ b/arch/powerpc/kernel/lparmap.c @@ -10,7 +10,8 @@ #include <asm/pgtable.h> #include <asm/iseries/lpar_map.h> -const struct LparMap __attribute__((__section__(".text"))) xLparMap = { +/* The # is to stop gcc trying to make .text nonexecutable */ +const struct LparMap __attribute__((__section__(".text #"))) xLparMap = { .xNumberEsids = HvEsidsToMap, .xNumberRanges = HvRangesToMap, .xSegmentTableOffs = STAB0_PAGE, diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c new file mode 100644 index 000000000000..c62d1012c013 --- /dev/null +++ b/arch/powerpc/kernel/msi.c @@ -0,0 +1,38 @@ +/* + * Copyright 2006-2007, Michael Ellerman, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/msi.h> + +#include <asm/machdep.h> + +int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) +{ + if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) { + pr_debug("msi: Platform doesn't provide MSI callbacks.\n"); + return -ENOSYS; + } + + if (ppc_md.msi_check_device) { + pr_debug("msi: Using platform check routine.\n"); + return ppc_md.msi_check_device(dev, nvec, type); + } + + return 0; +} + +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + return ppc_md.setup_msi_irqs(dev, nvec, type); +} + +void arch_teardown_msi_irqs(struct pci_dev *dev) +{ + return ppc_md.teardown_msi_irqs(dev); +} diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 0c8ea7659d92..a464d67248df 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c @@ -27,7 +27,7 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches, match &= node->type && !strcmp(matches->type, node->type); if (matches->compatible[0]) - match &= device_is_compatible(node, + match &= of_device_is_compatible(node, matches->compatible); if (match) return matches; @@ -120,8 +120,8 @@ void of_device_unregister(struct of_device *ofdev) } -static ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) +ssize_t of_device_get_modalias(struct of_device *ofdev, + char *str, ssize_t len) { const char *compat; int cplen, i; @@ -239,3 +239,4 @@ EXPORT_SYMBOL(of_dev_get); EXPORT_SYMBOL(of_dev_put); EXPORT_SYMBOL(of_release_dev); EXPORT_SYMBOL(of_device_uevent); +EXPORT_SYMBOL(of_device_get_modalias); diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index 908ed7926db4..d501c23e5159 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -29,7 +29,6 @@ #include <asm/ppc-pci.h> #include <asm/atomic.h> - /* * The list of OF IDs below is used for matching bus types in the * system whose devices are to be exposed as of_platform_devices. @@ -428,11 +427,13 @@ static int __devinit of_pci_phb_probe(struct of_device *dev, /* Process "ranges" property */ pci_process_bridge_OF_ranges(phb, dev->node, 0); - /* Setup IO space. - * This will not work properly for ISA IOs, something needs to be done - * about it if we ever generalize that way of probing PCI brigdes + /* Setup IO space. We use the non-dynamic version of that code here, + * which doesn't quite support unplugging. Next kernel release will + * have a better fix for this. + * Note also that we don't do ISA, this will also be fixed with a + * more massive rework. */ - pci_setup_phb_io_dynamic(phb, 0); + pci_setup_phb_io(phb, 0); /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index f022862de344..e66064b5093a 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -1658,7 +1658,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, int i; if (page_is_ram(pfn)) - return prot; + return __pgprot(prot); prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 7138092826aa..249cca27a9b8 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -41,6 +41,7 @@ unsigned long pci_probe_only = 1; int pci_assign_all_buses = 0; +static int pci_initial_scan_done; static void fixup_resource(struct resource *res, struct pci_dev *dev); static void do_bus_setup(struct pci_bus *bus); @@ -604,6 +605,8 @@ static int __init pcibios_init(void) /* map in PCI I/O space */ phbs_remap_io(); + pci_initial_scan_done = 1; + printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); return 0; @@ -1006,8 +1009,9 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, switch ((pci_space >> 24) & 0x3) { case 1: /* I/O space */ - hose->io_base_phys = cpu_phys_addr; - hose->pci_io_size = size; + hose->io_base_phys = cpu_phys_addr - pci_addr; + /* handle from 0 to top of I/O window */ + hose->pci_io_size = pci_addr + size; res = &hose->io_resource; res->flags = IORESOURCE_IO; @@ -1041,13 +1045,16 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, } } -void __init pci_setup_phb_io(struct pci_controller *hose, int primary) +void __devinit pci_setup_phb_io(struct pci_controller *hose, int primary) { unsigned long size = hose->pci_io_size; unsigned long io_virt_offset; struct resource *res; struct device_node *isa_dn; + if (size == 0) + return; + hose->io_base_virt = reserve_phb_iospace(size); DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", hose->global_number, hose->io_base_phys, @@ -1068,6 +1075,15 @@ void __init pci_setup_phb_io(struct pci_controller *hose, int primary) res = &hose->io_resource; res->start += io_virt_offset; res->end += io_virt_offset; + + /* If this is called after the initial PCI scan, then we need to + * proceed to IO mappings now + */ + if (pci_initial_scan_done) + __ioremap_explicit(hose->io_base_phys, + (unsigned long)hose->io_base_virt, + hose->pci_io_size, + _PAGE_NO_CACHE | _PAGE_GUARDED); } void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose, @@ -1077,6 +1093,9 @@ void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose, unsigned long io_virt_offset; struct resource *res; + if (size == 0) + return; + hose->io_base_virt = __ioremap(hose->io_base_phys, size, _PAGE_NO_CACHE | _PAGE_GUARDED); DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", @@ -1097,35 +1116,27 @@ static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, unsigned long *start_virt, unsigned long *size) { struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_bus_region region; struct resource *res; - if (bus->self) { + if (bus->self) res = bus->resource[0]; - pcibios_resource_to_bus(bus->self, ®ion, res); - *start_phys = hose->io_base_phys + region.start; - *start_virt = (unsigned long) hose->io_base_virt + - region.start; - if (region.end > region.start) - *size = region.end - region.start + 1; - else { - printk("%s(): unexpected region 0x%lx->0x%lx\n", - __FUNCTION__, region.start, region.end); - return 1; - } - - } else { + else /* Root Bus */ res = &hose->io_resource; - *start_phys = hose->io_base_phys; - *start_virt = (unsigned long) hose->io_base_virt; - if (res->end > res->start) - *size = res->end - res->start + 1; - else { - printk("%s(): unexpected region 0x%lx->0x%lx\n", - __FUNCTION__, res->start, res->end); - return 1; - } + + if (res->end == 0 && res->start == 0) + return 1; + + *start_virt = pci_io_base + res->start; + *start_phys = *start_virt + hose->io_base_phys + - (unsigned long) hose->io_base_virt; + + if (res->end > res->start) + *size = res->end - res->start + 1; + else { + printk("%s(): unexpected region 0x%lx->0x%lx\n", + __FUNCTION__, res->start, res->end); + return 1; } return 0; diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index 24d7b7c99bb9..ea04e0ab3f2f 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -20,8 +20,8 @@ #include <asm/cputable.h> #include <asm/pmc.h> -#ifndef MMCR0_PMA0 -#define MMCR0_PMA0 0 +#ifndef MMCR0_PMAO +#define MMCR0_PMAO 0 #endif static void dummy_perf(struct pt_regs *regs) @@ -30,7 +30,7 @@ static void dummy_perf(struct pt_regs *regs) mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE); #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) if (cur_cpu_spec->pmc_type == PPC_PMC_IBM) - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMA0)); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMAO)); #else mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE); #endif diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index ff252aaead12..c96fa9bd35a4 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -66,7 +66,6 @@ EXPORT_SYMBOL(clear_pages); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(transfer_to_handler); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e509aae2feb3..6e2f03566b0d 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -19,7 +19,6 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index caef555f2dc0..066a6a7a25b8 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -716,11 +716,40 @@ static int __init early_init_dt_scan_cpus(unsigned long node, return 0; } +#ifdef CONFIG_BLK_DEV_INITRD +static void __init early_init_dt_check_for_initrd(unsigned long node) +{ + unsigned long l; + u32 *prop; + + DBG("Looking for initrd properties... "); + + prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); + if (prop) { + initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); + + prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); + if (prop) { + initrd_end = (unsigned long) + __va(of_read_ulong(prop, l/4)); + initrd_below_start_ok = 1; + } else { + initrd_start = 0; + } + } + + DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end); +} +#else +static inline void early_init_dt_check_for_initrd(unsigned long node) +{ +} +#endif /* CONFIG_BLK_DEV_INITRD */ + static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { unsigned long *lprop; - u32 *prop; unsigned long l; char *p; @@ -762,21 +791,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node, crashk_res.end = crashk_res.start + *lprop - 1; #endif -#ifdef CONFIG_BLK_DEV_INITRD - DBG("Looking for initrd properties... "); - prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); - if (prop) { - initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); - prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); - if (prop) { - initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4)); - initrd_below_start_ok = 1; - } else { - initrd_start = 0; - } - } - DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end); -#endif /* CONFIG_BLK_DEV_INITRD */ + early_init_dt_check_for_initrd(node); /* Retreive command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); @@ -1457,6 +1472,11 @@ static int of_finish_dynamic_node(struct device_node *node) node->name = of_get_property(node, "name", NULL); node->type = of_get_property(node, "device_type", NULL); + if (!node->name) + node->name = "<NULL>"; + if (!node->type) + node->type = "<NULL>"; + if (!parent) { err = -ENODEV; goto out; diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e27d9d1b6e67..d6047c441034 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -635,6 +635,12 @@ static void __init early_cmdline_parse(void) /* ibm,dynamic-reconfiguration-memory property supported */ #define OV5_DRCONF_MEMORY 0x20 #define OV5_LARGE_PAGES 0x10 /* large pages supported */ +/* PCIe/MSI support. Without MSI full PCIe is not supported */ +#ifdef CONFIG_PCI_MSI +#define OV5_MSI 0x01 /* PCIe/MSI support */ +#else +#define OV5_MSI 0x00 +#endif /* CONFIG_PCI_MSI */ /* * The architecture vector has an array of PVR mask/value pairs, @@ -679,7 +685,7 @@ static unsigned char ibm_architecture_vec[] = { /* option vector 5: PAPR/OF options */ 3 - 2, /* length */ 0, /* don't ignore, don't halt */ - OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY, + OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI, }; /* Old method - ELF header with PT_NOTE sections */ @@ -967,7 +973,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp) * If problems seem to show up, it would be a good start to track * them down. */ -static void reserve_mem(u64 base, u64 size) +static void __init reserve_mem(u64 base, u64 size) { u64 top = base + size; unsigned long cnt = RELOC(mem_reserve_cnt); @@ -2153,7 +2159,7 @@ static void __init fixup_device_tree_efika(void) 3,12,0, 3,13,0, 3,14,0, 3,15,0 }; struct subst_entry efika_subst_table[] = { { "/", "device_type", prop_cstr("efika") }, - { "/builtin", "compatible", prop_cstr("soc") }, + { "/builtin", "device_type", prop_cstr("soc") }, { "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc5200-ata"), }, { "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") }, { "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) }, diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index aa40a5307294..3786dcc8a7b6 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -24,7 +24,7 @@ /* Max address size we deal with */ #define OF_MAX_ADDR_CELLS 4 #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) + (ns) >= 0) static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, @@ -1042,3 +1042,28 @@ const void *of_get_mac_address(struct device_node *np) } EXPORT_SYMBOL(of_get_mac_address); +int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) +{ + int irq = irq_of_parse_and_map(dev, index); + + /* Only dereference the resource if both the + * resource and the irq are valid. */ + if (r && irq != NO_IRQ) { + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + } + + return irq; +} +EXPORT_SYMBOL_GPL(of_irq_to_resource); + +void __iomem *of_iomap(struct device_node *np, int index) +{ + struct resource res; + + if (of_address_to_resource(np, index, &res)) + return NULL; + + return ioremap(res.start, 1 + res.end - res.start); +} +EXPORT_SYMBOL(of_iomap); diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index cc44c7b975aa..f4f391cdd8f5 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -19,7 +19,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 190b7ed1dbfb..f2e3bc714d76 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c @@ -379,7 +379,7 @@ static ssize_t ppc_rtas_progress_write(struct file *file, /* ****************************************************************** */ static int ppc_rtas_progress_show(struct seq_file *m, void *v) { - if (progress_led) + if (progress_led[0]) seq_printf(m, "%s\n", progress_led); return 0; } diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 370803722e47..ed07a198f8d6 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -530,3 +530,44 @@ void __init setup_panic(void) { atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block); } + +#ifdef CONFIG_CHECK_CACHE_COHERENCY +/* + * For platforms that have configurable cache-coherency. This function + * checks that the cache coherency setting of the kernel matches the setting + * left by the firmware, as indicated in the device tree. Since a mismatch + * will eventually result in DMA failures, we print * and error and call + * BUG() in that case. + */ + +#ifdef CONFIG_NOT_COHERENT_CACHE +#define KERNEL_COHERENCY 0 +#else +#define KERNEL_COHERENCY 1 +#endif + +static int __init check_cache_coherency(void) +{ + struct device_node *np; + const void *prop; + int devtree_coherency; + + np = of_find_node_by_path("/"); + prop = of_get_property(np, "coherency-off", NULL); + of_node_put(np); + + devtree_coherency = prop ? 0 : 1; + + if (devtree_coherency != KERNEL_COHERENCY) { + printk(KERN_ERR + "kernel coherency:%s != device tree_coherency:%s\n", + KERNEL_COHERENCY ? "on" : "off", + devtree_coherency ? "on" : "off"); + BUG(); + } + + return 0; +} + +late_initcall(check_cache_coherency); +#endif /* CONFIG_CHECK_CACHE_COHERENCY */ diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 6b405a3f43f9..dd1dca5bfa81 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -20,7 +20,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index f72e8e823d78..1ce0ae3f6ffc 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -15,7 +15,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index d8e503b2e1af..d577b71db375 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -176,10 +176,10 @@ static struct call_data_struct { #define SMP_CALL_TIMEOUT 8 /* - * This function sends a 'generic call function' IPI to all other CPUs - * in the system. + * These functions send a 'generic call function' IPI to other online + * CPUS in the system. * - * [SUMMARY] Run a function on all other CPUs. + * [SUMMARY] Run a function on other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <nonatomic> currently unused. @@ -190,18 +190,19 @@ static struct call_data_struct { * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, - int wait) -{ +int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, + int wait, cpumask_t map) +{ struct call_data_struct data; - int ret = -1, cpus; + int ret = -1, num_cpus; + int cpu; u64 timeout; /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); if (unlikely(smp_ops == NULL)) - return -1; + return ret; data.func = func; data.info = info; @@ -213,46 +214,56 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, spin_lock(&call_lock); /* Must grab online cpu count with preempt disabled, otherwise * it can change. */ - cpus = num_online_cpus() - 1; - if (!cpus) { - ret = 0; - goto out; - } + num_cpus = num_online_cpus() - 1; + if (!num_cpus) + goto done; + + /* remove 'self' from the map */ + if (cpu_isset(smp_processor_id(), map)) + cpu_clear(smp_processor_id(), map); + + /* sanity check the map, remove any non-online processors. */ + cpus_and(map, map, cpu_online_map); + if (cpus_empty(map)) + goto done; call_data = &data; smp_wmb(); - /* Send a message to all other CPUs and wait for them to respond */ - smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION); + /* Send a message to all CPUs in the map */ + for_each_cpu_mask(cpu, map) + smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec; - /* Wait for response */ - while (atomic_read(&data.started) != cpus) { + /* Wait for indication that they have received the message */ + while (atomic_read(&data.started) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other cpus not " - "responding (%d)\n", smp_processor_id(), - atomic_read(&data.started)); + "responding (%d)\n", smp_processor_id(), + atomic_read(&data.started)); debugger(NULL); goto out; } } + /* optionally wait for the CPUs to complete */ if (wait) { - while (atomic_read(&data.finished) != cpus) { + while (atomic_read(&data.finished) != num_cpus) { HMT_low(); if (get_tb() >= timeout) { printk("smp_call_function on cpu %d: other " - "cpus not finishing (%d/%d)\n", - smp_processor_id(), - atomic_read(&data.finished), - atomic_read(&data.started)); + "cpus not finishing (%d/%d)\n", + smp_processor_id(), + atomic_read(&data.finished), + atomic_read(&data.started)); debugger(NULL); goto out; } } } + done: ret = 0; out: @@ -262,8 +273,30 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, return ret; } +int smp_call_function(void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map); +} EXPORT_SYMBOL(smp_call_function); +int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, + int wait) +{ + cpumask_t map = CPU_MASK_NONE; + int ret = -EBUSY; + + if (!cpu_online(cpu)) + return -EINVAL; + + cpu_set(cpu, map); + if (cpu != get_cpu()) + ret = smp_call_function_map(func,info,nonatomic,wait,map); + put_cpu(); + return ret; +} +EXPORT_SYMBOL(smp_call_function_single); + void smp_call_function_interrupt(void) { void (*func) (void *info); diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c new file mode 100644 index 000000000000..77b7b34b5955 --- /dev/null +++ b/arch/powerpc/kernel/swsusp.c @@ -0,0 +1,39 @@ +/* + * Common powerpc suspend code for 32 and 64 bits + * + * Copyright 2007 Johannes Berg <johannes@sipsolutions.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 + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/sched.h> +#include <asm/suspend.h> +#include <asm/system.h> +#include <asm/current.h> +#include <asm/mmu_context.h> + +void save_processor_state(void) +{ + /* + * flush out all the special registers so we don't need + * to save them in the snapshot + */ + flush_fp_to_thread(current); + flush_altivec_to_thread(current); + flush_spe_to_thread(current); + +#ifdef CONFIG_PPC64 + hard_irq_disable(); +#endif + +} + +void restore_processor_state(void) +{ +#ifdef CONFIG_PPC32 + set_context(current->active_mm->context.id, current->active_mm->pgd); +#endif +} diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c new file mode 100644 index 000000000000..6f3f0697274e --- /dev/null +++ b/arch/powerpc/kernel/swsusp_64.c @@ -0,0 +1,24 @@ +/* + * PowerPC 64-bit swsusp implementation + * + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> + * + * GPLv2 + */ + +#include <asm/system.h> +#include <asm/iommu.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +void do_after_copyback(void) +{ + iommu_restore(); + touch_softlockup_watchdog(); + mb(); +} + +void _iommu_save(void) +{ + iommu_save(); +} diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S new file mode 100644 index 000000000000..e092c3cbdb9b --- /dev/null +++ b/arch/powerpc/kernel/swsusp_asm64.S @@ -0,0 +1,228 @@ +/* + * PowerPC 64-bit swsusp implementation + * + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> + * + * GPLv2 + */ + +#include <linux/threads.h> +#include <asm/processor.h> +#include <asm/page.h> +#include <asm/cputable.h> +#include <asm/thread_info.h> +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> + +/* + * Structure for storing CPU registers on the save area. + */ +#define SL_r1 0x00 /* stack pointer */ +#define SL_PC 0x08 +#define SL_MSR 0x10 +#define SL_SDR1 0x18 +#define SL_XER 0x20 +#define SL_TB 0x40 +#define SL_r2 0x48 +#define SL_CR 0x50 +#define SL_LR 0x58 +#define SL_r12 0x60 +#define SL_r13 0x68 +#define SL_r14 0x70 +#define SL_r15 0x78 +#define SL_r16 0x80 +#define SL_r17 0x88 +#define SL_r18 0x90 +#define SL_r19 0x98 +#define SL_r20 0xa0 +#define SL_r21 0xa8 +#define SL_r22 0xb0 +#define SL_r23 0xb8 +#define SL_r24 0xc0 +#define SL_r25 0xc8 +#define SL_r26 0xd0 +#define SL_r27 0xd8 +#define SL_r28 0xe0 +#define SL_r29 0xe8 +#define SL_r30 0xf0 +#define SL_r31 0xf8 +#define SL_SIZE SL_r31+8 + +/* these macros rely on the save area being + * pointed to by r11 */ +#define SAVE_SPECIAL(special) \ + mf##special r0 ;\ + std r0, SL_##special(r11) +#define RESTORE_SPECIAL(special) \ + ld r0, SL_##special(r11) ;\ + mt##special r0 +#define SAVE_REGISTER(reg) \ + std reg, SL_##reg(r11) +#define RESTORE_REGISTER(reg) \ + ld reg, SL_##reg(r11) + +/* space for storing cpu state */ + .section .data + .align 5 +swsusp_save_area: + .space SL_SIZE + + .section ".toc","aw" +swsusp_save_area_ptr: + .tc swsusp_save_area[TC],swsusp_save_area +restore_pblist_ptr: + .tc restore_pblist[TC],restore_pblist + + .section .text + .align 5 +_GLOBAL(swsusp_arch_suspend) + ld r11,swsusp_save_area_ptr@toc(r2) + SAVE_SPECIAL(LR) + SAVE_REGISTER(r1) + SAVE_SPECIAL(CR) + SAVE_SPECIAL(TB) + SAVE_REGISTER(r2) + SAVE_REGISTER(r12) + SAVE_REGISTER(r13) + SAVE_REGISTER(r14) + SAVE_REGISTER(r15) + SAVE_REGISTER(r16) + SAVE_REGISTER(r17) + SAVE_REGISTER(r18) + SAVE_REGISTER(r19) + SAVE_REGISTER(r20) + SAVE_REGISTER(r21) + SAVE_REGISTER(r22) + SAVE_REGISTER(r23) + SAVE_REGISTER(r24) + SAVE_REGISTER(r25) + SAVE_REGISTER(r26) + SAVE_REGISTER(r27) + SAVE_REGISTER(r28) + SAVE_REGISTER(r29) + SAVE_REGISTER(r30) + SAVE_REGISTER(r31) + SAVE_SPECIAL(MSR) + SAVE_SPECIAL(SDR1) + SAVE_SPECIAL(XER) + + /* we push the stack up 128 bytes but don't store the + * stack pointer on the stack like a real stackframe */ + addi r1,r1,-128 + + bl _iommu_save + bl swsusp_save + + /* restore LR */ + ld r11,swsusp_save_area_ptr@toc(r2) + RESTORE_SPECIAL(LR) + addi r1,r1,128 + + blr + +/* Resume code */ +_GLOBAL(swsusp_arch_resume) + /* Stop pending alitvec streams and memory accesses */ +BEGIN_FTR_SECTION + DSSALL +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + sync + + ld r12,restore_pblist_ptr@toc(r2) + ld r12,0(r12) + + cmpdi r12,0 + beq- nothing_to_copy + li r15,512 +copyloop: + ld r13,pbe_address(r12) + ld r14,pbe_orig_address(r12) + + mtctr r15 + li r10,0 +copy_page_loop: + ldx r0,r10,r13 + stdx r0,r10,r14 + addi r10,r10,8 + bdnz copy_page_loop + + ld r12,pbe_next(r12) + cmpdi r12,0 + bne+ copyloop +nothing_to_copy: + + /* flush caches */ + lis r3, 0x10 + mtctr r3 + li r3, 0 + ori r3, r3, CONFIG_KERNEL_START>>48 + li r0, 48 + sld r3, r3, r0 + li r0, 0 +1: + dcbf r0,r3 + addi r3,r3,0x20 + bdnz 1b + + sync + + tlbia + + ld r11,swsusp_save_area_ptr@toc(r2) + + RESTORE_SPECIAL(CR) + + /* restore timebase */ + /* load saved tb */ + ld r1, SL_TB(r11) + /* get upper 32 bits of it */ + srdi r2, r1, 32 + /* clear tb lower to avoid wrap */ + li r0, 0 + mttbl r0 + /* set tb upper */ + mttbu r2 + /* set tb lower */ + mttbl r1 + + /* restore registers */ + RESTORE_REGISTER(r1) + RESTORE_REGISTER(r2) + RESTORE_REGISTER(r12) + RESTORE_REGISTER(r13) + RESTORE_REGISTER(r14) + RESTORE_REGISTER(r15) + RESTORE_REGISTER(r16) + RESTORE_REGISTER(r17) + RESTORE_REGISTER(r18) + RESTORE_REGISTER(r19) + RESTORE_REGISTER(r20) + RESTORE_REGISTER(r21) + RESTORE_REGISTER(r22) + RESTORE_REGISTER(r23) + RESTORE_REGISTER(r24) + RESTORE_REGISTER(r25) + RESTORE_REGISTER(r26) + RESTORE_REGISTER(r27) + RESTORE_REGISTER(r28) + RESTORE_REGISTER(r29) + RESTORE_REGISTER(r30) + RESTORE_REGISTER(r31) + /* can't use RESTORE_SPECIAL(MSR) */ + ld r0, SL_MSR(r11) + mtmsrd r0, 0 + RESTORE_SPECIAL(SDR1) + RESTORE_SPECIAL(XER) + + sync + + addi r1,r1,-128 + bl slb_flush_and_rebolt + bl do_after_copyback + addi r1,r1,128 + + ld r11,swsusp_save_area_ptr@toc(r2) + RESTORE_SPECIAL(LR) + + li r3, 0 + blr diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index d358866b880f..fc6647d332cb 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -24,7 +24,6 @@ #include <linux/syscalls.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/sem.h> #include <linux/msg.h> #include <linux/shm.h> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 933e214c33e8..68991c2d4a1b 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -342,10 +342,12 @@ static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, switch (action) { case CPU_ONLINE: + case CPU_ONLINE_FROZEN: register_cpu_online(cpu); break; #ifdef CONFIG_HOTPLUG_CPU case CPU_DEAD: + case CPU_DEAD_FROZEN: unregister_cpu_online(cpu); break; #endif @@ -499,4 +501,4 @@ static int __init topology_init(void) return 0; } -__initcall(topology_init); +subsys_initcall(topology_init); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 7cedef8f5f70..2c8564d54e4d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -711,30 +711,15 @@ void wakeup_decrementer(void) 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; 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; - /* - * The stolen time calculation for POWER5 shared-processor LPAR - * systems works better if the two threads' timebase interrupts - * are staggered by half a jiffy with respect to each other. - */ + for_each_possible_cpu(i) { if (i == boot_cpuid) continue; - if (i == (boot_cpuid ^ 1)) - per_cpu(last_jiffy, i) = - per_cpu(last_jiffy, boot_cpuid) - half; - else if (i & 1) - per_cpu(last_jiffy, i) = - per_cpu(last_jiffy, i ^ 1) + half; - else { - previous_tb += offset; - per_cpu(last_jiffy, i) = previous_tb; - } + per_cpu(last_jiffy, i) = previous_tb; } } #endif diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index f7862224fe85..bf6445ac9f1c 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -33,8 +33,8 @@ #include <linux/kexec.h> #include <linux/backlight.h> #include <linux/bug.h> +#include <linux/kdebug.h> -#include <asm/kdebug.h> #include <asm/pgtable.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -72,20 +72,6 @@ EXPORT_SYMBOL(__debugger_dabr_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif -ATOMIC_NOTIFIER_HEAD(powerpc_die_chain); - -int register_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&powerpc_die_chain, nb); -} -EXPORT_SYMBOL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&powerpc_die_chain, nb); -} -EXPORT_SYMBOL(unregister_die_notifier); - /* * Trap & Exception support */ diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 7e0971868fc2..87703df87509 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -51,6 +51,9 @@ void __init udbg_early_init(void) udbg_init_pas_realmode(); #elif defined(CONFIG_BOOTX_TEXT) udbg_init_btext(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_44x) + /* PPC44x debug */ + udbg_init_44x_as1(); #endif } @@ -142,29 +145,22 @@ static void udbg_console_write(struct console *con, const char *s, static struct console udbg_console = { .name = "udbg", .write = udbg_console_write, - .flags = CON_PRINTBUFFER | CON_ENABLED, + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT, .index = -1, }; static int early_console_initialized; -void __init disable_early_printk(void) -{ - if (!early_console_initialized) - return; - if (strstr(boot_command_line, "udbg-immortal")) { - printk(KERN_INFO "early console immortal !\n"); - return; - } - unregister_console(&udbg_console); - early_console_initialized = 0; -} - /* called by setup_system */ void register_early_udbg_console(void) { if (early_console_initialized) return; + + if (strstr(boot_command_line, "udbg-immortal")) { + printk(KERN_INFO "early console immortal !\n"); + udbg_console.flags &= ~CON_BOOT; + } early_console_initialized = 1; register_console(&udbg_console); } diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index a963f657222b..7afab5bcd61a 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -191,3 +191,26 @@ void udbg_init_pas_realmode(void) udbg_getc_poll = NULL; } #endif /* CONFIG_PPC_MAPLE */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_44x +#include <platforms/44x/44x.h> + +static void udbg_44x_as1_putc(char c) +{ + if (udbg_comport) { + while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + as1_writeb(c, &udbg_comport->thr); eieio(); + if (c == '\n') + udbg_44x_as1_putc('\r'); + } +} + +void __init udbg_init_44x_as1(void) +{ + udbg_comport = + (volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; + + udbg_putc = udbg_44x_as1_putc; +} +#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index e46c31b36641..4245579edb4e 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/slab.h> diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index b2c1b67a10a7..62c1bc12ea39 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -117,7 +117,7 @@ static const struct vio_device_id *vio_match_device( { while (ids->type[0] != '\0') { if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && - device_is_compatible(dev->dev.archdata.of_node, + of_device_is_compatible(dev->dev.archdata.of_node, ids->compat)) return ids; ids++; diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 132067313147..21c39ff2dc39 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -34,7 +34,7 @@ SECTIONS /* Text and gots */ .text : { _text = .; - *(.text .text.*) + TEXT_TEXT SCHED_TEXT LOCK_TEXT KPROBES_TEXT @@ -167,7 +167,7 @@ SECTIONS #ifdef CONFIG_PPC32 .data : { - *(.data) + DATA_DATA *(.sdata) *(.got.plt) *(.got) } |