diff options
Diffstat (limited to 'arch/ppc64')
89 files changed, 1698 insertions, 1282 deletions
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 13b262f1021..c658650af42 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -28,10 +28,6 @@ config GENERIC_ISA_DMA bool default y -config HAVE_DEC_LOCK - bool - default y - config EARLY_PRINTK bool default y @@ -44,6 +40,10 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y +config ARCH_MAY_HAVE_PC_FDC + bool + default y + # We optimistically allocate largepages from the VM, so make the limit # large enough (16MB). This badly named config option is actually # max order + 1 diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug index 46b1ce58da3..f16a5030527 100644 --- a/arch/ppc64/Kconfig.debug +++ b/arch/ppc64/Kconfig.debug @@ -41,10 +41,19 @@ config XMON help Include in-kernel hooks for the xmon kernel monitor/debugger. Unless you are intending to debug the kernel, say N here. + Make sure to enable also CONFIG_BOOTX_TEXT on Macs. Otherwise + nothing will appear on the screen (xmon writes directly to the + framebuffer memory). + The cmdline option 'xmon' or 'xmon=early' will drop into xmon very + early during boot. 'xmon=on' will just enable the xmon debugger hooks. + 'xmon=off' will disable the debugger hooks if CONFIG_XMON_DEFAULT is set. config XMON_DEFAULT bool "Enable xmon by default" depends on XMON + help + xmon is normally disabled unless booted with 'xmon=on'. + Use 'xmon=off' to disable xmon init during runtime. config PPCDBG bool "Include PPCDBG realtime debugging" diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 6350cce82ef..521c2a5a286 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -49,14 +49,14 @@ NM := $(NM) --synthetic endif -CHECKFLAGS += -m64 -D__powerpc__ +CHECKFLAGS += -m64 -D__powerpc__ -D__powerpc64__ LDFLAGS := -m elf64ppc LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) CFLAGS += -msoft-float -pipe -mminimal-toc -mtraceback=none \ -mcall-aixdesc # Temporary hack until we have migrated to asm-powerpc -CPPFLAGS += -Iinclude3 +CPPFLAGS += -Iarch/$(ARCH)/include GCC_VERSION := $(call cc-version) GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;) @@ -89,11 +89,12 @@ drivers-$(CONFIG_OPROFILE) += arch/ppc64/oprofile/ boot := arch/ppc64/boot -boottarget-$(CONFIG_PPC_PSERIES) := zImage zImage.initrd -boottarget-$(CONFIG_PPC_MAPLE) := zImage zImage.initrd -boottarget-$(CONFIG_PPC_ISERIES) := vmlinux.sminitrd vmlinux.initrd vmlinux.sm -boottarget-$(CONFIG_PPC_BPA) := zImage zImage.initrd -$(boottarget-y): vmlinux +boottargets-$(CONFIG_PPC_PSERIES) += zImage zImage.initrd +boottargets-$(CONFIG_PPC_PMAC) += zImage.vmode zImage.initrd.vmode +boottargets-$(CONFIG_PPC_MAPLE) += zImage zImage.initrd +boottargets-$(CONFIG_PPC_ISERIES) += vmlinux.sminitrd vmlinux.initrd vmlinux.sm +boottargets-$(CONFIG_PPC_BPA) += zImage zImage.initrd +$(boottargets-y): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage @@ -106,7 +107,7 @@ install: vmlinux $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ defaultimage-$(CONFIG_PPC_PSERIES) := zImage -defaultimage-$(CONFIG_PPC_PMAC) := vmlinux +defaultimage-$(CONFIG_PPC_PMAC) := zImage.vmode defaultimage-$(CONFIG_PPC_MAPLE) := zImage defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux KBUILD_IMAGE := $(defaultimage-y) @@ -114,27 +115,21 @@ all: $(KBUILD_IMAGE) archclean: $(Q)$(MAKE) $(clean)=$(boot) - $(Q)rm -rf include3 + # Temporary hack until we have migrated to asm-powerpc + $(Q)rm -rf arch/$(ARCH)/include -prepare: include/asm-ppc64/offsets.h - -arch/ppc64/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-ppc64/offsets.h: arch/ppc64/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) # Temporary hack until we have migrated to asm-powerpc -include/asm: include3/asm -include3/asm: - $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi; - $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm +include/asm: arch/$(ARCH)/include/asm +arch/$(ARCH)/include/asm: + $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi + $(Q)ln -fsn $(srctree)/include/asm-powerpc arch/$(ARCH)/include/asm define archhelp - echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' - echo ' zImage.initrd- Compressed kernel image with initrd attached,' - echo ' sourced from arch/$(ARCH)/boot/ramdisk.image.gz' - echo ' (arch/$(ARCH)/boot/zImage.initrd)' + echo ' zImage.vmode - Compressed kernel image (arch/$(ARCH)/boot/zImage.vmode)' + echo ' zImage.initrd.vmode - Compressed kernel image with initrd attached,' + echo ' sourced from arch/$(ARCH)/boot/ramdisk.image.gz' + echo ' (arch/$(ARCH)/boot/zImage.initrd.vmode)' + echo ' zImage - zImage for pSeries machines' + echo ' zImage.initrd - zImage with initrd for pSeries machines' endef - -CLEAN_FILES += include/asm-ppc64/offsets.h diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index 2c5f5e73d00..33fdc871089 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -37,6 +37,9 @@ quiet_cmd_bootcc = BOOTCC $@ quiet_cmd_bootas = BOOTAS $@ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< +quiet_cmd_bootld = BOOTLD $@ + cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2) + $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c $(call if_changed_dep,bootcc) $(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S @@ -53,7 +56,7 @@ src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) hostprogs-y := addnote addRamDisk -targets += zImage zImage.initrd imagesize.c \ +targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd imagesize.c \ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ @@ -63,7 +66,7 @@ extra-y := initrd.o quiet_cmd_ramdisk = RAMDISK $@ cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@ -quiet_cmd_stripvm = STRIP $@ +quiet_cmd_stripvm = STRIP $@ cmd_stripvm = $(STRIP) -s $< -o $@ vmlinux.strip: vmlinux FORCE @@ -71,12 +74,20 @@ vmlinux.strip: vmlinux FORCE $(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE $(call if_changed,ramdisk) -addsection = $(CROSS32OBJCOPY) $(1) \ - --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ - --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(OBJCOPYFLAGS) +quiet_cmd_addsection = ADDSEC $@ + cmd_addsection = $(CROSS32OBJCOPY) $@ \ + --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \ + --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS) + +quiet_cmd_imagesize = GENSIZE $@ + cmd_imagesize = ls -l vmlinux.strip | \ + awk '{printf "/* generated -- do not edit! */\n" "unsigned long vmlinux_filesize = %d;\n", $$5}' \ + > $(obj)/imagesize.c && \ + $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ + awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' >> $(obj)/imagesize.c -quiet_cmd_addnote = ADDNOTE $@ - cmd_addnote = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@ +quiet_cmd_addnote = ADDNOTE $@ + cmd_addnote = $(obj)/addnote $@ $(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE $(call if_changed,gzip) @@ -85,28 +96,30 @@ $(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz cp -f $(obj)/ramdisk.image.gz $@ $(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz FORCE - touch $@ + @touch $@ $(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c FORCE $(call if_changed_dep,bootcc) - $(call addsection, $@) + $(call cmd,addsection) + +$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required)) +$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) FORCE + $(call cmd,bootld,$(obj-boot)) + +$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd)) +$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) FORCE + $(call cmd,bootld,$(obj-boot)) -$(obj)/zImage: obj-boot += $(call obj-sec, $(required)) -$(obj)/zImage: $(call obj-sec, $(required)) $(obj-boot) $(obj)/addnote FORCE +$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote FORCE + @cp -f $< $@ $(call if_changed,addnote) -$(obj)/zImage.initrd: obj-boot += $(call obj-sec, $(required) $(initrd)) -$(obj)/zImage.initrd: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/addnote FORCE +$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote FORCE + @cp -f $< $@ $(call if_changed,addnote) $(obj)/imagesize.c: vmlinux.strip - @echo Generating $@ - ls -l vmlinux.strip | \ - awk '{printf "/* generated -- do not edit! */\n" \ - "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c - $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ - awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' \ - >> $(obj)/imagesize.c + $(call cmd,imagesize) install: $(CONFIGURE) $(BOOTIMAGE) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)" diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index 99e68cfbe68..f7ec19a2d0b 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -23,7 +23,8 @@ extern void flush_cache(void *, unsigned long); /* Value picked to match that used by yaboot */ #define PROG_START 0x01400000 -#define RAM_END (256<<20) // Fixme: use OF */ +#define RAM_END (512<<20) // Fixme: use OF */ +#define ONE_MB 0x100000 static char *avail_ram; static char *begin_avail, *end_avail; @@ -32,6 +33,7 @@ static unsigned int heap_use; static unsigned int heap_max; extern char _start[]; +extern char _end[]; extern char _vmlinux_start[]; extern char _vmlinux_end[]; extern char _initrd_start[]; @@ -58,13 +60,13 @@ typedef void (*kernel_entry_t)( unsigned long, #undef DEBUG -static unsigned long claim_base = PROG_START; +static unsigned long claim_base; static unsigned long try_claim(unsigned long size) { unsigned long addr = 0; - for(; claim_base < RAM_END; claim_base += 0x100000) { + for(; claim_base < RAM_END; claim_base += ONE_MB) { #ifdef DEBUG printf(" trying: 0x%08lx\n\r", claim_base); #endif @@ -95,7 +97,26 @@ void start(unsigned long a1, unsigned long a2, void *promptr) if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) exit(); - printf("\n\rzImage starting: loaded at 0x%x\n\r", (unsigned)_start); + printf("\n\rzImage starting: loaded at 0x%lx\n\r", (unsigned long) _start); + + /* + * The first available claim_base must be above the end of the + * the loaded kernel wrapper file (_start to _end includes the + * initrd image if it is present) and rounded up to a nice + * 1 MB boundary for good measure. + */ + + claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB); + +#if defined(PROG_START) + /* + * Maintain a "magic" minimum address. This keeps some older + * firmware platforms running. + */ + + if (claim_base < PROG_START) + claim_base = PROG_START; +#endif /* * Now we try to claim some memory for the kernel itself @@ -105,7 +126,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr) * size... In practice we add 1Mb, that is enough, but we should really * consider fixing the Makefile to put a _raw_ kernel in there ! */ - vmlinux_memsize += 0x100000; + vmlinux_memsize += ONE_MB; printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); vmlinux.addr = try_claim(vmlinux_memsize); if (vmlinux.addr == 0) { diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index f4b3bfcc109..ae60eb1193c 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ - pSeries_setup.o pSeries_iommu.o + pSeries_setup.o pSeries_iommu.o udbg_16550.o obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ bpa_iic.o spider-pic.o @@ -58,9 +58,11 @@ obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_MPIC) += mpic.o obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ - pmac_time.o pmac_nvram.o pmac_low_i2c.o + pmac_time.o pmac_nvram.o pmac_low_i2c.o \ + udbg_scc.o -obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o +obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ + udbg_16550.o obj-$(CONFIG_U3_DART) += u3_iommu.o diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 17e35d0fed0..1ff4fa05a97 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -68,6 +68,7 @@ int main(void) DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); #endif /* CONFIG_ALTIVEC */ DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); diff --git a/arch/ppc64/kernel/bpa_iic.c b/arch/ppc64/kernel/bpa_iic.c index c8f3dc3fad7..0aaa878e19d 100644 --- a/arch/ppc64/kernel/bpa_iic.c +++ b/arch/ppc64/kernel/bpa_iic.c @@ -205,6 +205,18 @@ static struct iic_regs __iomem *find_iic(int cpu) } #ifdef CONFIG_SMP + +/* Use the highest interrupt priorities for IPI */ +static inline int iic_ipi_to_irq(int ipi) +{ + return IIC_IPI_OFFSET + IIC_NUM_IPIS - 1 - ipi; +} + +static inline int iic_irq_to_ipi(int irq) +{ + return IIC_NUM_IPIS - 1 - (irq - IIC_IPI_OFFSET); +} + void iic_setup_cpu(void) { out_be64(&__get_cpu_var(iic).regs->prio, 0xff); @@ -212,18 +224,20 @@ void iic_setup_cpu(void) void iic_cause_IPI(int cpu, int mesg) { - out_be64(&per_cpu(iic, cpu).regs->generate, mesg); + out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); } static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { - - smp_message_recv(irq - IIC_IPI_OFFSET, regs); + smp_message_recv(iic_irq_to_ipi(irq), regs); return IRQ_HANDLED; } -static void iic_request_ipi(int irq, const char *name) +static void iic_request_ipi(int ipi, const char *name) { + int irq; + + irq = iic_ipi_to_irq(ipi); /* IPIs are marked SA_INTERRUPT as they must run with irqs * disabled */ get_irq_desc(irq)->handler = &iic_pic; @@ -233,10 +247,10 @@ static void iic_request_ipi(int irq, const char *name) void iic_request_IPIs(void) { - iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_CALL_FUNCTION, "IPI-call"); - iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_RESCHEDULE, "IPI-resched"); + iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call"); + iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched"); #ifdef CONFIG_DEBUGGER - iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); + iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); #endif /* CONFIG_DEBUGGER */ } #endif /* CONFIG_SMP */ diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c index c53f079e9b7..b6fbfbe9032 100644 --- a/arch/ppc64/kernel/btext.c +++ b/arch/ppc64/kernel/btext.c @@ -7,7 +7,6 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> -#include <linux/version.h> #include <asm/sections.h> #include <asm/prom.h> diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S index 0482c063c26..1fb673c511f 100644 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ b/arch/ppc64/kernel/cpu_setup_power4.S @@ -12,10 +12,9 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/page.h> -#include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cache.h> _GLOBAL(__970_cpu_preinit) diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 4847f2ac8c9..8831a28c3c4 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/module.h> +#include <asm/oprofile_impl.h> #include <asm/cputable.h> struct cpu_spec* cur_cpu_spec = NULL; @@ -54,24 +55,32 @@ struct cpu_spec cpu_specs[] = { .pvr_value = 0x00400000, .cpu_name = "POWER3 (630)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8, + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power3", + .oprofile_model = &op_model_rs64, +#endif }, { /* Power3+ */ .pvr_mask = 0xffff0000, .pvr_value = 0x00410000, .cpu_name = "POWER3 (630+)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8, + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power3", + .oprofile_model = &op_model_rs64, +#endif }, { /* Northstar */ .pvr_mask = 0xffff0000, @@ -79,11 +88,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "RS64-II (northstar)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + CPU_FTR_MMCRA | CPU_FTR_CTRL, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif }, { /* Pulsar */ .pvr_mask = 0xffff0000, @@ -91,11 +105,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "RS64-III (pulsar)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + CPU_FTR_MMCRA | CPU_FTR_CTRL, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif }, { /* I-star */ .pvr_mask = 0xffff0000, @@ -103,11 +122,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "RS64-III (icestar)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + CPU_FTR_MMCRA | CPU_FTR_CTRL, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif }, { /* S-star */ .pvr_mask = 0xffff0000, @@ -115,11 +139,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "RS64-IV (sstar)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + CPU_FTR_MMCRA | CPU_FTR_CTRL, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/rs64", + .oprofile_model = &op_model_rs64, +#endif }, { /* Power4 */ .pvr_mask = 0xffff0000, @@ -127,11 +156,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "POWER4 (gp)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power4", + .oprofile_model = &op_model_rs64, +#endif }, { /* Power4+ */ .pvr_mask = 0xffff0000, @@ -139,11 +173,16 @@ struct cpu_spec cpu_specs[] = { .cpu_name = "POWER4+ (gq)", .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power4", + .oprofile_model = &op_model_power4, +#endif }, { /* PPC970 */ .pvr_mask = 0xffff0000, @@ -152,12 +191,17 @@ struct cpu_spec cpu_specs[] = { .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif }, { /* PPC970FX */ .pvr_mask = 0xffff0000, @@ -166,12 +210,17 @@ struct cpu_spec cpu_specs[] = { .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 8, .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif }, { /* PPC970MP */ .pvr_mask = 0xffff0000, @@ -180,12 +229,16 @@ struct cpu_spec cpu_specs[] = { .cpu_features = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, .icache_bsize = 128, .dcache_bsize = 128, .cpu_setup = __setup_cpu_ppc970, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/970", + .oprofile_model = &op_model_power4, +#endif }, { /* Power5 */ .pvr_mask = 0xffff0000, @@ -199,7 +252,12 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power5", + .oprofile_model = &op_model_power4, +#endif }, { /* Power5 */ .pvr_mask = 0xffff0000, @@ -213,7 +271,12 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc64/power5", + .oprofile_model = &op_model_power4, +#endif }, { /* BE DD1.x */ .pvr_mask = 0xffff0000, @@ -239,6 +302,7 @@ struct cpu_spec cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64, .icache_bsize = 128, .dcache_bsize = 128, + .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, } }; diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c index af5272fedad..ba93fd73122 100644 --- a/arch/ppc64/kernel/eeh.c +++ b/arch/ppc64/kernel/eeh.c @@ -202,10 +202,9 @@ static void pci_addr_cache_print(struct pci_io_addr_cache *cache) while (n) { struct pci_io_addr_range *piar; piar = rb_entry(n, struct pci_io_addr_range, rb_node); - printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s %s\n", + printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s\n", (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt, - piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev), - pci_pretty_name(piar->pcidev)); + piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev)); cnt++; n = rb_next(n); } @@ -255,22 +254,24 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, static void __pci_addr_cache_insert_device(struct pci_dev *dev) { struct device_node *dn; + struct pci_dn *pdn; int i; int inserted = 0; dn = pci_device_to_OF_node(dev); if (!dn) { - printk(KERN_WARNING "PCI: no pci dn found for dev=%s %s\n", - pci_name(dev), pci_pretty_name(dev)); + printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", + pci_name(dev)); return; } /* Skip any devices for which EEH is not enabled. */ - if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || - dn->eeh_mode & EEH_MODE_NOCHECK) { + pdn = dn->data; + if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || + pdn->eeh_mode & EEH_MODE_NOCHECK) { #ifdef DEBUG - printk(KERN_INFO "PCI: skip building address cache for=%s %s\n", - pci_name(dev), pci_pretty_name(dev)); + printk(KERN_INFO "PCI: skip building address cache for=%s\n", + pci_name(dev)); #endif return; } @@ -416,6 +417,7 @@ int eeh_unregister_notifier(struct notifier_block *nb) static int read_slot_reset_state(struct device_node *dn, int rets[]) { int token, outputs; + struct pci_dn *pdn = dn->data; if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { token = ibm_read_slot_reset_state2; @@ -425,8 +427,8 @@ static int read_slot_reset_state(struct device_node *dn, int rets[]) outputs = 3; } - return rtas_call(token, 3, outputs, rets, dn->eeh_config_addr, - BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); + return rtas_call(token, 3, outputs, rets, pdn->eeh_config_addr, + BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); } /** @@ -447,12 +449,12 @@ static void eeh_panic(struct pci_dev *dev, int reset_state) * in light of potential corruption, we can use it here. */ if (panic_on_oops) - panic("EEH: MMIO failure (%d) on device:%s %s\n", reset_state, - pci_name(dev), pci_pretty_name(dev)); + panic("EEH: MMIO failure (%d) on device:%s\n", reset_state, + pci_name(dev)); else { __get_cpu_var(ignored_failures)++; - printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s %s\n", - reset_state, pci_name(dev), pci_pretty_name(dev)); + printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n", + reset_state, pci_name(dev)); } } @@ -482,8 +484,8 @@ static void eeh_event_handler(void *dummy) break; printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device " - "%s %s\n", event->reset_state, - pci_name(event->dev), pci_pretty_name(event->dev)); + "%s\n", event->reset_state, + pci_name(event->dev)); atomic_set(&eeh_fail_count, 0); notifier_call_chain (&eeh_notifier_chain, @@ -535,6 +537,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) unsigned long flags; int rc, reset_state; struct eeh_event *event; + struct pci_dn *pdn; __get_cpu_var(total_mmio_ffs)++; @@ -543,14 +546,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) if (!dn) return 0; + pdn = dn->data; /* Access to IO BARs might get this far and still not want checking. */ - if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || - dn->eeh_mode & EEH_MODE_NOCHECK) { + if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) || + pdn->eeh_mode & EEH_MODE_NOCHECK) { return 0; } - if (!dn->eeh_config_addr) { + if (!pdn->eeh_config_addr) { return 0; } @@ -558,7 +562,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * If we already have a pending isolation event for this * slot, we know it's bad already, we don't need to check... */ - if (dn->eeh_mode & EEH_MODE_ISOLATED) { + if (pdn->eeh_mode & EEH_MODE_ISOLATED) { atomic_inc(&eeh_fail_count); if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) { /* re-read the slot reset state */ @@ -583,7 +587,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) } /* prevent repeated reports of this failure */ - dn->eeh_mode |= EEH_MODE_ISOLATED; + pdn->eeh_mode |= EEH_MODE_ISOLATED; reset_state = rets[0]; @@ -591,9 +595,9 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) memset(slot_errbuf, 0, eeh_error_buf_size); rc = rtas_call(ibm_slot_error_detail, - 8, 1, NULL, dn->eeh_config_addr, - BUID_HI(dn->phb->buid), - BUID_LO(dn->phb->buid), NULL, 0, + 8, 1, NULL, pdn->eeh_config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), NULL, 0, virt_to_phys(slot_errbuf), eeh_error_buf_size, 1 /* Temporary Error */); @@ -680,8 +684,9 @@ static void *early_enable_eeh(struct device_node *dn, void *data) u32 *device_id = (u32 *)get_property(dn, "device-id", NULL); u32 *regs; int enable; + struct pci_dn *pdn = dn->data; - dn->eeh_mode = 0; + pdn->eeh_mode = 0; if (status && strcmp(status, "ok") != 0) return NULL; /* ignore devices with bad status */ @@ -692,7 +697,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* There is nothing to check on PCI to ISA bridges */ if (dn->type && !strcmp(dn->type, "isa")) { - dn->eeh_mode |= EEH_MODE_NOCHECK; + pdn->eeh_mode |= EEH_MODE_NOCHECK; return NULL; } @@ -709,7 +714,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) enable = 0; if (!enable) - dn->eeh_mode |= EEH_MODE_NOCHECK; + pdn->eeh_mode |= EEH_MODE_NOCHECK; /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ @@ -722,8 +727,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data) EEH_ENABLE); if (ret == 0) { eeh_subsystem_enabled = 1; - dn->eeh_mode |= EEH_MODE_SUPPORTED; - dn->eeh_config_addr = regs[0]; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + pdn->eeh_config_addr = regs[0]; #ifdef DEBUG printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name); #endif @@ -731,10 +736,11 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* This device doesn't support EEH, but it may have an * EEH parent, in which case we mark it as supported. */ - if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) { + if (dn->parent && dn->parent->data + && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { /* Parent supports EEH. */ - dn->eeh_mode |= EEH_MODE_SUPPORTED; - dn->eeh_config_addr = dn->parent->eeh_config_addr; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; return NULL; } } @@ -791,11 +797,13 @@ void __init eeh_init(void) for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { unsigned long buid; + struct pci_dn *pci; buid = get_phb_buid(phb); - if (buid == 0) + if (buid == 0 || phb->data == NULL) continue; + pci = phb->data; info.buid_lo = BUID_LO(buid); info.buid_hi = BUID_HI(buid); traverse_pci_devices(phb, early_enable_eeh, &info); @@ -824,9 +832,9 @@ void eeh_add_device_early(struct device_node *dn) struct pci_controller *phb; struct eeh_early_enable_info info; - if (!dn) + if (!dn || !dn->data) return; - phb = dn->phb; + phb = PCI_DN(dn)->phb; if (NULL == phb || 0 == phb->buid) { printk(KERN_WARNING "EEH: Expected buid but found none\n"); return; @@ -851,8 +859,7 @@ void eeh_add_device_late(struct pci_dev *dev) return; #ifdef DEBUG - printk(KERN_DEBUG "EEH: adding device %s %s\n", pci_name(dev), - pci_pretty_name(dev)); + printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); #endif pci_addr_cache_insert_device (dev); @@ -873,8 +880,7 @@ void eeh_remove_device(struct pci_dev *dev) /* Unregister the device with the EEH/PCI address search system */ #ifdef DEBUG - printk(KERN_DEBUG "EEH: remove device %s %s\n", pci_name(dev), - pci_pretty_name(dev)); + printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); #endif pci_addr_cache_remove_device(dev); } diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index b61572eb2a7..e8c0bbf4d00 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -28,7 +28,7 @@ #include <asm/mmu.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> #ifdef CONFIG_PPC_ISERIES @@ -276,12 +276,22 @@ _GLOBAL(ppc64_rt_sigsuspend) _GLOBAL(ppc32_rt_sigsuspend) bl .save_nvgprs bl .sys32_rt_sigsuspend - /* If sigsuspend() returns zero, we are going into a signal handler */ 70: cmpdi 0,r3,0 - beq .ret_from_except - /* If it returned -EINTR, we need to return via syscall_exit to set + /* If it returned an error, we need to return via syscall_exit to set the SO bit in cr0 and potentially stop for ptrace. */ - b syscall_exit + bne syscall_exit + /* If sigsuspend() returns zero, we are going into a signal handler. We + may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ +#ifdef CONFIG_AUDIT + ld r3,PACACURRENT(r13) + ld r4,AUDITCONTEXT(r3) + cmpdi 0,r4,0 + beq .ret_from_except /* No audit_context: Leave immediately. */ + li r4, 2 /* AUDITSC_FAILURE */ + li r5,-4 /* It's always -EINTR */ + bl .audit_syscall_exit +#endif + b .ret_from_except _GLOBAL(ppc_fork) bl .save_nvgprs @@ -400,15 +410,14 @@ BEGIN_FTR_SECTION cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq beq 2f /* if yes, don't slbie it */ - oris r0,r6,0x0800 /* set C (class) bit */ /* Bolt in the new stack SLB entry */ ld r7,KSP_VSID(r4) /* Get new stack's VSID */ - oris r6,r6,(SLB_ESID_V)@h - ori r6,r6,(SLB_NUM_BOLTED-1)@l - slbie r0 - slbie r0 /* Workaround POWER5 < DD2.1 issue */ - slbmte r7,r6 + oris r0,r6,(SLB_ESID_V)@h + ori r0,r0,(SLB_NUM_BOLTED-1)@l + slbie r6 + slbie r6 /* Workaround POWER5 < DD2.1 issue */ + slbmte r7,r0 isync 2: diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 03695977562..72c61041151 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -30,7 +30,7 @@ #include <asm/mmu.h> #include <asm/systemcfg.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/bug.h> #include <asm/cputable.h> #include <asm/setup.h> @@ -1646,9 +1646,10 @@ _GLOBAL(__secondary_start) #else /* set the ASR */ ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) lwz r3,PLATFORM(r3) /* r3 = platform flags */ - cmpldi r3,PLATFORM_PSERIES_LPAR - bne 98f + andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ + beq 98f /* branch if result is 0 */ mfspr r3,PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ @@ -1809,9 +1810,10 @@ _STATIC(start_here_multiplatform) ld r3,PACASTABREAL(r13) ori r4,r3,1 /* turn on valid bit */ ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) lwz r3,PLATFORM(r3) /* r3 = platform flags */ - cmpldi r3,PLATFORM_PSERIES_LPAR - bne 98f + andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ + beq 98f /* branch if result is 0 */ mfspr r3,PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ @@ -1828,10 +1830,11 @@ _STATIC(start_here_multiplatform) 99: /* Set SDR1 (hash table pointer) */ ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ + ld r3,0(r3) lwz r3,PLATFORM(r3) /* r3 = platform flags */ /* Test if bit 0 is set (LPAR bit) */ - andi. r3,r3,0x1 - bne 98f + andi. r3,r3,PLATFORM_LPAR + bne 98f /* branch if result is !0 */ LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ sub r6,r6,r26 ld r6,0(r6) /* get the value of _SDR1 */ diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c index d11c732daf8..5d921792571 100644 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ b/arch/ppc64/kernel/iSeries_VpdInfo.c @@ -264,8 +264,5 @@ void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ", count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor, frame, card); - if (pci_class_name(PciDev->class >> 8) == 0) - printk("0x%04X\n", (int)(PciDev->class >> 8)); - else - printk("%s\n", pci_class_name(PciDev->class >> 8)); + printk("0x%04X\n", (int)(PciDev->class >> 8)); } diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 356e4fd9a94..fbc273c32bc 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -252,7 +252,7 @@ unsigned long __init find_and_init_phbs(void) phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); if (phb == NULL) return -ENOMEM; - pci_setup_pci_controller(phb); + pci_setup_pci_controller(phb); phb->pci_mem_offset = phb->local_number = bus; phb->first_busno = bus; diff --git a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S index 97e4a265504..ca02afe2a79 100644 --- a/arch/ppc64/kernel/idle_power4.S +++ b/arch/ppc64/kernel/idle_power4.S @@ -20,7 +20,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #undef DEBUG diff --git a/arch/ppc64/kernel/iomap.c b/arch/ppc64/kernel/iomap.c index 153cc8b0f13..6160c8dbb7c 100644 --- a/arch/ppc64/kernel/iomap.c +++ b/arch/ppc64/kernel/iomap.c @@ -22,13 +22,23 @@ unsigned int fastcall ioread16(void __iomem *addr) { return readw(addr); } +unsigned int fastcall ioread16be(void __iomem *addr) +{ + return in_be16(addr); +} unsigned int fastcall ioread32(void __iomem *addr) { return readl(addr); } +unsigned int fastcall ioread32be(void __iomem *addr) +{ + return in_be32(addr); +} EXPORT_SYMBOL(ioread8); EXPORT_SYMBOL(ioread16); +EXPORT_SYMBOL(ioread16be); EXPORT_SYMBOL(ioread32); +EXPORT_SYMBOL(ioread32be); void fastcall iowrite8(u8 val, void __iomem *addr) { @@ -38,13 +48,23 @@ void fastcall iowrite16(u16 val, void __iomem *addr) { writew(val, addr); } +void fastcall iowrite16be(u16 val, void __iomem *addr) +{ + out_be16(addr, val); +} void fastcall iowrite32(u32 val, void __iomem *addr) { writel(val, addr); } +void fastcall iowrite32be(u32 val, void __iomem *addr) +{ + out_be32(addr, val); +} EXPORT_SYMBOL(iowrite8); EXPORT_SYMBOL(iowrite16); +EXPORT_SYMBOL(iowrite16be); EXPORT_SYMBOL(iowrite32); +EXPORT_SYMBOL(iowrite32be); /* * These are the "repeat read/write" functions. Note the @@ -56,15 +76,15 @@ EXPORT_SYMBOL(iowrite32); */ void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) { - _insb((u8 __force *) addr, dst, count); + _insb((u8 __iomem *) addr, dst, count); } void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) { - _insw_ns((u16 __force *) addr, dst, count); + _insw_ns((u16 __iomem *) addr, dst, count); } void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) { - _insl_ns((u32 __force *) addr, dst, count); + _insl_ns((u32 __iomem *) addr, dst, count); } EXPORT_SYMBOL(ioread8_rep); EXPORT_SYMBOL(ioread16_rep); @@ -72,15 +92,15 @@ EXPORT_SYMBOL(ioread32_rep); void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) { - _outsb((u8 __force *) addr, src, count); + _outsb((u8 __iomem *) addr, src, count); } void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) { - _outsw_ns((u16 __force *) addr, src, count); + _outsw_ns((u16 __iomem *) addr, src, count); } void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) { - _outsl_ns((u32 __force *) addr, src, count); + _outsl_ns((u32 __iomem *) addr, src, count); } EXPORT_SYMBOL(iowrite8_rep); EXPORT_SYMBOL(iowrite16_rep); diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c index 845eebd1e28..9032b6bfe03 100644 --- a/arch/ppc64/kernel/iommu.c +++ b/arch/ppc64/kernel/iommu.c @@ -438,7 +438,8 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl) void iommu_free_table(struct device_node *dn) { - struct iommu_table *tbl = dn->iommu_table; + struct pci_dn *pdn = dn->data; + struct iommu_table *tbl = pdn->iommu_table; unsigned long bitmap_sz, i; unsigned int order; diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index a3d519518fb..7e80d49c589 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c @@ -44,7 +44,7 @@ static struct kprobe *kprobe_prev; static unsigned long kprobe_status_prev, kprobe_saved_msr_prev; static struct pt_regs jprobe_saved_regs; -int arch_prepare_kprobe(struct kprobe *p) +int __kprobes arch_prepare_kprobe(struct kprobe *p) { int ret = 0; kprobe_opcode_t insn = *p->addr; @@ -68,27 +68,27 @@ int arch_prepare_kprobe(struct kprobe *p) return ret; } -void arch_copy_kprobe(struct kprobe *p) +void __kprobes arch_copy_kprobe(struct kprobe *p) { memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); p->opcode = *p->addr; } -void arch_arm_kprobe(struct kprobe *p) +void __kprobes arch_arm_kprobe(struct kprobe *p) { *p->addr = BREAKPOINT_INSTRUCTION; flush_icache_range((unsigned long) p->addr, (unsigned long) p->addr + sizeof(kprobe_opcode_t)); } -void arch_disarm_kprobe(struct kprobe *p) +void __kprobes arch_disarm_kprobe(struct kprobe *p) { *p->addr = p->opcode; flush_icache_range((unsigned long) p->addr, (unsigned long) p->addr + sizeof(kprobe_opcode_t)); } -void arch_remove_kprobe(struct kprobe *p) +void __kprobes arch_remove_kprobe(struct kprobe *p) { up(&kprobe_mutex); free_insn_slot(p->ainsn.insn); @@ -102,7 +102,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) regs->msr |= MSR_SE; /* single step inline if it is a trap variant */ - if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn)) + if (is_trap(insn)) regs->nip = (unsigned long)p->addr; else regs->nip = (unsigned long)p->ainsn.insn; @@ -122,7 +122,8 @@ static inline void restore_previous_kprobe(void) kprobe_saved_msr = kprobe_saved_msr_prev; } -void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) +void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, + struct pt_regs *regs) { struct kretprobe_instance *ri; @@ -151,7 +152,9 @@ static inline int kprobe_handler(struct pt_regs *regs) Disarm the probe we just hit, and ignore it. */ p = get_kprobe(addr); if (p) { - if (kprobe_status == KPROBE_HIT_SS) { + kprobe_opcode_t insn = *p->ainsn.insn; + if (kprobe_status == KPROBE_HIT_SS && + is_trap(insn)) { regs->msr &= ~MSR_SE; regs->msr |= kprobe_saved_msr; unlock_kprobes(); @@ -191,8 +194,7 @@ static inline int kprobe_handler(struct pt_regs *regs) * trap variant, it could belong to someone else */ kprobe_opcode_t cur_insn = *addr; - if (IS_TW(cur_insn) || IS_TD(cur_insn) || - IS_TWI(cur_insn) || IS_TDI(cur_insn)) + if (is_trap(cur_insn)) goto no_kprobe; /* * The breakpoint instruction was removed right @@ -244,7 +246,7 @@ void kretprobe_trampoline_holder(void) /* * Called when the probe at kretprobe trampoline is hit */ -int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; struct hlist_head *head; @@ -308,7 +310,7 @@ int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) * single-stepped a copy of the instruction. The address of this * copy is p->ainsn.insn. */ -static void resume_execution(struct kprobe *p, struct pt_regs *regs) +static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) { int ret; unsigned int insn = *p->ainsn.insn; @@ -373,8 +375,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) /* * Wrapper routine to for handling exceptions. */ -int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, - void *data) +int __kprobes kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) { struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; @@ -402,11 +404,11 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, default: break; } - preempt_enable(); + preempt_enable_no_resched(); return ret; } -int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); @@ -419,16 +421,16 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) return 1; } -void jprobe_return(void) +void __kprobes jprobe_return(void) { asm volatile("trap" ::: "memory"); } -void jprobe_return_end(void) +void __kprobes jprobe_return_end(void) { }; -int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { /* * FIXME - we should ideally be validating that we got here 'cos diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index edad361a8db..cae19bbd5ac 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -569,7 +569,7 @@ struct file_operations lparcfg_fops = { int __init lparcfg_init(void) { struct proc_dir_entry *ent; - mode_t mode = S_IRUSR; + mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; /* Allow writing if we have FW_FEATURE_SPLPAR */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 53993999b26..1d297e0edfc 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -283,7 +283,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; hose->ops = &u3_agp_pci_ops; hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); @@ -315,24 +315,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -346,25 +346,25 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev); pci_setup_phb_io(hose, primary); - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } @@ -447,9 +447,9 @@ void __init maple_pci_init(void) */ if (u3_agp) { struct device_node *np = u3_agp->arch_data; - np->busno = 0xf0; + PCI_DN(np)->busno = 0xf0; for (np = np->child; np; np = np->sibling) - np->busno = 0xf0; + PCI_DN(np)->busno = 0xf0; } /* Tell pci.c to use the common resource allocation mecanism */ diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index bb55b5a5691..fc0567498a3 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c @@ -207,9 +207,6 @@ static void __init maple_init_early(void) comport = (void *)ioremap(physport, 16); udbg_init_uart(comport, default_speed); - ppc_md.udbg_putc = udbg_putc; - ppc_md.udbg_getc = udbg_getc; - ppc_md.udbg_getc_poll = udbg_getc_poll; DBG("Hello World !\n"); } diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 474df0a862b..e7241ad80a0 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -26,7 +26,7 @@ #include <asm/page.h> #include <asm/cache.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> .text @@ -183,7 +183,7 @@ PPC64_CACHES: * flush all bytes from start through stop-1 inclusive */ -_GLOBAL(__flush_icache_range) +_KPROBE(__flush_icache_range) /* * Flush the data cache to memory @@ -223,7 +223,7 @@ _GLOBAL(__flush_icache_range) bdnz 2b isync blr - + .previous .text /* * Like above, but only do the D-cache. * @@ -957,7 +957,7 @@ _GLOBAL(sys_call_table32) .llong .ppc_fork .llong .sys_read .llong .sys_write - .llong .sys32_open /* 5 */ + .llong .compat_sys_open /* 5 */ .llong .sys_close .llong .sys32_waitpid .llong .sys32_creat @@ -1431,9 +1431,9 @@ _GLOBAL(sys_call_table) .llong .sys_ni_syscall /* 195 - 32bit only stat64 */ .llong .sys_ni_syscall /* 32bit only lstat64 */ .llong .sys_ni_syscall /* 32bit only fstat64 */ - .llong .sys_ni_syscall /* 32bit only pciconfig_read */ - .llong .sys_ni_syscall /* 32bit only pciconfig_write */ - .llong .sys_ni_syscall /* 32bit only pciconfig_iobase */ + .llong .sys_pciconfig_read + .llong .sys_pciconfig_write + .llong .sys_pciconfig_iobase /* 200 - pciconfig_iobase */ .llong .sys_ni_syscall /* reserved for MacOnLinux */ .llong .sys_getdents64 .llong .sys_pivot_root diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c index da580812ddf..9f200f0f2ad 100644 --- a/arch/ppc64/kernel/of_device.c +++ b/arch/ppc64/kernel/of_device.c @@ -233,7 +233,9 @@ void of_device_unregister(struct of_device *ofdev) device_unregister(&ofdev->dev); } -struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id) +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) { struct of_device *dev; @@ -245,7 +247,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * dev->node = np; dev->dma_mask = 0xffffffffUL; dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = NULL; + dev->dev.parent = parent; dev->dev.bus = &of_platform_bus_type; dev->dev.release = of_release_dev; @@ -259,6 +261,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * return dev; } + EXPORT_SYMBOL(of_match_device); EXPORT_SYMBOL(of_platform_bus_type); EXPORT_SYMBOL(of_register_driver); diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 9d5e1e7fc38..d17f0108a03 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -265,8 +265,10 @@ static void iommu_table_setparms(struct pci_controller *phb, tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; /* Test if we are going over 2GB of DMA space */ - if (phb->dma_window_base_cur + phb->dma_window_size > (1L << 31)) + if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { + udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); + } phb->dma_window_base_cur += phb->dma_window_size; @@ -295,7 +297,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, struct iommu_table *tbl, unsigned int *dma_window) { - tbl->it_busno = dn->bussubno; + tbl->it_busno = PCI_DN(dn)->bussubno; /* TODO: Parse field size properties properly. */ tbl->it_size = (((unsigned long)dma_window[4] << 32) | @@ -310,90 +312,85 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, static void iommu_bus_setup_pSeries(struct pci_bus *bus) { - struct device_node *dn, *pdn; + struct device_node *dn; struct iommu_table *tbl; + struct device_node *isa_dn, *isa_dn_orig; + struct device_node *tmp; + struct pci_dn *pci; + int children; DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self); - /* For each (root) bus, we carve up the available DMA space in 256MB - * pieces. Since each piece is used by one (sub) bus/device, that would - * give a maximum of 7 devices per PHB. In most cases, this is plenty. - * - * The exception is on Python PHBs (pre-POWER4). Here we don't have EADS - * bridges below the PHB to allocate the sectioned tables to, so instead - * we allocate a 1GB table at the PHB level. + dn = pci_bus_to_OF_node(bus); + pci = PCI_DN(dn); + + if (bus->self) { + /* This is not a root bus, any setup will be done for the + * device-side of the bridge in iommu_dev_setup_pSeries(). + */ + return; + } + + /* Check if the ISA bus on the system is under + * this PHB. */ + isa_dn = isa_dn_orig = of_find_node_by_type(NULL, "isa"); - dn = pci_bus_to_OF_node(bus); + while (isa_dn && isa_dn != dn) + isa_dn = isa_dn->parent; - if (!bus->self) { - /* Root bus */ - if (is_python(dn)) { - unsigned int *iohole; - - DBG("Python root bus %s\n", bus->name); - - iohole = (unsigned int *)get_property(dn, "io-hole", 0); - - if (iohole) { - /* On first bus we need to leave room for the - * ISA address space. Just skip the first 256MB - * alltogether. This leaves 768MB for the window. - */ - DBG("PHB has io-hole, reserving 256MB\n"); - dn->phb->dma_window_size = 3 << 28; - dn->phb->dma_window_base_cur = 1 << 28; - } else { - /* 1GB window by default */ - dn->phb->dma_window_size = 1 << 30; - dn->phb->dma_window_base_cur = 0; - } - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_setparms(dn->phb, dn, tbl); - dn->iommu_table = iommu_init_table(tbl); - } else { - /* Do a 128MB table at root. This is used for the IDE - * controller on some SMP-mode POWER4 machines. It - * doesn't hurt to allocate it on other machines - * -- it'll just be unused since new tables are - * allocated on the EADS level. - * - * Allocate at offset 128MB to avoid having to deal - * with ISA holes; 128MB table for IDE is plenty. - */ - dn->phb->dma_window_size = 1 << 27; - dn->phb->dma_window_base_cur = 1 << 27; - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_setparms(dn->phb, dn, tbl); - dn->iommu_table = iommu_init_table(tbl); - - /* All child buses have 256MB tables */ - dn->phb->dma_window_size = 1 << 28; - } - } else { - pdn = pci_bus_to_OF_node(bus->parent); + if (isa_dn_orig) + of_node_put(isa_dn_orig); + + /* Count number of direct PCI children of the PHB. + * All PCI device nodes have class-code property, so it's + * an easy way to find them. + */ + for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) + if (get_property(tmp, "class-code", NULL)) + children++; - if (!bus->parent->self && !is_python(pdn)) { - struct iommu_table *tbl; - /* First child and not python means this is the EADS - * level. Allocate new table for this slot with 256MB - * window. - */ + DBG("Children: %d\n", children); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + /* Calculate amount of DMA window per slot. Each window must be + * a power of two (due to pci_alloc_consistent requirements). + * + * Keep 256MB aside for PHBs with ISA. + */ - iommu_table_setparms(dn->phb, dn, tbl); + if (!isa_dn) { + /* No ISA/IDE - just set window size and return */ + pci->phb->dma_window_size = 0x80000000ul; /* To be divided */ - dn->iommu_table = iommu_init_table(tbl); - } else { - /* Lower than first child or under python, use parent table */ - dn->iommu_table = pdn->iommu_table; - } + while (pci->phb->dma_window_size * children > 0x80000000ul) + pci->phb->dma_window_size >>= 1; + DBG("No ISA/IDE, window size is 0x%lx\n", + pci->phb->dma_window_size); + pci->phb->dma_window_base_cur = 0; + + return; } + + /* If we have ISA, then we probably have an IDE + * controller too. Allocate a 128MB table but + * skip the first 128MB to avoid stepping on ISA + * space. + */ + pci->phb->dma_window_size = 0x8000000ul; + pci->phb->dma_window_base_cur = 0x8000000ul; + + tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + + iommu_table_setparms(pci->phb, dn, tbl); + pci->iommu_table = iommu_init_table(tbl); + + /* Divide the rest (1.75GB) among the children */ + pci->phb->dma_window_size = 0x80000000ul; + while (pci->phb->dma_window_size * children > 0x70000000ul) + pci->phb->dma_window_size >>= 1; + + DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); + } @@ -401,6 +398,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) { struct iommu_table *tbl; struct device_node *dn, *pdn; + struct pci_dn *ppci; unsigned int *dma_window = NULL; DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self); @@ -419,43 +417,60 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) return; } - if (!pdn->iommu_table) { + ppci = pdn->data; + if (!ppci->iommu_table) { /* Bussubno hasn't been copied yet. * Do it now because iommu_table_setparms_lpar needs it. */ - pdn->bussubno = bus->number; + + ppci->bussubno = bus->number; tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window); + iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); - pdn->iommu_table = iommu_init_table(tbl); + ppci->iommu_table = iommu_init_table(tbl); } if (pdn != dn) - dn->iommu_table = pdn->iommu_table; + PCI_DN(dn)->iommu_table = ppci->iommu_table; } static void iommu_dev_setup_pSeries(struct pci_dev *dev) { struct device_node *dn, *mydn; + struct iommu_table *tbl; + + DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, pci_name(dev)); - DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, dev->pretty_name); - /* Now copy the iommu_table ptr from the bus device down to the - * pci device_node. This means get_iommu_table() won't need to search - * up the device tree to find it. - */ mydn = dn = pci_device_to_OF_node(dev); - while (dn && dn->iommu_table == NULL) + /* If we're the direct child of a root bus, then we need to allocate + * an iommu table ourselves. The bus setup code should have setup + * the window sizes already. + */ + if (!dev->bus->self) { + DBG(" --> first child, no bridge. Allocating iommu table.\n"); + tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); + PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); + + return; + } + + /* If this device is further down the bus tree, search upwards until + * an already allocated iommu table is found and use that. + */ + + while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL) dn = dn->parent; - if (dn) { - mydn->iommu_table = dn->iommu_table; + if (dn && dn->data) { + PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table; } else { - DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name); + DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev)); } } @@ -463,10 +478,11 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti { int err = NOTIFY_OK; struct device_node *np = node; + struct pci_dn *pci = np->data; switch (action) { case PSERIES_RECONFIG_REMOVE: - if (np->iommu_table && + if (pci->iommu_table && get_property(np, "ibm,dma-window", NULL)) iommu_free_table(np); break; @@ -486,8 +502,9 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) struct device_node *pdn, *dn; struct iommu_table *tbl; int *dma_window = NULL; + struct pci_dn *pci; - DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name); + DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev)); /* dev setup for LPAR is a little tricky, since the device tree might * contain the dma-window properties per-device and not neccesarily @@ -497,8 +514,10 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) */ dn = pci_device_to_OF_node(dev); - for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) { - dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL); + for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table; + pdn = pdn->parent) { + dma_window = (unsigned int *) + get_property(pdn, "ibm,dma-window", NULL); if (dma_window) break; } @@ -507,28 +526,28 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) * slots on POWER4 machines. */ if (dma_window == NULL || pdn->parent == NULL) { - /* Fall back to regular (non-LPAR) dev setup */ - DBG("No dma window for device, falling back to regular setup\n"); - iommu_dev_setup_pSeries(dev); + DBG("No dma window for device, linking to parent\n"); + PCI_DN(dn)->iommu_table = PCI_DN(pdn)->iommu_table; return; } else { DBG("Found DMA window, allocating table\n"); } - if (!pdn->iommu_table) { + pci = pdn->data; + if (!pci->iommu_table) { /* iommu_table_setparms_lpar needs bussubno. */ - pdn->bussubno = pdn->phb->bus->number; + pci->bussubno = pci->phb->bus->number; tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window); + iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); - pdn->iommu_table = iommu_init_table(tbl); + pci->iommu_table = iommu_init_table(tbl); } if (pdn != dn) - dn->iommu_table = pdn->iommu_table; + PCI_DN(dn)->iommu_table = pci->iommu_table; } static void iommu_bus_setup_null(struct pci_bus *b) { } diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index 0a3ddc9227c..a6de83f2078 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -192,9 +192,9 @@ static unsigned char udbg_getcLP(void) void udbg_init_debug_lpar(void) { vtermno = 0; - ppc_md.udbg_putc = udbg_putcLP; - ppc_md.udbg_getc = udbg_getcLP; - ppc_md.udbg_getc_poll = udbg_getc_pollLP; + udbg_putc = udbg_putcLP; + udbg_getc = udbg_getcLP; + udbg_getc_poll = udbg_getc_pollLP; } /* returns 0 if couldn't find or use /chosen/stdout as console */ @@ -227,18 +227,18 @@ int find_udbg_vterm(void) termno = (u32 *)get_property(stdout_node, "reg", NULL); if (termno) { vtermno = termno[0]; - ppc_md.udbg_putc = udbg_putcLP; - ppc_md.udbg_getc = udbg_getcLP; - ppc_md.udbg_getc_poll = udbg_getc_pollLP; + udbg_putc = udbg_putcLP; + udbg_getc = udbg_getcLP; + udbg_getc_poll = udbg_getc_pollLP; found = 1; } } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { termno = (u32 *)get_property(stdout_node, "reg", NULL); if (termno) { vtermno = termno[0]; - ppc_md.udbg_putc = udbg_hvsi_putc; - ppc_md.udbg_getc = udbg_hvsi_getc; - ppc_md.udbg_getc_poll = udbg_hvsi_getc_poll; + udbg_putc = udbg_hvsi_putc; + udbg_getc = udbg_hvsi_getc; + udbg_getc_poll = udbg_hvsi_getc_poll; found = 1; } } @@ -266,6 +266,10 @@ void vpa_init(int cpu) /* Register the Virtual Processor Area (VPA) */ flags = 1UL << (63 - 18); + + if (cpu_has_feature(CPU_FTR_ALTIVEC)) + paca[cpu].lppaca.vmxregs_in_use = 1; + ret = register_vpa(flags, hwcpu, __pa(vpa)); if (ret) diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c index dc2a69d412a..58c61219d08 100644 --- a/arch/ppc64/kernel/pSeries_reconfig.c +++ b/arch/ppc64/kernel/pSeries_reconfig.c @@ -111,7 +111,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist struct device_node *np; int err = -ENOMEM; - np = kcalloc(1, sizeof(*np), GFP_KERNEL); + np = kzalloc(sizeof(*np), GFP_KERNEL); if (!np) goto out_err; diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index f0f0630cf07..3009701eb90 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -37,7 +37,7 @@ #include <linux/ioport.h> #include <linux/console.h> #include <linux/pci.h> -#include <linux/version.h> +#include <linux/utsname.h> #include <linux/adb.h> #include <linux/module.h> #include <linux/delay.h> @@ -238,8 +238,8 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - eeh_init(); find_and_init_phbs(); + eeh_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -272,7 +272,7 @@ static int __init pSeries_init_panel(void) { /* Manually leave the kernel version on the panel. */ ppc_md.progress("Linux ppc64\n", 0); - ppc_md.progress(UTS_RELEASE, 0); + ppc_md.progress(system_utsname.version, 0); return 0; } @@ -397,9 +397,6 @@ static void __init pSeries_init_early(void) comport = (void *)ioremap(physport, 16); udbg_init_uart(comport, default_speed); - ppc_md.udbg_putc = udbg_putc; - ppc_md.udbg_getc = udbg_getc; - ppc_md.udbg_getc_poll = udbg_getc_poll; DBG("Hello World !\n"); } @@ -593,6 +590,13 @@ static int pseries_shared_idle(void) return 0; } +static int pSeries_pci_probe_mode(struct pci_bus *bus) +{ + if (systemcfg->platform & PLATFORM_LPAR) + return PCI_PROBE_DEVTREE; + return PCI_PROBE_NORMAL; +} + struct machdep_calls __initdata pSeries_md = { .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, @@ -600,6 +604,7 @@ struct machdep_calls __initdata pSeries_md = { .get_cpuinfo = pSeries_get_cpuinfo, .log_error = pSeries_log_error, .pcibios_fixup = pSeries_final_fixup, + .pci_probe_mode = pSeries_pci_probe_mode, .irq_bus_setup = pSeries_irq_bus_setup, .restart = rtas_restart, .power_off = rtas_power_off, diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 79c7f322366..d2c7e2c4733 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -272,6 +272,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned long start_here = __pa((u32)*((unsigned long *) pSeries_secondary_smp_init)); unsigned int pcpu; + int start_cpu; if (cpu_isset(lcpu, of_spin_map)) /* Already started by OF and sitting in spin loop */ @@ -282,12 +283,20 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) /* Fixup atomic count: it exited inside IRQ handler. */ paca[lcpu].__current->thread_info->preempt_count = 0; - status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL, - pcpu, start_here, lcpu); + /* + * If the RTAS start-cpu token does not exist then presume the + * cpu is already spinning. + */ + start_cpu = rtas_token("start-cpu"); + if (start_cpu == RTAS_UNKNOWN_SERVICE) + return 1; + + status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu); if (status != 0) { printk(KERN_ERR "start-cpu failed: %i\n", status); return 0; } + return 1; } diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c index 6182a2cd90a..33a2d8db3f2 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/ppc64/kernel/pacaData.c @@ -59,6 +59,7 @@ extern unsigned long __toc_start; .fpregs_in_use = 1, \ .end_of_quantum = 0xfffffffffffffffful, \ .slb_count = 64, \ + .vmxregs_in_use = 0, \ }, \ #ifdef CONFIG_PPC_ISERIES diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index d0d55c7908e..ff4be1da69d 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -21,6 +21,7 @@ #include <linux/bootmem.h> #include <linux/mm.h> #include <linux/list.h> +#include <linux/syscalls.h> #include <asm/processor.h> #include <asm/io.h> @@ -50,6 +51,10 @@ unsigned long io_page_mask; EXPORT_SYMBOL(io_page_mask); +#ifdef CONFIG_PPC_MULTIPLATFORM +static void fixup_resource(struct resource *res, struct pci_dev *dev); +static void do_bus_setup(struct pci_bus *bus); +#endif unsigned int pcibios_assign_all_busses(void) { @@ -84,7 +89,6 @@ static void fixup_broken_pcnet32(struct pci_dev* dev) if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { dev->vendor = PCI_VENDOR_ID_AMD; pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); - pci_name_device(dev); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); @@ -225,10 +229,290 @@ static void __init pcibios_claim_of_setup(void) } #endif +#ifdef CONFIG_PPC_MULTIPLATFORM +static u32 get_int_prop(struct device_node *np, const char *name, u32 def) +{ + u32 *prop; + int len; + + prop = (u32 *) get_property(np, name, &len); + if (prop && len >= 4) + return *prop; + return def; +} + +static unsigned int pci_parse_of_flags(u32 addr0) +{ + unsigned int flags = 0; + + if (addr0 & 0x02000000) { + flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY; + flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64; + flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M; + if (addr0 & 0x40000000) + flags |= IORESOURCE_PREFETCH + | PCI_BASE_ADDRESS_MEM_PREFETCH; + } else if (addr0 & 0x01000000) + flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; + return flags; +} + +#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) + +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; + int proplen; + + addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); + if (!addrs) + return; + for (; proplen >= 20; proplen -= 20, addrs += 5) { + flags = pci_parse_of_flags(addrs[0]); + if (!flags) + continue; + base = GET_64BIT(addrs, 1); + size = GET_64BIT(addrs, 3); + if (!size) + continue; + i = addrs[0] & 0xff; + if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { + res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; + } else if (i == dev->rom_base_reg) { + res = &dev->resource[PCI_ROM_RESOURCE]; + flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + } else { + printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); + continue; + } + res->start = base; + res->end = base + size - 1; + res->flags = flags; + res->name = pci_name(dev); + fixup_resource(res, dev); + } +} + +static struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn) +{ + struct pci_dev *dev; + const char *type; + + dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + if (!dev) + return NULL; + type = get_property(node, "device_type", NULL); + if (type == NULL) + type = ""; + + memset(dev, 0, sizeof(struct pci_dev)); + dev->bus = bus; + dev->sysdata = node; + dev->dev.parent = bus->bridge; + dev->dev.bus = &pci_bus_type; + dev->devfn = devfn; + dev->multifunction = 0; /* maybe a lie? */ + + dev->vendor = get_int_prop(node, "vendor-id", 0xffff); + dev->device = get_int_prop(node, "device-id", 0xffff); + dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); + dev->subsystem_device = get_int_prop(node, "subsystem-id", 0); + + dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/ + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dev->class = get_int_prop(node, "class-code", 0); + + dev->current_state = 4; /* unknown power state */ + + if (!strcmp(type, "pci")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; + 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); + + pci_device_add(dev, bus); + + /* XXX pci_scan_msi_device(dev); */ + + return dev; +} + +static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); + +static void __devinit of_scan_bus(struct device_node *node, + struct pci_bus *bus) +{ + struct device_node *child = NULL; + u32 *reg; + int reglen, devfn; + struct pci_dev *dev; + + while ((child = of_get_next_child(node, child)) != NULL) { + reg = (u32 *) get_property(child, "reg", ®len); + if (reg == NULL || reglen < 20) + continue; + devfn = (reg[0] >> 8) & 0xff; + /* create a new pci_dev for this device */ + dev = of_create_pci_dev(child, bus, devfn); + if (!dev) + continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + of_scan_pci_bridge(child, dev); + } + + do_bus_setup(bus); +} + +static void __devinit of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev) +{ + struct pci_bus *bus; + u32 *busrange, *ranges; + int len, i, mode; + struct resource *res; + unsigned int flags; + u64 size; + + /* parse bus-range property */ + busrange = (u32 *) get_property(node, "bus-range", &len); + if (busrange == NULL || len != 8) { + printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", + node->full_name); + return; + } + ranges = (u32 *) get_property(node, "ranges", &len); + if (ranges == NULL) { + printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", + node->full_name); + return; + } + + bus = pci_add_new_bus(dev->bus, dev, busrange[0]); + if (!bus) { + printk(KERN_ERR "Failed to create pci bus for %s\n", + node->full_name); + return; + } + + bus->primary = dev->bus->number; + bus->subordinate = busrange[1]; + bus->bridge_ctl = 0; + bus->sysdata = node; + + /* parse ranges property */ + /* PCI #address-cells == 3 and #size-cells == 2 always */ + res = &dev->resource[PCI_BRIDGE_RESOURCES]; + for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { + res->flags = 0; + bus->resource[i] = res; + ++res; + } + i = 1; + for (; len >= 32; len -= 32, ranges += 8) { + flags = pci_parse_of_flags(ranges[0]); + size = GET_64BIT(ranges, 6); + if (flags == 0 || size == 0) + continue; + if (flags & IORESOURCE_IO) { + res = bus->resource[0]; + if (res->flags) { + printk(KERN_ERR "PCI: ignoring extra I/O range" + " for bridge %s\n", node->full_name); + continue; + } + } else { + if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { + printk(KERN_ERR "PCI: too many memory ranges" + " for bridge %s\n", node->full_name); + continue; + } + res = bus->resource[i]; + ++i; + } + res->start = GET_64BIT(ranges, 1); + res->end = res->start + size - 1; + res->flags = flags; + fixup_resource(res, dev); + } + sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), + bus->number); + + mode = PCI_PROBE_NORMAL; + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) + of_scan_bus(node, bus); + else if (mode == PCI_PROBE_NORMAL) + pci_scan_child_bus(bus); +} +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +static void __devinit scan_phb(struct pci_controller *hose) +{ + struct pci_bus *bus; + struct device_node *node = hose->arch_data; + int i, mode; + struct resource *res; + + bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); + if (bus == NULL) { + printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", + hose->global_number); + return; + } + bus->secondary = hose->first_busno; + hose->bus = bus; + + bus->resource[0] = res = &hose->io_resource; + if (res->flags && request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request PCI IO region " + "on PCI domain %04x\n", hose->global_number); + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request PCI memory region " + "on PCI domain %04x\n", hose->global_number); + } + + mode = PCI_PROBE_NORMAL; +#ifdef CONFIG_PPC_MULTIPLATFORM + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) { + bus->subordinate = hose->last_busno; + of_scan_bus(node, bus); + } +#endif /* CONFIG_PPC_MULTIPLATFORM */ + if (mode == PCI_PROBE_NORMAL) + hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + pci_bus_add_devices(bus); +} + static int __init pcibios_init(void) { struct pci_controller *hose, *tmp; - struct pci_bus *bus; /* For now, override phys_mem_access_prot. If we need it, * later, we may move that initialization to each ppc_md @@ -242,13 +526,8 @@ static int __init pcibios_init(void) printk("PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - hose->last_busno = 0xff; - bus = pci_scan_bus(hose->first_busno, hose->ops, - hose->arch_data); - hose->bus = bus; - hose->last_busno = bus->subordinate; - } + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + scan_phb(hose); #ifndef CONFIG_PPC_ISERIES if (pci_probe_only) @@ -820,118 +1099,89 @@ void phbs_remap_io(void) /* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. + * XXX this can go now, we use the OF device tree in all the + * cases that caused problems. -- paulus */ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) { - struct device_node *busdn, *dn; + return 0; +} + +static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + unsigned long start, end, mask, offset; - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ + if (res->flags & IORESOURCE_IO) { + offset = (unsigned long)hose->io_base_virt - pci_io_base; - if (busdn == NULL) - return 0; + start = res->start += offset; + end = res->end += offset; - /* - * Check to see if there is any of the 8 functions are in the - * device tree. If they are then we need to scan all the - * functions of this slot. - */ - for (dn = busdn->child; dn; dn = dn->sibling) - if ((dn->devfn >> 3) == (devfn >> 3)) - return 1; + /* Need to allow IO access to pages that are in the + ISA range */ + if (start < MAX_ISA_PORT) { + if (end > MAX_ISA_PORT) + end = MAX_ISA_PORT; - return 0; -} + start >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + /* get the range of pages for the map */ + mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1); + io_page_mask |= mask; + } + } else if (res->flags & IORESOURCE_MEM) { + res->start += hose->pci_mem_offset; + res->end += hose->pci_mem_offset; + } +} void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) + struct pci_bus *bus) { /* Update device resources. */ - struct pci_controller *hose = pci_bus_to_host(bus); int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - - pci_io_base; - unsigned long start, end, mask; - - start = dev->resource[i].start += offset; - end = dev->resource[i].end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1))-1) ^ ((1 << start)-1); - io_page_mask |= mask; - } - } - else if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += hose->pci_mem_offset; - dev->resource[i].end += hose->pci_mem_offset; - } - } + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (dev->resource[i].flags) + fixup_resource(&dev->resource[i], dev); } EXPORT_SYMBOL(pcibios_fixup_device_resources); -void __devinit pcibios_fixup_bus(struct pci_bus *bus) +static void __devinit do_bus_setup(struct pci_bus *bus) { - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_dev *dev = bus->self; - struct resource *res; - int i; + struct pci_dev *dev; - if (!dev) { - /* Root bus. */ + ppc_md.iommu_bus_setup(bus); - hose->bus = bus; - bus->resource[0] = res = &hose->io_resource; + list_for_each_entry(dev, &bus->devices, bus_list) + ppc_md.iommu_dev_setup(dev); - if (res->flags && request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request IO on " - "PCI domain %d\n", pci_domain_nr(bus)); + if (ppc_md.irq_bus_setup) + ppc_md.irq_bus_setup(bus); +} - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request MEM on " - "PCI domain %d\n", - pci_domain_nr(bus)); - } - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + if (dev && pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); } - ppc_md.iommu_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - ppc_md.iommu_dev_setup(dev); - - if (ppc_md.irq_bus_setup) - ppc_md.irq_bus_setup(bus); + do_bus_setup(bus); if (!pci_probe_only) return; - list_for_each_entry(dev, &bus->devices, bus_list) { + list_for_each_entry(dev, &bus->devices, bus_list) if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) pcibios_fixup_device_resources(dev, bus); - } } EXPORT_SYMBOL(pcibios_fixup_bus); @@ -983,3 +1233,62 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, } #endif /* CONFIG_PPC_MULTIPLATFORM */ + + +#define IOBASE_BRIDGE_NUMBER 0 +#define IOBASE_MEMORY 1 +#define IOBASE_IO 2 +#define IOBASE_ISA_IO 3 +#define IOBASE_ISA_MEM 4 + +long sys_pciconfig_iobase(long which, unsigned long in_bus, + unsigned long in_devfn) +{ + struct pci_controller* hose; + struct list_head *ln; + struct pci_bus *bus = NULL; + struct device_node *hose_node; + + /* Argh ! Please forgive me for that hack, but that's the + * simplest way to get existing XFree to not lockup on some + * G5 machines... So when something asks for bus 0 io base + * (bus 0 is HT root), we return the AGP one instead. + */ +#ifdef CONFIG_PPC_PMAC + if (systemcfg->platform == PLATFORM_POWERMAC && + machine_is_compatible("MacRISC4")) + if (in_bus == 0) + in_bus = 0xf0; +#endif /* CONFIG_PPC_PMAC */ + + /* That syscall isn't quite compatible with PCI domains, but it's + * used on pre-domains setup. We return the first match + */ + + for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { + bus = pci_bus_b(ln); + if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate)) + break; + bus = NULL; + } + if (bus == NULL || bus->sysdata == NULL) + return -ENODEV; + + hose_node = (struct device_node *)bus->sysdata; + hose = PCI_DN(hose_node)->phb; + + switch (which) { + case IOBASE_BRIDGE_NUMBER: + return (long)hose->first_busno; + case IOBASE_MEMORY: + return (long)hose->pci_mem_offset; + case IOBASE_IO: + return (long)hose->io_base_phys; + case IOBASE_ISA_IO: + return (long)isa_io_base; + case IOBASE_ISA_MEM: + return -EINVAL; + } + + return -EOPNOTSUPP; +} diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h index 26be78b13af..5eb2cc32056 100644 --- a/arch/ppc64/kernel/pci.h +++ b/arch/ppc64/kernel/pci.h @@ -34,7 +34,6 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, void pci_devs_phb_init(void); void pci_devs_phb_init_dynamic(struct pci_controller *phb); -struct device_node *fetch_dev_dn(struct pci_dev *dev); /* PCI address cache management routines */ void pci_addr_cache_insert_device(struct pci_dev *dev); diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c index ec345462afc..a86389d07d5 100644 --- a/arch/ppc64/kernel/pci_dn.c +++ b/arch/ppc64/kernel/pci_dn.c @@ -23,6 +23,8 @@ #include <linux/pci.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/slab.h> +#include <linux/bootmem.h> #include <asm/io.h> #include <asm/prom.h> @@ -40,16 +42,26 @@ 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; - - dn->phb = phb; + struct pci_dn *pdn; + + if (phb->is_dynamic) + pdn = kmalloc(sizeof(*pdn), GFP_KERNEL); + else + pdn = alloc_bootmem(sizeof(*pdn)); + if (pdn == NULL) + return NULL; + memset(pdn, 0, sizeof(*pdn)); + dn->data = pdn; + pdn->node = dn; + pdn->phb = phb; regs = (u32 *)get_property(dn, "reg", NULL); if (regs) { /* First register entry is addr (00BBSS00) */ - dn->busno = (regs[0] >> 16) & 0xff; - dn->devfn = (regs[0] >> 8) & 0xff; + pdn->busno = (regs[0] >> 16) & 0xff; + pdn->devfn = (regs[0] >> 8) & 0xff; } - dn->pci_ext_config_space = (type && *type == 1); + pdn->pci_ext_config_space = (type && *type == 1); return NULL; } @@ -112,10 +124,15 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb) { struct device_node * dn = (struct device_node *) phb->arch_data; + struct pci_dn *pdn; /* PHB nodes themselves must not match */ - dn->devfn = dn->busno = -1; - dn->phb = phb; + update_dn_pci_info(dn, phb); + pdn = dn->data; + if (pdn) { + pdn->devfn = pdn->busno = -1; + pdn->phb = phb; + } /* Update dn->phb ptrs for new phb and children devices */ traverse_pci_devices(dn, update_dn_pci_info, phb); @@ -123,14 +140,17 @@ void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb) /* * Traversal func that looks for a <busno,devfcn> value. - * If found, the device_node is returned (thus terminating the traversal). + * If found, the pci_dn is returned (thus terminating the traversal). */ static void *is_devfn_node(struct device_node *dn, void *data) { int busno = ((unsigned long)data >> 8) & 0xff; int devfn = ((unsigned long)data) & 0xff; + struct pci_dn *pci = dn->data; - return ((devfn == dn->devfn) && (busno == dn->busno)) ? dn : NULL; + if (pci && (devfn == pci->devfn) && (busno == pci->busno)) + return dn; + return NULL; } /* @@ -149,13 +169,10 @@ static void *is_devfn_node(struct device_node *dn, void *data) struct device_node *fetch_dev_dn(struct pci_dev *dev) { struct device_node *orig_dn = dev->sysdata; - struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */ - struct device_node *phb_dn; struct device_node *dn; unsigned long searchval = (dev->bus->number << 8) | dev->devfn; - phb_dn = phb->arch_data; - dn = traverse_pci_devices(phb_dn, is_devfn_node, (void *)searchval); + dn = traverse_pci_devices(orig_dn, is_devfn_node, (void *)searchval); if (dn) dev->sysdata = dn; return dn; @@ -165,11 +182,13 @@ EXPORT_SYMBOL(fetch_dev_dn); static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) { struct device_node *np = node; + struct pci_dn *pci; int err = NOTIFY_OK; switch (action) { case PSERIES_RECONFIG_ADD: - update_dn_pci_info(np, np->parent->phb); + pci = np->parent->data; + update_dn_pci_info(np, pci->phb); break; default: err = NOTIFY_DONE; diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c index ef0a62b916b..14647e09c9c 100644 --- a/arch/ppc64/kernel/pci_iommu.c +++ b/arch/ppc64/kernel/pci_iommu.c @@ -66,7 +66,7 @@ static inline struct iommu_table *devnode_table(struct device *dev) #endif /* CONFIG_PPC_ISERIES */ #ifdef CONFIG_PPC_MULTIPLATFORM - return PCI_GET_DN(pdev)->iommu_table; + return PCI_DN(PCI_GET_DN(pdev))->iommu_table; #endif /* CONFIG_PPC_MULTIPLATFORM */ } diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c index 98ed2bccab1..eb4e6c3f694 100644 --- a/arch/ppc64/kernel/pmac_feature.c +++ b/arch/ppc64/kernel/pmac_feature.c @@ -674,6 +674,7 @@ void __init pmac_check_ht_link(void) #if 0 /* Disabled for now */ u32 ufreq, freq, ucfg, cfg; struct device_node *pcix_node; + struct pci_dn *pdn; u8 px_bus, px_devfn; struct pci_controller *px_hose; @@ -687,9 +688,10 @@ void __init pmac_check_ht_link(void) printk("No PCI-X bridge found\n"); return; } - px_hose = pcix_node->phb; - px_bus = pcix_node->busno; - px_devfn = pcix_node->devfn; + pdn = pcix_node->data; + px_hose = pdn->phb; + px_bus = pdn->busno; + px_devfn = pdn->devfn; early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index 71fe911ad18..dc40a0cad0b 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -242,7 +242,7 @@ static int u3_ht_skip_device(struct pci_controller *hose, else busdn = hose->arch_data; for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn) + if (dn->data && PCI_DN(dn)->devfn == devfn) break; if (dn == NULL) return -1; @@ -388,7 +388,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; has_uninorth = 1; hose->ops = ¯isc_pci_ops; @@ -473,7 +473,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) continue; } cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); hose->mem_resources[cur].name = np->full_name; hose->mem_resources[cur].flags = IORESOURCE_MEM; @@ -603,24 +603,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -634,24 +634,24 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pmac_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pmac_process_bridge_OF_ranges(hose, dev, primary); + + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } @@ -746,9 +746,9 @@ void __init pmac_pci_init(void) */ if (u3_agp) { struct device_node *np = u3_agp->arch_data; - np->busno = 0xf0; + PCI_DN(np)->busno = 0xf0; for (np = np->child; np; np = np->sibling) - np->busno = 0xf0; + PCI_DN(np)->busno = 0xf0; } pmac_check_ht_link(); diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 8ff86a766cd..25755252067 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -274,16 +274,6 @@ static void __pmac pmac_halt(void) } #ifdef CONFIG_BOOTX_TEXT -static int dummy_getc_poll(void) -{ - return -1; -} - -static unsigned char dummy_getc(void) -{ - return 0; -} - static void btext_putc(unsigned char c) { btext_drawchar(c); @@ -342,16 +332,13 @@ static void __init pmac_init_early(void) sccdbg = 1; udbg_init_scc(NULL); } - - else { #ifdef CONFIG_BOOTX_TEXT + else { init_boot_display(); - ppc_md.udbg_putc = btext_putc; - ppc_md.udbg_getc = dummy_getc; - ppc_md.udbg_getc_poll = dummy_getc_poll; -#endif /* CONFIG_BOOTX_TEXT */ + udbg_putc = btext_putc; } +#endif /* CONFIG_BOOTX_TEXT */ /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; @@ -447,15 +434,23 @@ static int pmac_check_legacy_ioport(unsigned int baseport) static int __init pmac_declare_of_platform_devices(void) { - struct device_node *np; + struct device_node *np, *npp; - np = find_devices("u3"); - if (np) { - for (np = np->child; np != NULL; np = np->sibling) + npp = of_find_node_by_name(NULL, "u3"); + if (npp) { + for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c"); + of_platform_device_create(np, "u3-i2c", NULL); + of_node_put(np); break; } + } + of_node_put(npp); + } + npp = of_find_node_by_type(NULL, "smu"); + if (npp) { + of_platform_device_create(npp, "smu", NULL); + of_node_put(npp); } return 0; @@ -490,6 +485,18 @@ static int __init pmac_probe(int platform) return 1; } +static int pmac_probe_mode(struct pci_bus *bus) +{ + struct device_node *node = bus->sysdata; + + /* We need to use normal PCI probing for the AGP bus, + since the device for the AGP bridge isn't in the tree. */ + if (bus->self == NULL && device_is_compatible(node, "u3-agp")) + return PCI_PROBE_NORMAL; + + return PCI_PROBE_DEVTREE; +} + struct machdep_calls __initdata pmac_md = { #ifdef CONFIG_HOTPLUG_CPU .cpu_die = generic_mach_cpu_die, @@ -501,6 +508,7 @@ struct machdep_calls __initdata pmac_md = { .init_IRQ = pmac_init_IRQ, .get_irq = mpic_get_irq, .pcibios_fixup = pmac_pcibios_fixup, + .pci_probe_mode = pmac_probe_mode, .restart = pmac_restart, .power_off = pmac_power_off, .halt = pmac_halt, diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index 3059edb09cc..41bbb8c5969 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -84,7 +84,7 @@ void __pmac pmac_get_rtc_time(struct rtc_time *tm) #ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: - smu_get_rtc_time(tm); + smu_get_rtc_time(tm, 1); break; #endif /* CONFIG_PMAC_SMU */ default: @@ -128,7 +128,7 @@ int __pmac pmac_set_rtc_time(struct rtc_time *tm) #ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: - return smu_set_rtc_time(tm); + return smu_set_rtc_time(tm, 1); #endif /* CONFIG_PMAC_SMU */ default: return -ENODEV; diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c index cdfec7438d0..63d9481c3ec 100644 --- a/arch/ppc64/kernel/pmc.c +++ b/arch/ppc64/kernel/pmc.c @@ -26,7 +26,7 @@ static void dummy_perf(struct pt_regs *regs) mtspr(SPRN_MMCR0, mmcr0); } -static spinlock_t pmc_owner_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pmc_owner_lock); static void *pmc_owner_caller; /* mostly for debugging */ perf_irq_t perf_irq = dummy_perf; diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 7a7e027653a..887005358eb 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -54,6 +54,7 @@ #include <asm/sections.h> #include <asm/tlbflush.h> #include <asm/time.h> +#include <asm/plpar_wrappers.h> #ifndef CONFIG_SMP struct task_struct *last_task_used_math = NULL; @@ -163,7 +164,30 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) #endif /* CONFIG_ALTIVEC */ +static void set_dabr_spr(unsigned long val) +{ + mtspr(SPRN_DABR, val); +} + +int set_dabr(unsigned long dabr) +{ + int ret = 0; + + if (firmware_has_feature(FW_FEATURE_XDABR)) { + /* We want to catch accesses from kernel and userspace */ + unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; + ret = plpar_set_xdabr(dabr, flags); + } else if (firmware_has_feature(FW_FEATURE_DABR)) { + ret = plpar_set_dabr(dabr); + } else { + set_dabr_spr(dabr); + } + + return ret; +} + DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); +static DEFINE_PER_CPU(unsigned long, current_dabr); struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) @@ -198,6 +222,11 @@ struct task_struct *__switch_to(struct task_struct *prev, new->thread.regs->msr |= MSR_VEC; #endif /* CONFIG_ALTIVEC */ + if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { + set_dabr(new->thread.dabr); + __get_cpu_var(current_dabr) = new->thread.dabr; + } + flush_tlb_pending(); new_thread = &new->thread; @@ -334,6 +363,11 @@ void flush_thread(void) last_task_used_altivec = NULL; #endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_SMP */ + + if (current->thread.dabr) { + current->thread.dabr = 0; + set_dabr(0); + } } void diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index b2184882679..7035deb6de9 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -22,7 +22,6 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> -#include <linux/version.h> #include <linux/threads.h> #include <linux/spinlock.h> #include <linux/types.h> @@ -1734,6 +1733,7 @@ static void of_node_release(struct kref *kref) kfree(node->intrs); kfree(node->addrs); kfree(node->full_name); + kfree(node->data); kfree(node); } diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 122283a1d39..f252670874a 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -22,7 +22,6 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> -#include <linux/version.h> #include <linux/threads.h> #include <linux/spinlock.h> #include <linux/types.h> @@ -1712,6 +1711,7 @@ static void __init flatten_device_tree(void) unsigned long offset = reloc_offset(); unsigned long mem_start, mem_end, room; struct boot_param_header *hdr; + struct prom_t *_prom = PTRRELOC(&prom); char *namep; u64 *rsvmap; @@ -1766,6 +1766,7 @@ static void __init flatten_device_tree(void) RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); /* Finish header */ + hdr->boot_cpuid_phys = _prom->cpu; hdr->magic = OF_DT_HEADER; hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); @@ -1855,7 +1856,6 @@ static void __init prom_find_boot_cpu(void) cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0); prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); _prom->cpu = getprop_rval; diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 2993f108d96..b1c044ca575 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -206,6 +207,20 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, + (unsigned long __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; @@ -274,6 +289,20 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 16436426c7e..fb8c22d6084 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -337,6 +338,19 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, (u32 __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; @@ -405,9 +419,23 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned int __user *) data); + break; + +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif default: ret = ptrace_request(child, request, addr, data); diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 3c00f7bfc1b..41b97dc9cc0 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c @@ -59,8 +59,6 @@ char mce_data_buf[RTAS_ERROR_LOG_MAX] /* This is true if we are using the firmware NMI handler (typically LPAR) */ extern int fwnmi_active; -extern void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); - static int ras_get_sensor_state_token; static int ras_check_exception_token; diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 1dccadaddd1..4a9719b48ab 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -48,7 +48,7 @@ static int write_pci_config; static int ibm_read_pci_config; static int ibm_write_pci_config; -static int config_access_valid(struct device_node *dn, int where) +static int config_access_valid(struct pci_dn *dn, int where) { if (where < 256) return 1; @@ -78,15 +78,17 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va int returnval = -1; unsigned long buid, addr; int ret; + struct pci_dn *pdn; - if (!dn) + if (!dn || !dn->data) return PCIBIOS_DEVICE_NOT_FOUND; - if (!config_access_valid(dn, where)) + pdn = dn->data; + if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; - addr = ((where & 0xf00) << 20) | (dn->busno << 16) | - (dn->devfn << 8) | (where & 0xff); - buid = dn->phb->buid; + addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | + (pdn->devfn << 8) | (where & 0xff); + buid = pdn->phb->buid; if (buid) { ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, size); @@ -98,8 +100,8 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va if (ret) return PCIBIOS_DEVICE_NOT_FOUND; - if (returnval == EEH_IO_ERROR_VALUE(size) - && eeh_dn_check_failure (dn, NULL)) + if (returnval == EEH_IO_ERROR_VALUE(size) && + eeh_dn_check_failure (dn, NULL)) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; @@ -118,24 +120,28 @@ static int rtas_pci_read_config(struct pci_bus *bus, /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn && of_device_available(dn)) + if (dn->data && PCI_DN(dn)->devfn == devfn + && of_device_available(dn)) return rtas_read_config(dn, where, size, val); + return PCIBIOS_DEVICE_NOT_FOUND; } -static int rtas_write_config(struct device_node *dn, int where, int size, u32 val) +int rtas_write_config(struct device_node *dn, int where, int size, u32 val) { unsigned long buid, addr; int ret; + struct pci_dn *pdn; - if (!dn) + if (!dn || !dn->data) return PCIBIOS_DEVICE_NOT_FOUND; - if (!config_access_valid(dn, where)) + pdn = dn->data; + if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; - addr = ((where & 0xf00) << 20) | (dn->busno << 16) | - (dn->devfn << 8) | (where & 0xff); - buid = dn->phb->buid; + addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | + (pdn->devfn << 8) | (where & 0xff); + buid = pdn->phb->buid; if (buid) { ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val); } else { @@ -161,7 +167,8 @@ static int rtas_pci_write_config(struct pci_bus *bus, /* Search only direct children of the bus */ for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->devfn == devfn && of_device_available(dn)) + if (dn->data && PCI_DN(dn)->devfn == devfn + && of_device_available(dn)) return rtas_write_config(dn, where, size, val); return PCIBIOS_DEVICE_NOT_FOUND; } diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c index b0c3b829fe4..e26b0420b6d 100644 --- a/arch/ppc64/kernel/rtasd.c +++ b/arch/ppc64/kernel/rtasd.c @@ -19,6 +19,7 @@ #include <linux/vmalloc.h> #include <linux/spinlock.h> #include <linux/cpu.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -412,8 +413,7 @@ static void do_event_scan_all_cpus(long delay) /* Drop hotplug lock, and sleep for the specified delay */ unlock_cpu_hotplug(); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(delay); + msleep_interruptible(delay); lock_cpu_hotplug(); cpu = next_cpu(cpu, cpu_online_map); @@ -442,7 +442,7 @@ static int rtasd(void *unused) printk(KERN_INFO "RTAS daemon started\n"); - DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2); + DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); @@ -459,7 +459,7 @@ static int rtasd(void *unused) } /* First pass. */ - do_event_scan_all_cpus(HZ); + do_event_scan_all_cpus(1000); if (surveillance_timeout != -1) { DEBUG("enabling surveillance\n"); @@ -471,7 +471,7 @@ static int rtasd(void *unused) * machines have problems if we call event-scan too * quickly. */ for (;;) - do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2); + do_event_scan_all_cpus(30000/rtas_event_scan_rate); error: /* Should delete proc entries */ diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index d729fefa0df..6ff52bc6132 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/bcd.h> #include <linux/interrupt.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -351,8 +352,7 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm) return; /* delay not allowed */ } wait_time = rtas_extended_busy_delay_time(error); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(wait_time); + msleep_interruptible(wait_time); error = RTAS_CLOCK_BUSY; } } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb)); @@ -386,8 +386,7 @@ int rtas_set_rtc_time(struct rtc_time *tm) if (in_interrupt()) return 1; /* probably decrementer */ wait_time = rtas_extended_busy_delay_time(error); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(wait_time); + msleep_interruptible(wait_time); error = RTAS_CLOCK_BUSY; } } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb)); diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c index 4d70736619c..215bf890030 100644 --- a/arch/ppc64/kernel/scanlog.c +++ b/arch/ppc64/kernel/scanlog.c @@ -25,6 +25,7 @@ #include <linux/errno.h> #include <linux/proc_fs.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/rtas.h> #include <asm/prom.h> @@ -77,7 +78,7 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, return -EFAULT; for (;;) { - wait_time = HZ/2; /* default wait if no data */ + wait_time = 500; /* default wait if no data */ spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, @@ -107,24 +108,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, break; default: if (status > 9900 && status <= 9905) { - /* No data. RTAS is hinting at a delay required - * between 1-100000 milliseconds - */ - int ms = 1; - for (; status > 9900; status--) - ms = ms * 10; - /* Use microseconds for reasonable accuracy */ - ms *= 1000; - wait_time = ms / (1000000/HZ); /* round down is fine */ - /* Fall through to sleep */ + wait_time = rtas_extended_busy_delay_time(status); } else { printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); return -EIO; } } /* Apparently no data yet. Wait and try again. */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(wait_time); + msleep_interruptible(wait_time); } /*NOTREACHED*/ } diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index ee3b20de2e7..5ac48bd6489 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -25,7 +25,7 @@ #include <linux/seq_file.h> #include <linux/ioport.h> #include <linux/console.h> -#include <linux/version.h> +#include <linux/utsname.h> #include <linux/tty.h> #include <linux/root_dev.h> #include <linux/notifier.h> @@ -89,7 +89,7 @@ extern void udbg_init_maple_realmode(void); #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() #define EARLY_DEBUG_INIT() \ - do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) + do { udbg_putc = call_rtas_display_status_delay; } while(0) #endif /* extern void *stab; */ @@ -108,7 +108,6 @@ int boot_cpuid = 0; int boot_cpuid_phys = 0; dev_t boot_dev; u64 ppc64_pft_size; -u64 ppc64_debug_switch; struct ppc64_caches ppc64_caches; EXPORT_SYMBOL_GPL(ppc64_caches); @@ -154,34 +153,6 @@ struct screen_info screen_info = { .orig_video_points = 16 }; -/* - * Initialize the PPCDBG state. Called before relocation has been enabled. - */ -void __init ppcdbg_initialize(void) -{ - ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ - /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; -} - -/* - * Early boot console based on udbg - */ -static struct console udbg_console = { - .name = "udbg", - .write = udbg_console_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; -static int early_console_initialized; - -void __init disable_early_printk(void) -{ - if (!early_console_initialized) - return; - unregister_console(&udbg_console); - early_console_initialized = 0; -} - #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) static int smt_enabled_cmdline; @@ -425,12 +396,6 @@ void __init early_setup(unsigned long dt_ptr) } ppc_md = **mach; - /* our udbg callbacks got overriden by the above, let's put them - * back in. Ultimately, I want those things to be split from the - * main ppc_md - */ - EARLY_DEBUG_INIT(); - DBG("Found, Initializing memory management...\n"); /* @@ -636,8 +601,7 @@ void __init setup_system(void) /* * Register early console */ - early_console_initialized = 1; - register_console(&udbg_console); + register_early_udbg_console(); /* Save unparsed command line copy for /proc/cmdline */ strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); @@ -657,7 +621,7 @@ void __init setup_system(void) smp_release_cpus(); #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ - printk("Starting Linux PPC64 %s\n", UTS_RELEASE); + printk("Starting Linux PPC64 %s\n", system_utsname.version); printk("-----------------------------------------------------\n"); printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); @@ -1100,8 +1064,6 @@ void __init setup_arch(char **cmdline_p) #define PPC64_LINUX_FUNCTION 0x0f000000 #define PPC64_IPL_MESSAGE 0xc0000000 #define PPC64_TERM_MESSAGE 0xb0000000 -#define PPC64_ATTN_MESSAGE 0xa0000000 -#define PPC64_DUMP_MESSAGE 0xd0000000 static void ppc64_do_msg(unsigned int src, const char *msg) { @@ -1129,20 +1091,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -/* Print something that needs attention (device error, etc) */ -void ppc64_attention_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); - printk("[attention]%04x %s\n", src, msg); -} - -/* Print a dump progress message. */ -void ppc64_dump_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); - printk("[dump]%04x %s\n", src, msg); -} - /* This should only be called on processor 0 during calibrate decr */ void __init setup_default_decr(void) { @@ -1319,7 +1267,7 @@ void __init generic_find_legacy_serial_ports(u64 *physport, static struct platform_device serial_device = { .name = "serial8250", - .id = 0, + .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_ports, }, diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 49a79a55c32..347112cca3c 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -550,6 +550,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* Whee! Actually deliver the signal. */ if (TRAP(regs) == 0x0C00) syscall_restart(regs, &ka); + + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + return handle_signal(signr, &ka, &info, oldset, regs); } diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 46f4d6cc7fc..a8b7a5a56bb 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -970,6 +970,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) newsp = regs->gpr[1]; newsp &= ~0xfUL; + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + /* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags & SA_SIGINFO) ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 206619080e6..e93c1345891 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -708,62 +708,9 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu compat_ptr(ubuf)); } -#define IOBASE_BRIDGE_NUMBER 0 -#define IOBASE_MEMORY 1 -#define IOBASE_IO 2 -#define IOBASE_ISA_IO 3 -#define IOBASE_ISA_MEM 4 - asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) { -#ifdef CONFIG_PCI - struct pci_controller* hose; - struct list_head *ln; - struct pci_bus *bus = NULL; - struct device_node *hose_node; - - /* Argh ! Please forgive me for that hack, but that's the - * simplest way to get existing XFree to not lockup on some - * G5 machines... So when something asks for bus 0 io base - * (bus 0 is HT root), we return the AGP one instead. - */ -#ifdef CONFIG_PPC_PMAC - if (systemcfg->platform == PLATFORM_POWERMAC && - machine_is_compatible("MacRISC4")) - if (in_bus == 0) - in_bus = 0xf0; -#endif /* CONFIG_PPC_PMAC */ - - /* That syscall isn't quite compatible with PCI domains, but it's - * used on pre-domains setup. We return the first match - */ - - for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - bus = pci_bus_b(ln); - if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate)) - break; - bus = NULL; - } - if (bus == NULL || bus->sysdata == NULL) - return -ENODEV; - - hose_node = (struct device_node *)bus->sysdata; - hose = hose_node->phb; - - switch (which) { - case IOBASE_BRIDGE_NUMBER: - return (long)hose->first_busno; - case IOBASE_MEMORY: - return (long)hose->pci_mem_offset; - case IOBASE_IO: - return (long)hose->io_base_phys; - case IOBASE_ISA_IO: - return (long)isa_io_base; - case IOBASE_ISA_MEM: - return -EINVAL; - } -#endif /* CONFIG_PCI */ - return -EOPNOTSUPP; + return sys_pciconfig_iobase(which, in_bus, in_devfn); } @@ -867,37 +814,6 @@ off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin) return sys_lseek(fd, (int)offset, origin); } -/* - * This is just a version for 32-bit applications which does - * not force O_LARGEFILE on. - */ -asmlinkage long sys32_open(const char __user * filename, int flags, int mode) -{ - char * tmp; - int fd, error; - - tmp = getname(filename); - fd = PTR_ERR(tmp); - if (!IS_ERR(tmp)) { - fd = get_unused_fd(); - if (fd >= 0) { - struct file * f = filp_open(tmp, flags, mode); - error = PTR_ERR(f); - if (IS_ERR(f)) - goto out_error; - fd_install(fd, f); - } -out: - putname(tmp); - } - return fd; - -out_error: - put_unused_fd(fd); - fd = error; - goto out; -} - /* Note: it is necessary to treat bufsiz as an unsigned int, * with the corresponding cast to a signed int to insure that the * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) diff --git a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c index a8cbb202b8c..05f16633bd2 100644 --- a/arch/ppc64/kernel/syscalls.c +++ b/arch/ppc64/kernel/syscalls.c @@ -46,10 +46,6 @@ extern unsigned long wall_jiffies; -void -check_bugs(void) -{ -} /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index f311ee7c007..6654b350979 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -215,18 +215,23 @@ static void register_cpu_online(unsigned int cpu) if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_create_file(s, &attr_mmcra); - sysdev_create_file(s, &attr_pmc1); - sysdev_create_file(s, &attr_pmc2); - sysdev_create_file(s, &attr_pmc3); - sysdev_create_file(s, &attr_pmc4); - sysdev_create_file(s, &attr_pmc5); - sysdev_create_file(s, &attr_pmc6); - - if (cpu_has_feature(CPU_FTR_PMC8)) { + if (cur_cpu_spec->num_pmcs >= 1) + sysdev_create_file(s, &attr_pmc1); + if (cur_cpu_spec->num_pmcs >= 2) + sysdev_create_file(s, &attr_pmc2); + if (cur_cpu_spec->num_pmcs >= 3) + sysdev_create_file(s, &attr_pmc3); + if (cur_cpu_spec->num_pmcs >= 4) + sysdev_create_file(s, &attr_pmc4); + if (cur_cpu_spec->num_pmcs >= 5) + sysdev_create_file(s, &attr_pmc5); + if (cur_cpu_spec->num_pmcs >= 6) + sysdev_create_file(s, &attr_pmc6); + if (cur_cpu_spec->num_pmcs >= 7) sysdev_create_file(s, &attr_pmc7); + if (cur_cpu_spec->num_pmcs >= 8) sysdev_create_file(s, &attr_pmc8); - } - + if (cpu_has_feature(CPU_FTR_SMT)) sysdev_create_file(s, &attr_purr); } @@ -252,17 +257,22 @@ static void unregister_cpu_online(unsigned int cpu) if (cpu_has_feature(CPU_FTR_MMCRA)) sysdev_remove_file(s, &attr_mmcra); - sysdev_remove_file(s, &attr_pmc1); - sysdev_remove_file(s, &attr_pmc2); - sysdev_remove_file(s, &attr_pmc3); - sysdev_remove_file(s, &attr_pmc4); - sysdev_remove_file(s, &attr_pmc5); - sysdev_remove_file(s, &attr_pmc6); - - if (cpu_has_feature(CPU_FTR_PMC8)) { + if (cur_cpu_spec->num_pmcs >= 1) + sysdev_remove_file(s, &attr_pmc1); + if (cur_cpu_spec->num_pmcs >= 2) + sysdev_remove_file(s, &attr_pmc2); + if (cur_cpu_spec->num_pmcs >= 3) + sysdev_remove_file(s, &attr_pmc3); + if (cur_cpu_spec->num_pmcs >= 4) + sysdev_remove_file(s, &attr_pmc4); + if (cur_cpu_spec->num_pmcs >= 5) + sysdev_remove_file(s, &attr_pmc5); + if (cur_cpu_spec->num_pmcs >= 6) + sysdev_remove_file(s, &attr_pmc6); + if (cur_cpu_spec->num_pmcs >= 7) sysdev_remove_file(s, &attr_pmc7); + if (cur_cpu_spec->num_pmcs >= 8) sysdev_remove_file(s, &attr_pmc8); - } if (cpu_has_feature(CPU_FTR_SMT)) sysdev_remove_file(s, &attr_purr); diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 1696e1b05bb..9939c206afa 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -51,7 +51,6 @@ #include <linux/cpu.h> #include <linux/security.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/nvram.h> @@ -129,7 +128,7 @@ static __inline__ void timer_check_rtc(void) * We should have an rtc call that only sets the minutes and * seconds like on Intel to avoid problems with non UTC clocks. */ - if ( (time_status & STA_UNSYNC) == 0 && + if (ntp_synced() && xtime.tv_sec - last_rtc_update >= 659 && abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ && jiffies - wall_jiffies == 1) { @@ -436,10 +435,7 @@ int do_settimeofday(struct timespec *tv) */ last_rtc_update = new_sec - 658; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; + ntp_clear(); delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp), do_gtod.varp->tb_to_xs ); diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index a8d5e83ee89..7467ae508e6 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c @@ -30,6 +30,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/kprobes.h> #include <asm/kdebug.h> #include <asm/pgtable.h> @@ -220,7 +221,7 @@ void instruction_breakpoint_exception(struct pt_regs *regs) _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); } -void single_step_exception(struct pt_regs *regs) +void __kprobes single_step_exception(struct pt_regs *regs) { regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ @@ -398,7 +399,7 @@ check_bug_trap(struct pt_regs *regs) return 0; } -void program_check_exception(struct pt_regs *regs) +void __kprobes program_check_exception(struct pt_regs *regs) { if (debugger_fault_handler(regs)) return; diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c index b6e3bca4102..41ea09cb9ac 100644 --- a/arch/ppc64/kernel/u3_iommu.c +++ b/arch/ppc64/kernel/u3_iommu.c @@ -276,7 +276,7 @@ static void iommu_dev_setup_u3(struct pci_dev *dev) dn = pci_device_to_OF_node(dev); if (dn) - dn->iommu_table = &iommu_table_u3; + PCI_DN(dn)->iommu_table = &iommu_table_u3; } static void iommu_bus_setup_u3(struct pci_bus *bus) @@ -291,7 +291,7 @@ static void iommu_bus_setup_u3(struct pci_bus *bus) dn = pci_bus_to_OF_node(bus); if (dn) - dn->iommu_table = &iommu_table_u3; + PCI_DN(dn)->iommu_table = &iommu_table_u3; } static void iommu_dev_setup_null(struct pci_dev *dev) { } diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c index c0da45540f0..d49c3613c8e 100644 --- a/arch/ppc64/kernel/udbg.c +++ b/arch/ppc64/kernel/udbg.c @@ -1,5 +1,5 @@ /* - * NS16550 Serial Port (uart) debugging stuff. + * polling mode stateless debugging stuff, originally for NS16550 Serial Ports * * c 2001 PPC 64 Team, IBM Corp * @@ -13,249 +13,24 @@ #define WANT_PPCDBG_TAB /* Only defined here */ #include <linux/config.h> #include <linux/types.h> +#include <linux/sched.h> +#include <linux/console.h> #include <asm/ppcdebug.h> #include <asm/processor.h> -#include <asm/uaccess.h> -#include <asm/machdep.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pmac_feature.h> -extern u8 real_readb(volatile u8 __iomem *addr); -extern void real_writeb(u8 data, volatile u8 __iomem *addr); - -struct NS16550 { - /* this struct must be packed */ - unsigned char rbr; /* 0 */ - unsigned char ier; /* 1 */ - unsigned char fcr; /* 2 */ - unsigned char lcr; /* 3 */ - unsigned char mcr; /* 4 */ - unsigned char lsr; /* 5 */ - unsigned char msr; /* 6 */ - unsigned char scr; /* 7 */ -}; - -#define thr rbr -#define iir fcr -#define dll rbr -#define dlm ier -#define dlab lcr - -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit holding register empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -static volatile struct NS16550 __iomem *udbg_comport; - -void udbg_init_uart(void __iomem *comport, unsigned int speed) -{ - u16 dll = speed ? (115200 / speed) : 12; - - if (comport) { - udbg_comport = (struct NS16550 __iomem *)comport; - out_8(&udbg_comport->lcr, 0x00); - out_8(&udbg_comport->ier, 0xff); - out_8(&udbg_comport->ier, 0x00); - out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ - out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, - 3 = 38400, 12 = 9600 baud */ - out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero - for fast rates; */ - out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ - out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ - out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ - } -} - -#ifdef CONFIG_PPC_PMAC - -#define SCC_TXRDY 4 -#define SCC_RXRDY 1 - -static volatile u8 __iomem *sccc; -static volatile u8 __iomem *sccd; - -static unsigned char scc_inittab[] = { - 13, 0, /* set baud rate divisor */ - 12, 0, - 14, 1, /* baud rate gen enable, src=rtxc */ - 11, 0x50, /* clocks = br gen */ - 5, 0xea, /* tx 8 bits, assert DTR & RTS */ - 4, 0x46, /* x16 clock, 1 stop */ - 3, 0xc1, /* rx enable, 8 bits */ -}; - -void udbg_init_scc(struct device_node *np) -{ - u32 *reg; - unsigned long addr; - int i, x; - - if (np == NULL) - np = of_find_node_by_name(NULL, "escc"); - if (np == NULL || np->parent == NULL) - return; - - udbg_printf("found SCC...\n"); - /* Get address within mac-io ASIC */ - reg = (u32 *)get_property(np, "reg", NULL); - if (reg == NULL) - return; - addr = reg[0]; - udbg_printf("local addr: %lx\n", addr); - /* Get address of mac-io PCI itself */ - reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); - if (reg == NULL) - return; - addr += reg[2]; - udbg_printf("final addr: %lx\n", addr); - - /* Setup for 57600 8N1 */ - addr += 0x20; - sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; - sccc += addr & ~PAGE_MASK; - sccd = sccc + 0x10; - - udbg_printf("ioremap result sccc: %p\n", sccc); - mb(); - - for (i = 20000; i != 0; --i) - x = in_8(sccc); - out_8(sccc, 0x09); /* reset A or B side */ - out_8(sccc, 0xc0); - for (i = 0; i < sizeof(scc_inittab); ++i) - out_8(sccc, scc_inittab[i]); - - ppc_md.udbg_putc = udbg_putc; - ppc_md.udbg_getc = udbg_getc; - ppc_md.udbg_getc_poll = udbg_getc_poll; - - udbg_puts("Hello World !\n"); -} - -#endif /* CONFIG_PPC_PMAC */ - -#ifdef CONFIG_PPC_PMAC -static void udbg_real_putc(unsigned char c) -{ - while ((real_readb(sccc) & SCC_TXRDY) == 0) - ; - real_writeb(c, sccd); - if (c == '\n') - udbg_real_putc('\r'); -} - -void udbg_init_pmac_realmode(void) -{ - sccc = (volatile u8 __iomem *)0x80013020ul; - sccd = (volatile u8 __iomem *)0x80013030ul; - - ppc_md.udbg_putc = udbg_real_putc; - ppc_md.udbg_getc = NULL; - ppc_md.udbg_getc_poll = NULL; -} -#endif /* CONFIG_PPC_PMAC */ - -#ifdef CONFIG_PPC_MAPLE -void udbg_maple_real_putc(unsigned char c) -{ - if (udbg_comport) { - while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - real_writeb(c, &udbg_comport->thr); eieio(); - if (c == '\n') { - /* Also put a CR. This is for convenience. */ - while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - real_writeb('\r', &udbg_comport->thr); eieio(); - } - } -} - -void udbg_init_maple_realmode(void) -{ - udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; - - ppc_md.udbg_putc = udbg_maple_real_putc; - ppc_md.udbg_getc = NULL; - ppc_md.udbg_getc_poll = NULL; -} -#endif /* CONFIG_PPC_MAPLE */ - -void udbg_putc(unsigned char c) -{ - if (udbg_comport) { - while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - out_8(&udbg_comport->thr, c); - if (c == '\n') { - /* Also put a CR. This is for convenience. */ - while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - out_8(&udbg_comport->thr, '\r'); - } - } -#ifdef CONFIG_PPC_PMAC - else if (sccc) { - while ((in_8(sccc) & SCC_TXRDY) == 0) - ; - out_8(sccd, c); - if (c == '\n') - udbg_putc('\r'); - } -#endif /* CONFIG_PPC_PMAC */ -} - -int udbg_getc_poll(void) -{ - if (udbg_comport) { - if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) - return in_8(&udbg_comport->rbr); - else - return -1; - } -#ifdef CONFIG_PPC_PMAC - else if (sccc) { - if ((in_8(sccc) & SCC_RXRDY) != 0) - return in_8(sccd); - else - return -1; - } -#endif /* CONFIG_PPC_PMAC */ - return -1; -} - -unsigned char udbg_getc(void) -{ - if (udbg_comport) { - while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) - /* wait for char */; - return in_8(&udbg_comport->rbr); - } -#ifdef CONFIG_PPC_PMAC - else if (sccc) { - while ((in_8(sccc) & SCC_RXRDY) == 0) - ; - return in_8(sccd); - } -#endif /* CONFIG_PPC_PMAC */ - return 0; -} +void (*udbg_putc)(unsigned char c); +unsigned char (*udbg_getc)(void); +int (*udbg_getc_poll)(void); +/* udbg library, used by xmon et al */ void udbg_puts(const char *s) { - if (ppc_md.udbg_putc) { + if (udbg_putc) { char c; if (s && *s != '\0') { while ((c = *s++) != '\0') - ppc_md.udbg_putc(c); + udbg_putc(c); } } #if 0 @@ -270,12 +45,12 @@ int udbg_write(const char *s, int n) int remain = n; char c; - if (!ppc_md.udbg_putc) + if (!udbg_putc) return 0; if (s && *s != '\0') { while (((c = *s++) != '\0') && (remain-- > 0)) { - ppc_md.udbg_putc(c); + udbg_putc(c); } } @@ -287,12 +62,12 @@ int udbg_read(char *buf, int buflen) char c, *p = buf; int i; - if (!ppc_md.udbg_getc) + if (!udbg_getc) return 0; for (i = 0; i < buflen; ++i) { do { - c = ppc_md.udbg_getc(); + c = udbg_getc(); } while (c == 0x11 || c == 0x13); if (c == 0) break; @@ -302,11 +77,6 @@ int udbg_read(char *buf, int buflen) return i; } -void udbg_console_write(struct console *con, const char *s, unsigned int n) -{ - udbg_write(s, n); -} - #define UDBG_BUFSIZE 256 void udbg_printf(const char *fmt, ...) { @@ -319,6 +89,10 @@ void udbg_printf(const char *fmt, ...) va_end(args); } +/* PPCDBG stuff */ + +u64 ppc64_debug_switch; + /* Special print used by PPCDBG() macro */ void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...) { @@ -358,3 +132,49 @@ unsigned long udbg_ifdebug(unsigned long flags) { return (flags & ppc64_debug_switch); } + +/* + * Initialize the PPCDBG state. Called before relocation has been enabled. + */ +void __init ppcdbg_initialize(void) +{ + ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ + /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; +} + +/* + * Early boot console based on udbg + */ +static void udbg_console_write(struct console *con, const char *s, + unsigned int n) +{ + udbg_write(s, n); +} + +static struct console udbg_console = { + .name = "udbg", + .write = udbg_console_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int early_console_initialized; + +void __init disable_early_printk(void) +{ + if (!early_console_initialized) + return; + unregister_console(&udbg_console); + early_console_initialized = 0; +} + +/* called by setup_system */ +void register_early_udbg_console(void) +{ + early_console_initialized = 1; + register_console(&udbg_console); +} + +#if 0 /* if you want to use this as a regular output console */ +console_initcall(register_udbg_console); +#endif diff --git a/arch/ppc64/kernel/udbg_16550.c b/arch/ppc64/kernel/udbg_16550.c new file mode 100644 index 00000000000..9313574ab93 --- /dev/null +++ b/arch/ppc64/kernel/udbg_16550.c @@ -0,0 +1,123 @@ +/* + * udbg for for NS16550 compatable serial ports + * + * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp + * + * 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/config.h> +#include <linux/types.h> +#include <asm/udbg.h> +#include <asm/io.h> + +extern u8 real_readb(volatile u8 __iomem *addr); +extern void real_writeb(u8 data, volatile u8 __iomem *addr); + +struct NS16550 { + /* this struct must be packed */ + unsigned char rbr; /* 0 */ + unsigned char ier; /* 1 */ + unsigned char fcr; /* 2 */ + unsigned char lcr; /* 3 */ + unsigned char mcr; /* 4 */ + unsigned char lsr; /* 5 */ + unsigned char msr; /* 6 */ + unsigned char scr; /* 7 */ +}; + +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier +#define dlab lcr + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +static volatile struct NS16550 __iomem *udbg_comport; + +static void udbg_550_putc(unsigned char c) +{ + if (udbg_comport) { + while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + out_8(&udbg_comport->thr, c); + if (c == '\n') + udbg_550_putc('\r'); + } +} + +static int udbg_550_getc_poll(void) +{ + if (udbg_comport) { + if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) + return in_8(&udbg_comport->rbr); + else + return -1; + } + return -1; +} + +static unsigned char udbg_550_getc(void) +{ + if (udbg_comport) { + while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) + /* wait for char */; + return in_8(&udbg_comport->rbr); + } + return 0; +} + +void udbg_init_uart(void __iomem *comport, unsigned int speed) +{ + u16 dll = speed ? (115200 / speed) : 12; + + if (comport) { + udbg_comport = (struct NS16550 __iomem *)comport; + out_8(&udbg_comport->lcr, 0x00); + out_8(&udbg_comport->ier, 0xff); + out_8(&udbg_comport->ier, 0x00); + out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ + out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, + 3 = 38400, 12 = 9600 baud */ + out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero + for fast rates; */ + out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ + out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ + out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ + udbg_putc = udbg_550_putc; + udbg_getc = udbg_550_getc; + udbg_getc_poll = udbg_550_getc_poll; + } +} + +#ifdef CONFIG_PPC_MAPLE +void udbg_maple_real_putc(unsigned char c) +{ + if (udbg_comport) { + while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + real_writeb(c, &udbg_comport->thr); eieio(); + if (c == '\n') + udbg_maple_real_putc('\r'); + } +} + +void udbg_init_maple_realmode(void) +{ + udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; + + udbg_putc = udbg_maple_real_putc; + udbg_getc = NULL; + udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC_MAPLE */ diff --git a/arch/ppc64/kernel/udbg_scc.c b/arch/ppc64/kernel/udbg_scc.c new file mode 100644 index 00000000000..c47fd6c6353 --- /dev/null +++ b/arch/ppc64/kernel/udbg_scc.c @@ -0,0 +1,136 @@ +/* + * udbg for for zilog scc ports as found on Apple PowerMacs + * + * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp + * + * 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/config.h> +#include <linux/types.h> +#include <asm/udbg.h> +#include <asm/processor.h> +#include <asm/naca.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pmac_feature.h> + +extern u8 real_readb(volatile u8 __iomem *addr); +extern void real_writeb(u8 data, volatile u8 __iomem *addr); + +#define SCC_TXRDY 4 +#define SCC_RXRDY 1 + +static volatile u8 __iomem *sccc; +static volatile u8 __iomem *sccd; + +static void udbg_scc_putc(unsigned char c) +{ + if (sccc) { + while ((in_8(sccc) & SCC_TXRDY) == 0) + ; + out_8(sccd, c); + if (c == '\n') + udbg_scc_putc('\r'); + } +} + +static int udbg_scc_getc_poll(void) +{ + if (sccc) { + if ((in_8(sccc) & SCC_RXRDY) != 0) + return in_8(sccd); + else + return -1; + } + return -1; +} + +static unsigned char udbg_scc_getc(void) +{ + if (sccc) { + while ((in_8(sccc) & SCC_RXRDY) == 0) + ; + return in_8(sccd); + } + return 0; +} + +static unsigned char scc_inittab[] = { + 13, 0, /* set baud rate divisor */ + 12, 0, + 14, 1, /* baud rate gen enable, src=rtxc */ + 11, 0x50, /* clocks = br gen */ + 5, 0xea, /* tx 8 bits, assert DTR & RTS */ + 4, 0x46, /* x16 clock, 1 stop */ + 3, 0xc1, /* rx enable, 8 bits */ +}; + +void udbg_init_scc(struct device_node *np) +{ + u32 *reg; + unsigned long addr; + int i, x; + + if (np == NULL) + np = of_find_node_by_name(NULL, "escc"); + if (np == NULL || np->parent == NULL) + return; + + udbg_printf("found SCC...\n"); + /* Get address within mac-io ASIC */ + reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) + return; + addr = reg[0]; + udbg_printf("local addr: %lx\n", addr); + /* Get address of mac-io PCI itself */ + reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); + if (reg == NULL) + return; + addr += reg[2]; + udbg_printf("final addr: %lx\n", addr); + + /* Setup for 57600 8N1 */ + addr += 0x20; + sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; + sccc += addr & ~PAGE_MASK; + sccd = sccc + 0x10; + + udbg_printf("ioremap result sccc: %p\n", sccc); + mb(); + + for (i = 20000; i != 0; --i) + x = in_8(sccc); + out_8(sccc, 0x09); /* reset A or B side */ + out_8(sccc, 0xc0); + for (i = 0; i < sizeof(scc_inittab); ++i) + out_8(sccc, scc_inittab[i]); + + udbg_putc = udbg_scc_putc; + udbg_getc = udbg_scc_getc; + udbg_getc_poll = udbg_scc_getc_poll; + + udbg_puts("Hello World !\n"); +} + +static void udbg_real_scc_putc(unsigned char c) +{ + while ((real_readb(sccc) & SCC_TXRDY) == 0) + ; + real_writeb(c, sccd); + if (c == '\n') + udbg_real_scc_putc('\r'); +} + +void udbg_init_pmac_realmode(void) +{ + sccc = (volatile u8 __iomem *)0x80013020ul; + sccd = (volatile u8 __iomem *)0x80013030ul; + + udbg_putc = udbg_real_scc_putc; + udbg_getc = NULL; + udbg_getc_poll = NULL; +} diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c index 4777676365f..efa985f05ac 100644 --- a/arch/ppc64/kernel/vdso.c +++ b/arch/ppc64/kernel/vdso.c @@ -224,10 +224,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma == NULL) return -ENOMEM; - if (security_vm_enough_memory(vdso_pages)) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } + memset(vma, 0, sizeof(*vma)); /* @@ -237,8 +234,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) */ vdso_base = get_unmapped_area(NULL, vdso_base, vdso_pages << PAGE_SHIFT, 0, 0); - if (vdso_base & ~PAGE_MASK) + if (vdso_base & ~PAGE_MASK) { + kmem_cache_free(vm_area_cachep, vma); return (int)vdso_base; + } current->thread.vdso_base = vdso_base; @@ -266,7 +265,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) vma->vm_ops = &vdso_vmops; down_write(&mm->mmap_sem); - insert_vm_struct(mm, vma); + if (insert_vm_struct(mm, vma)) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; + } mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; up_write(&mm->mmap_sem); diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S index 0ed7ea72171..c8db993574e 100644 --- a/arch/ppc64/kernel/vdso32/cacheflush.S +++ b/arch/ppc64/kernel/vdso32/cacheflush.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/ppc64/kernel/vdso32/datapage.S index 29b6bd32e1f..4f4eb0be399 100644 --- a/arch/ppc64/kernel/vdso32/datapage.S +++ b/arch/ppc64/kernel/vdso32/datapage.S @@ -12,7 +12,7 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/vdso.h> diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S index 2b48bf1fb10..07f1c1c650c 100644 --- a/arch/ppc64/kernel/vdso32/gettimeofday.S +++ b/arch/ppc64/kernel/vdso32/gettimeofday.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> .text diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S index e0725b7b700..d4a0ad28d53 100644 --- a/arch/ppc64/kernel/vdso64/cacheflush.S +++ b/arch/ppc64/kernel/vdso64/cacheflush.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/ppc64/kernel/vdso64/datapage.S index 18afd971c9d..ed6e599ae82 100644 --- a/arch/ppc64/kernel/vdso64/datapage.S +++ b/arch/ppc64/kernel/vdso64/datapage.S @@ -12,7 +12,7 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/vdso.h> diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S index ed3f970ff05..f6df8028570 100644 --- a/arch/ppc64/kernel/vdso64/gettimeofday.S +++ b/arch/ppc64/kernel/vdso64/gettimeofday.S @@ -14,7 +14,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text /* diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S index 4103cc13f8d..0306510bc4f 100644 --- a/arch/ppc64/kernel/vmlinux.lds.S +++ b/arch/ppc64/kernel/vmlinux.lds.S @@ -15,6 +15,7 @@ SECTIONS *(.text .text.*) SCHED_TEXT LOCK_TEXT + KPROBES_TEXT *(.fixup) . = ALIGN(4096); _etext = .; diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index d9dc6f28d05..daf93885dcf 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -38,7 +38,7 @@ static void xics_mask_and_ack_irq(unsigned int irq); static void xics_end_irq(unsigned int irq); static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask); -struct hw_interrupt_type xics_pic = { +static struct hw_interrupt_type xics_pic = { .typename = " XICS ", .startup = xics_startup, .enable = xics_enable_irq, @@ -48,7 +48,7 @@ struct hw_interrupt_type xics_pic = { .set_affinity = xics_set_affinity }; -struct hw_interrupt_type xics_8259_pic = { +static struct hw_interrupt_type xics_8259_pic = { .typename = " XICS/8259", .ack = xics_mask_and_ack_irq, }; @@ -89,9 +89,8 @@ static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; static int xics_irq_8259_cascade = 0; static int xics_irq_8259_cascade_real = 0; static unsigned int default_server = 0xFF; -/* also referenced in smp.c... */ -unsigned int default_distrib_server = 0; -unsigned int interrupt_server_size = 8; +static unsigned int default_distrib_server = 0; +static unsigned int interrupt_server_size = 8; /* * XICS only has a single IPI, so encode the messages per CPU @@ -99,10 +98,10 @@ unsigned int interrupt_server_size = 8; struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; /* RTAS service tokens */ -int ibm_get_xive; -int ibm_set_xive; -int ibm_int_on; -int ibm_int_off; +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; typedef struct { int (*xirr_info_get)(int cpu); @@ -284,16 +283,17 @@ static void xics_enable_irq(unsigned int virq) call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_set_xive " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " + "returned %d\n", irq, call_status); + printk("set_xive %x, server %x\n", ibm_set_xive, server); return; } /* Now unmask the interrupt (often a no-op) */ call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_int_on " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " + "returned %d\n", irq, call_status); return; } } @@ -308,8 +308,8 @@ static void xics_disable_real_irq(unsigned int irq) call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_disable_real_irq: irq=%d: " - "ibm_int_off returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_real_irq: irq=%u: " + "ibm_int_off returned %d\n", irq, call_status); return; } @@ -317,8 +317,8 @@ static void xics_disable_real_irq(unsigned int irq) /* Have to set XIVE to 0xff to be able to remove a slot */ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff); if (call_status != 0) { - printk(KERN_ERR "xics_disable_irq: irq=%d: ibm_set_xive(0xff)" - " returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" + " returned %d\n", irq, call_status); return; } } @@ -380,7 +380,7 @@ int xics_get_irq(struct pt_regs *regs) if (irq == NO_IRQ) irq = real_irq_to_virt_slowpath(vec); if (irq == NO_IRQ) { - printk(KERN_ERR "Interrupt %d (real) is invalid," + printk(KERN_ERR "Interrupt %u (real) is invalid," " disabling it.\n", vec); xics_disable_real_irq(vec); } else @@ -622,7 +622,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,get-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " "returns %d\n", irq, status); return; } @@ -641,7 +641,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) irq, newmask, xics_status[1]); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,set-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " "returns %d\n", irq, status); return; } @@ -720,7 +720,7 @@ void xics_migrate_irqs_away(void) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "migrate_irqs_away: irq=%d " + printk(KERN_ERR "migrate_irqs_away: irq=%u " "ibm,get-xive returns %d\n", virq, status); goto unlock; @@ -734,7 +734,7 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != get_hard_smp_processor_id(cpu)) goto unlock; - printk(KERN_WARNING "IRQ %d affinity broken off cpu %u\n", + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", virq, cpu); /* Reset affinity to all cpus */ diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 76fbfa9f706..0b6e967de94 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc64-specific library files.. # -lib-y := checksum.o dec_and_lock.o string.o strcase.o +lib-y := checksum.o string.o strcase.o lib-y += copypage.o memcpy.o copyuser.o usercopy.o # Lock primitives are defined as no-ops in include/linux/spinlock.h diff --git a/arch/ppc64/lib/dec_and_lock.c b/arch/ppc64/lib/dec_and_lock.c deleted file mode 100644 index 6e8d8591708..00000000000 --- a/arch/ppc64/lib/dec_and_lock.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ppc64 version of atomic_dec_and_lock() using cmpxchg - * - * 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/module.h> -#include <linux/spinlock.h> -#include <asm/atomic.h> -#include <asm/system.h> - -/* - * This is an implementation of the notion of "decrement a - * reference count, and return locked if it decremented to zero". - * - * This implementation can be used on any architecture that - * has a cmpxchg, and where atomic->value is an int holding - * the value of the atomic (i.e. the high bits aren't used - * for a lock or anything like that). - * - * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h - * if spinlocks are empty and thus atomic_dec_and_lock is defined - * to be atomic_dec_and_test - in that case we don't need it - * defined here as well. - */ - -#ifndef ATOMIC_DEC_AND_LOCK -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - - for (;;) { - counter = atomic_read(atomic); - newcount = counter - 1; - if (!newcount) - break; /* do it the slow way */ - - newcount = cmpxchg(&atomic->counter, counter, newcount); - if (newcount == counter) - return 0; - } - - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* ATOMIC_DEC_AND_LOCK */ diff --git a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c index ef70ef91abe..033643ab69e 100644 --- a/arch/ppc64/lib/locks.c +++ b/arch/ppc64/lib/locks.c @@ -23,12 +23,12 @@ /* waiting for a spinlock... */ #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) -void __spin_yield(spinlock_t *lock) +void __spin_yield(raw_spinlock_t *lock) { unsigned int lock_value, holder_cpu, yield_count; struct paca_struct *holder_paca; - lock_value = lock->lock; + lock_value = lock->slock; if (lock_value == 0) return; holder_cpu = lock_value & 0xffff; @@ -38,7 +38,7 @@ void __spin_yield(spinlock_t *lock) if ((yield_count & 1) == 0) return; /* virtual cpu is currently running */ rmb(); - if (lock->lock != lock_value) + if (lock->slock != lock_value) return; /* something has changed */ #ifdef CONFIG_PPC_ISERIES HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, @@ -54,7 +54,7 @@ void __spin_yield(spinlock_t *lock) * This turns out to be the same for read and write locks, since * we only know the holder if it is write-locked. */ -void __rw_yield(rwlock_t *rw) +void __rw_yield(raw_rwlock_t *rw) { int lock_value; unsigned int holder_cpu, yield_count; @@ -82,9 +82,9 @@ void __rw_yield(rwlock_t *rw) } #endif -void spin_unlock_wait(spinlock_t *lock) +void __raw_spin_unlock_wait(raw_spinlock_t *lock) { - while (lock->lock) { + while (lock->slock) { HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); @@ -92,4 +92,4 @@ void spin_unlock_wait(spinlock_t *lock) HMT_medium(); } -EXPORT_SYMBOL(spin_unlock_wait); +EXPORT_SYMBOL(__raw_spin_unlock_wait); diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c index 20b0f37e8bf..be3f25cf3e9 100644 --- a/arch/ppc64/mm/fault.c +++ b/arch/ppc64/mm/fault.c @@ -29,6 +29,7 @@ #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/module.h> +#include <linux/kprobes.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -37,6 +38,7 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/kdebug.h> +#include <asm/siginfo.h> /* * Check whether the instruction at regs->nip is a store using @@ -76,6 +78,28 @@ static int store_updates_sp(struct pt_regs *regs) return 0; } +static void do_dabr(struct pt_regs *regs, unsigned long error_code) +{ + siginfo_t info; + + if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, + 11, SIGSEGV) == NOTIFY_STOP) + return; + + if (debugger_dabr_match(regs)) + return; + + /* Clear the DABR */ + set_dabr(0); + + /* Deliver the signal to userspace */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + info.si_addr = (void __user *)regs->nip; + force_sig_info(SIGTRAP, &info, current); +} + /* * The error_code parameter is * - DSISR for a non-SLB data access fault, @@ -84,8 +108,8 @@ static int store_updates_sp(struct pt_regs *regs) * The return value is 0 if the fault was handled, or the signal * number if this is a kernel fault that can't be handled here. */ -int do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long error_code) +int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; @@ -110,12 +134,9 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && (address >= TASK_SIZE)) return SIGSEGV; - if (error_code & DSISR_DABRMATCH) { - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return 0; - if (debugger_dabr_match(regs)) - return 0; + if (error_code & DSISR_DABRMATCH) { + do_dabr(regs, error_code); + return 0; } if (in_atomic() || mm == NULL) { diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S index 35eb49e1b89..ee5a5d36bfa 100644 --- a/arch/ppc64/mm/hash_low.S +++ b/arch/ppc64/mm/hash_low.S @@ -16,7 +16,7 @@ #include <asm/page.h> #include <asm/types.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> .text diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index 7626bb59954..eb1bbb5b6c1 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c @@ -343,9 +343,7 @@ static void native_flush_hash_range(unsigned long context, hpte_t *hptep; unsigned long hpte_v; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - - /* XXX fix for large ptes */ - unsigned long large = 0; + unsigned long large; local_irq_save(flags); @@ -358,6 +356,7 @@ static void native_flush_hash_range(unsigned long context, va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); batch->vaddr[j] = va; + large = pte_huge(batch->pte[i]); if (large) vpn = va >> HPAGE_SHIFT; else diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index e7833c80eb6..0ea0994ed97 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -144,7 +144,8 @@ static void flush_low_segments(void *parm) for (i = 0; i < NUM_LOW_AREAS; i++) { if (! (areas & (1U << i))) continue; - asm volatile("slbie %0" : : "r" (i << SID_SHIFT)); + asm volatile("slbie %0" + : : "r" ((i << SID_SHIFT) | SLBIE_C)); } asm volatile("isync" : : : "memory"); @@ -164,7 +165,8 @@ static void flush_high_segments(void *parm) continue; for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++) asm volatile("slbie %0" - :: "r" ((i << HTLB_AREA_SHIFT) + (j << SID_SHIFT))); + :: "r" (((i << HTLB_AREA_SHIFT) + + (j << SID_SHIFT)) | SLBIE_C)); } asm volatile("isync" : : : "memory"); @@ -708,10 +710,13 @@ repeat: hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; slot = ppc_md.hpte_insert(hpte_group, va, prpn, - HPTE_V_LARGE, rflags); + HPTE_V_LARGE | + HPTE_V_SECONDARY, + rflags); if (slot == -1) { if (mftb() & 0x1) - hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; + hpte_group = ((hash & htab_hash_mask) * + HPTES_PER_GROUP)&~0x7UL; ppc_md.hpte_remove(hpte_group); goto repeat; diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index c02dc9809ca..c2157c9c3ac 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -392,6 +392,7 @@ void free_initmem(void) addr = (unsigned long)__init_begin; for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { + memset((void *)addr, 0xcc, PAGE_SIZE); ClearPageReserved(virt_to_page(addr)); set_page_count(virt_to_page(addr), 1); free_page(addr); @@ -552,27 +553,18 @@ void __init do_init_bootmem(void) /* Add all physical memory to the bootmem map, mark each area * present. */ - for (i=0; i < lmb.memory.cnt; i++) { - unsigned long base, size; - unsigned long start_pfn, end_pfn; - - base = lmb.memory.region[i].base; - size = lmb.memory.region[i].size; - - start_pfn = base >> PAGE_SHIFT; - end_pfn = start_pfn + (size >> PAGE_SHIFT); - memory_present(0, start_pfn, end_pfn); - - free_bootmem(base, size); - } + for (i=0; i < lmb.memory.cnt; i++) + free_bootmem(lmb.memory.region[i].base, + lmb_size_bytes(&lmb.memory, i)); /* reserve the sections we're already using */ - for (i=0; i < lmb.reserved.cnt; i++) { - unsigned long base = lmb.reserved.region[i].base; - unsigned long size = lmb.reserved.region[i].size; + for (i=0; i < lmb.reserved.cnt; i++) + reserve_bootmem(lmb.reserved.region[i].base, + lmb_size_bytes(&lmb.reserved, i)); - reserve_bootmem(base, size); - } + for (i=0; i < lmb.memory.cnt; i++) + memory_present(0, lmb_start_pfn(&lmb.memory, i), + lmb_end_pfn(&lmb.memory, i)); } /* diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c index c3116f0d788..cb864b8f275 100644 --- a/arch/ppc64/mm/numa.c +++ b/arch/ppc64/mm/numa.c @@ -440,8 +440,6 @@ new_range: for (i = start ; i < (start+size); i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = numa_domain; - memory_present(numa_domain, start >> PAGE_SHIFT, - (start + size) >> PAGE_SHIFT); if (--ranges) goto new_range; @@ -483,7 +481,6 @@ static void __init setup_nonnuma(void) for (i = 0 ; i < top_of_ram; i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0; - memory_present(0, 0, init_node_data[0].node_end_pfn); } static void __init dump_numa_topology(void) @@ -695,6 +692,46 @@ new_range: size); } } + /* + * This loop may look famaliar, but we have to do it again + * after marking our reserved memory to mark memory present + * for sparsemem. + */ + addr_cells = get_mem_addr_cells(); + size_cells = get_mem_size_cells(); + memory = NULL; + while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { + unsigned long mem_start, mem_size; + int numa_domain, ranges; + unsigned int *memcell_buf; + unsigned int len; + + memcell_buf = (unsigned int *)get_property(memory, "reg", &len); + if (!memcell_buf || len <= 0) + continue; + + ranges = memory->n_addrs; /* ranges in cell */ +new_range2: + mem_start = read_n_cells(addr_cells, &memcell_buf); + mem_size = read_n_cells(size_cells, &memcell_buf); + if (numa_enabled) { + numa_domain = of_node_numa_domain(memory); + if (numa_domain >= MAX_NUMNODES) + numa_domain = 0; + } else + numa_domain = 0; + + if (numa_domain != nid) + continue; + + mem_size = numa_enforce_memory_limit(mem_start, mem_size); + memory_present(numa_domain, mem_start >> PAGE_SHIFT, + (mem_start + mem_size) >> PAGE_SHIFT); + + if (--ranges) /* process all ranges in cell */ + goto new_range2; + } + } } diff --git a/arch/ppc64/mm/slb.c b/arch/ppc64/mm/slb.c index 244150a0bc1..0473953f6a3 100644 --- a/arch/ppc64/mm/slb.c +++ b/arch/ppc64/mm/slb.c @@ -87,8 +87,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) int i; asm volatile("isync" : : : "memory"); for (i = 0; i < offset; i++) { - esid_data = (unsigned long)get_paca()->slb_cache[i] - << SID_SHIFT; + esid_data = ((unsigned long)get_paca()->slb_cache[i] + << SID_SHIFT) | SLBIE_C; asm volatile("slbie %0" : : "r" (esid_data)); } asm volatile("isync" : : : "memory"); diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S index 698d6b9ed6d..a3a03da503b 100644 --- a/arch/ppc64/mm/slb_low.S +++ b/arch/ppc64/mm/slb_low.S @@ -21,7 +21,7 @@ #include <asm/page.h> #include <asm/mmu.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> /* void slb_allocate(unsigned long ea); diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c index 4acd1a42493..e5f572710aa 100644 --- a/arch/ppc64/oprofile/common.c +++ b/arch/ppc64/oprofile/common.c @@ -16,11 +16,9 @@ #include <asm/ptrace.h> #include <asm/system.h> #include <asm/pmc.h> +#include <asm/cputable.h> +#include <asm/oprofile_impl.h> -#include "op_impl.h" - -extern struct op_ppc64_model op_model_rs64; -extern struct op_ppc64_model op_model_power4; static struct op_ppc64_model *model; static struct op_counter_config ctr[OP_MAX_COUNTER]; @@ -123,53 +121,13 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) int __init oprofile_arch_init(struct oprofile_operations *ops) { - unsigned int pvr; - - pvr = mfspr(SPRN_PVR); - - switch (PVR_VER(pvr)) { - case PV_630: - case PV_630p: - model = &op_model_rs64; - model->num_counters = 8; - ops->cpu_type = "ppc64/power3"; - break; - - case PV_NORTHSTAR: - case PV_PULSAR: - case PV_ICESTAR: - case PV_SSTAR: - model = &op_model_rs64; - model->num_counters = 8; - ops->cpu_type = "ppc64/rs64"; - break; - - case PV_POWER4: - case PV_POWER4p: - model = &op_model_power4; - model->num_counters = 8; - ops->cpu_type = "ppc64/power4"; - break; - - case PV_970: - case PV_970FX: - case PV_970MP: - model = &op_model_power4; - model->num_counters = 8; - ops->cpu_type = "ppc64/970"; - break; - - case PV_POWER5: - case PV_POWER5p: - model = &op_model_power4; - model->num_counters = 6; - ops->cpu_type = "ppc64/power5"; - break; - - default: - return -ENODEV; - } + if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type) + return -ENODEV; + + model = cur_cpu_spec->oprofile_model; + model->num_counters = cur_cpu_spec->num_pmcs; + ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; ops->create_files = op_ppc64_create_files; ops->setup = op_ppc64_setup; ops->shutdown = op_ppc64_shutdown; diff --git a/arch/ppc64/oprofile/op_impl.h b/arch/ppc64/oprofile/op_impl.h deleted file mode 100644 index 7fa7eaabc03..00000000000 --- a/arch/ppc64/oprofile/op_impl.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM - * - * Based on alpha version. - * - * 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. - */ - -#ifndef OP_IMPL_H -#define OP_IMPL_H 1 - -#define OP_MAX_COUNTER 8 - -/* Per-counter configuration as set via oprofilefs. */ -struct op_counter_config { - unsigned long valid; - unsigned long enabled; - unsigned long event; - unsigned long count; - unsigned long kernel; - /* We dont support per counter user/kernel selection */ - unsigned long user; - unsigned long unit_mask; -}; - -/* System-wide configuration as set via oprofilefs. */ -struct op_system_config { - unsigned long mmcr0; - unsigned long mmcr1; - unsigned long mmcra; - unsigned long enable_kernel; - unsigned long enable_user; - unsigned long backtrace_spinlocks; -}; - -/* Per-arch configuration */ -struct op_ppc64_model { - void (*reg_setup) (struct op_counter_config *, - struct op_system_config *, - int num_counters); - void (*cpu_setup) (void *); - void (*start) (struct op_counter_config *); - void (*stop) (void); - void (*handle_interrupt) (struct pt_regs *, - struct op_counter_config *); - int num_counters; -}; - -static inline unsigned int ctr_read(unsigned int i) -{ - switch(i) { - case 0: - return mfspr(SPRN_PMC1); - case 1: - return mfspr(SPRN_PMC2); - case 2: - return mfspr(SPRN_PMC3); - case 3: - return mfspr(SPRN_PMC4); - case 4: - return mfspr(SPRN_PMC5); - case 5: - return mfspr(SPRN_PMC6); - case 6: - return mfspr(SPRN_PMC7); - case 7: - return mfspr(SPRN_PMC8); - default: - return 0; - } -} - -static inline void ctr_write(unsigned int i, unsigned int val) -{ - switch(i) { - case 0: - mtspr(SPRN_PMC1, val); - break; - case 1: - mtspr(SPRN_PMC2, val); - break; - case 2: - mtspr(SPRN_PMC3, val); - break; - case 3: - mtspr(SPRN_PMC4, val); - break; - case 4: - mtspr(SPRN_PMC5, val); - break; - case 5: - mtspr(SPRN_PMC6, val); - break; - case 6: - mtspr(SPRN_PMC7, val); - break; - case 7: - mtspr(SPRN_PMC8, val); - break; - default: - break; - } -} - -#endif diff --git a/arch/ppc64/oprofile/op_model_power4.c b/arch/ppc64/oprofile/op_model_power4.c index 3d103d66870..32b2bb5625f 100644 --- a/arch/ppc64/oprofile/op_model_power4.c +++ b/arch/ppc64/oprofile/op_model_power4.c @@ -16,14 +16,12 @@ #include <asm/cputable.h> #include <asm/systemcfg.h> #include <asm/rtas.h> +#include <asm/oprofile_impl.h> #define dbg(args...) -#include "op_impl.h" - static unsigned long reset_value[OP_MAX_COUNTER]; -static int num_counters; static int oprofile_running; static int mmcra_has_sihv; @@ -45,8 +43,6 @@ static void power4_reg_setup(struct op_counter_config *ctr, { int i; - num_counters = num_ctrs; - /* * SIHV / SIPR bits are only implemented on POWER4+ (GQ) and above. * However we disable it on all POWER4 until we verify it works @@ -68,7 +64,7 @@ static void power4_reg_setup(struct op_counter_config *ctr, backtrace_spinlocks = sys->backtrace_spinlocks; - for (i = 0; i < num_counters; ++i) + for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; /* setup user and kernel profiling */ @@ -121,7 +117,7 @@ static void power4_start(struct op_counter_config *ctr) /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); - for (i = 0; i < num_counters; ++i) { + for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { if (ctr[i].enabled) { ctr_write(i, reset_value[i]); } else { @@ -272,7 +268,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); - for (i = 0; i < num_counters; ++i) { + for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { diff --git a/arch/ppc64/oprofile/op_model_rs64.c b/arch/ppc64/oprofile/op_model_rs64.c index bcec506c266..08c5b333f5c 100644 --- a/arch/ppc64/oprofile/op_model_rs64.c +++ b/arch/ppc64/oprofile/op_model_rs64.c @@ -14,11 +14,10 @@ #include <asm/system.h> #include <asm/processor.h> #include <asm/cputable.h> +#include <asm/oprofile_impl.h> #define dbg(args...) -#include "op_impl.h" - static void ctrl_write(unsigned int i, unsigned int val) { unsigned int tmp = 0; diff --git a/arch/ppc64/xmon/privinst.h b/arch/ppc64/xmon/privinst.h index 183c3e40025..02eb40dac0b 100644 --- a/arch/ppc64/xmon/privinst.h +++ b/arch/ppc64/xmon/privinst.h @@ -46,7 +46,6 @@ GSETSPR(287, pvr) GSETSPR(1008, hid0) GSETSPR(1009, hid1) GSETSPR(1010, iabr) -GSETSPR(1013, dabr) GSETSPR(1023, pir) static inline void store_inst(void *p) diff --git a/arch/ppc64/xmon/start.c b/arch/ppc64/xmon/start.c index f86b584acd7..e50c158191e 100644 --- a/arch/ppc64/xmon/start.c +++ b/arch/ppc64/xmon/start.c @@ -61,7 +61,9 @@ xmon_read(void *handle, void *ptr, int nb) int xmon_read_poll(void) { - return udbg_getc_poll(); + if (udbg_getc_poll) + return udbg_getc_poll(); + return -1; } FILE *xmon_stdin; diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 45908b10acd..74e63a886a6 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -586,6 +586,8 @@ int xmon_dabr_match(struct pt_regs *regs) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) return 0; + if (dabr.enabled == 0) + return 0; xmon_core(regs, 0); return 1; } @@ -628,20 +630,6 @@ int xmon_fault_handler(struct pt_regs *regs) return 0; } -/* On systems with a hypervisor, we can't set the DABR - (data address breakpoint register) directly. */ -static void set_controlled_dabr(unsigned long val) -{ -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { - int rc = plpar_hcall_norets(H_SET_DABR, val); - if (rc != H_Success) - xmon_printf("Warning: setting DABR failed (%d)\n", rc); - } else -#endif - set_dabr(val); -} - static struct bpt *at_breakpoint(unsigned long pc) { int i; @@ -728,7 +716,7 @@ static void insert_bpts(void) static void insert_cpu_bpts(void) { if (dabr.enabled) - set_controlled_dabr(dabr.address | (dabr.enabled & 7)); + set_dabr(dabr.address | (dabr.enabled & 7)); if (iabr && cpu_has_feature(CPU_FTR_IABR)) set_iabr(iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); @@ -756,7 +744,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { - set_controlled_dabr(0); + set_dabr(0); if (cpu_has_feature(CPU_FTR_IABR)) set_iabr(0); } |