diff options
Diffstat (limited to 'arch')
23 files changed, 929 insertions, 499 deletions
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 0b5469fb6e0..7994955c29d 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc4 -# Tue Dec 4 22:49:57 2007 +# Linux kernel version: 2.6.24-rc8 +# Wed Jan 16 14:31:21 2008 # CONFIG_PPC64=y @@ -103,6 +103,7 @@ CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -154,7 +155,6 @@ CONFIG_PPC_PS3=y # CONFIG_PS3_ADVANCED is not set CONFIG_PS3_HTAB_SIZE=20 # CONFIG_PS3_DYNAMIC_DMA is not set -CONFIG_PS3_USE_LPAR_ADDR=y CONFIG_PS3_VUART=y CONFIG_PS3_PS3AV=y CONFIG_PS3_SYS_MANAGER=y @@ -162,6 +162,7 @@ CONFIG_PS3_STORAGE=y CONFIG_PS3_DISK=y CONFIG_PS3_ROM=y CONFIG_PS3_FLASH=y +CONFIG_PS3_LPM=m CONFIG_PPC_CELL=y # CONFIG_PPC_CELL_NATIVE is not set # CONFIG_PPC_IBM_CELL_BLADE is not set @@ -225,7 +226,7 @@ CONFIG_HAVE_MEMORY_PRESENT=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y -CONFIG_SPARSEMEM_VMEMMAP=y +# CONFIG_SPARSEMEM_VMEMMAP is not set CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTPLUG_SPARSE=y CONFIG_SPLIT_PTLOCK_CPUS=4 @@ -338,7 +339,26 @@ CONFIG_IPV6_SIT=y # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set -# CONFIG_BT is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +CONFIG_BT_HCIUSB_SCO=y +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set # CONFIG_AF_RXRPC is not set # @@ -666,14 +686,14 @@ CONFIG_LOGO_LINUX_CLUT224=y # # Sound # -CONFIG_SOUND=y +CONFIG_SOUND=m # # Advanced Linux Sound Architecture # -CONFIG_SND=y -CONFIG_SND_TIMER=y -CONFIG_SND_PCM=y +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m # CONFIG_SND_SEQUENCER is not set # CONFIG_SND_MIXER_OSS is not set # CONFIG_SND_PCM_OSS is not set @@ -702,7 +722,7 @@ CONFIG_SND_VERBOSE_PROCFS=y # # ALSA PowerPC devices # -CONFIG_SND_PS3=y +CONFIG_SND_PS3=m CONFIG_SND_PS3_DEFAULT_START_DELAY=2000 # @@ -747,7 +767,7 @@ CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y -CONFIG_USB=y +CONFIG_USB=m # CONFIG_USB_DEBUG is not set # @@ -761,13 +781,13 @@ CONFIG_USB_DEVICEFS=y # # USB Host Controller Drivers # -CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y # CONFIG_USB_ISP116X_HCD is not set -CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD=m # CONFIG_USB_OHCI_HCD_PPC_OF is not set # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y @@ -1033,7 +1053,8 @@ CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y CONFIG_INSTRUMENTATION=y -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=m # CONFIG_KPROBES is not set # CONFIG_MARKERS is not set diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 77c749a1337..571132ed12c 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -32,6 +32,8 @@ #include <asm/lmb.h> #include <asm/firmware.h> #include <asm/smp.h> +#include <asm/system.h> +#include <asm/setjmp.h> #ifdef DEBUG #include <asm/udbg.h> @@ -45,6 +47,11 @@ int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; cpumask_t cpus_in_sr = CPU_MASK_NONE; +#define CRASH_HANDLER_MAX 1 +/* NULL terminated list of shutdown handles */ +static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; +static DEFINE_SPINLOCK(crash_handlers_lock); + #ifdef CONFIG_SMP static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); @@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus(void) } #endif /* CONFIG_SPU_BASE */ +/* + * Register a function to be called on shutdown. Only use this if you + * can't reset your device in the second kernel. + */ +int crash_shutdown_register(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (!crash_shutdown_handles[i]) { + /* Insert handle at first empty entry */ + crash_shutdown_handles[i] = handler; + rc = 0; + break; + } + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handles full, " + "not registered.\n"); + rc = 1; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_register); + +int crash_shutdown_unregister(crash_shutdown_t handler) +{ + unsigned int i, rc; + + spin_lock(&crash_handlers_lock); + for (i = 0 ; i < CRASH_HANDLER_MAX; i++) + if (crash_shutdown_handles[i] == handler) + break; + + if (i == CRASH_HANDLER_MAX) { + printk(KERN_ERR "Crash shutdown handle not found\n"); + rc = 1; + } else { + /* Shift handles down */ + for (; crash_shutdown_handles[i]; i++) + crash_shutdown_handles[i] = + crash_shutdown_handles[i+1]; + rc = 0; + } + + spin_unlock(&crash_handlers_lock); + return rc; +} +EXPORT_SYMBOL(crash_shutdown_unregister); + +static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; + +static int handle_fault(struct pt_regs *regs) +{ + longjmp(crash_shutdown_buf, 1); + return 0; +} + void default_machine_crash_shutdown(struct pt_regs *regs) { - unsigned int irq; + unsigned int i; + int (*old_handler)(struct pt_regs *regs); + /* * This function is only called after the system @@ -301,15 +371,36 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ hard_irq_disable(); - for_each_irq(irq) { - struct irq_desc *desc = irq_desc + irq; + for_each_irq(i) { + struct irq_desc *desc = irq_desc + i; if (desc->status & IRQ_INPROGRESS) - desc->chip->eoi(irq); + desc->chip->eoi(i); if (!(desc->status & IRQ_DISABLED)) - desc->chip->disable(irq); + desc->chip->disable(i); + } + + /* + * Call registered shutdown routines savely. Swap out + * __debugger_fault_handler, and replace on exit. + */ + old_handler = __debugger_fault_handler; + __debugger_fault_handler = handle_fault; + for (i = 0; crash_shutdown_handles[i]; i++) { + if (setjmp(crash_shutdown_buf) == 0) { + /* + * Insert syncs and delay to ensure + * instructions in the dangerous region don't + * leak away from this protected region. + */ + asm volatile("sync; isync"); + /* dangerous region */ + crash_shutdown_handles[i](); + asm volatile("sync; isync"); + } } + __debugger_fault_handler = old_handler; /* * Make a note of crashing cpu. Will be used in machine_kexec diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 14206e3f081..84239076a5b 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c @@ -112,10 +112,16 @@ EXPORT_SYMBOL(dma_iommu_ops); /* * Generic direct DMA implementation * - * This implementation supports a global offset that can be applied if - * the address at which memory is visible to devices is not 0. + * This implementation supports a per-device offset that can be applied if + * the address at which memory is visible to devices is not 0. Platform code + * can set archdata.dma_data to an unsigned long holding the offset. By + * default the offset is zero. */ -unsigned long dma_direct_offset; + +static unsigned long get_dma_direct_offset(struct device *dev) +{ + return (unsigned long)dev->archdata.dma_data; +} static void *dma_direct_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) @@ -124,13 +130,12 @@ static void *dma_direct_alloc_coherent(struct device *dev, size_t size, void *ret; int node = dev->archdata.numa_node; - /* TODO: Maybe use the numa node here too ? */ page = alloc_pages_node(node, flag, get_order(size)); if (page == NULL) return NULL; ret = page_address(page); memset(ret, 0, size); - *dma_handle = virt_to_abs(ret) | dma_direct_offset; + *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev); return ret; } @@ -145,7 +150,7 @@ static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction direction) { - return virt_to_abs(ptr) | dma_direct_offset; + return virt_to_abs(ptr) + get_dma_direct_offset(dev); } static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, @@ -161,7 +166,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int i; for_each_sg(sgl, sg, nents, i) { - sg->dma_address = sg_phys(sg) | dma_direct_offset; + sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev); sg->dma_length = sg->length; } diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index fd5ae8d17c9..2f50bb5d00f 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -198,16 +198,13 @@ int ibmebus_register_driver(struct of_platform_driver *drv) /* If the driver uses devices that ibmebus doesn't know, add them */ ibmebus_create_devices(drv->match_table); - drv->driver.name = drv->name; - drv->driver.bus = &ibmebus_bus_type; - - return driver_register(&drv->driver); + return of_register_driver(drv, &ibmebus_bus_type); } EXPORT_SYMBOL(ibmebus_register_driver); void ibmebus_unregister_driver(struct of_platform_driver *drv) { - driver_unregister(&drv->driver); + of_unregister_driver(drv); } EXPORT_SYMBOL(ibmebus_unregister_driver); diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 74ce0c7a7b1..7b916022069 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -8,6 +8,8 @@ * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * + * setjmp/longjmp code by Paul Mackerras. + * * 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 @@ -15,6 +17,8 @@ */ #include <asm/ppc_asm.h> #include <asm/unistd.h> +#include <asm/asm-compat.h> +#include <asm/asm-offsets.h> .text @@ -51,3 +55,64 @@ _GLOBAL(kernel_execve) bnslr neg r3,r3 blr + +_GLOBAL(setjmp) + mflr r0 + PPC_STL r0,0(r3) + PPC_STL r1,SZL(r3) + PPC_STL r2,2*SZL(r3) + mfcr r0 + PPC_STL r0,3*SZL(r3) + PPC_STL r13,4*SZL(r3) + PPC_STL r14,5*SZL(r3) + PPC_STL r15,6*SZL(r3) + PPC_STL r16,7*SZL(r3) + PPC_STL r17,8*SZL(r3) + PPC_STL r18,9*SZL(r3) + PPC_STL r19,10*SZL(r3) + PPC_STL r20,11*SZL(r3) + PPC_STL r21,12*SZL(r3) + PPC_STL r22,13*SZL(r3) + PPC_STL r23,14*SZL(r3) + PPC_STL r24,15*SZL(r3) + PPC_STL r25,16*SZL(r3) + PPC_STL r26,17*SZL(r3) + PPC_STL r27,18*SZL(r3) + PPC_STL r28,19*SZL(r3) + PPC_STL r29,20*SZL(r3) + PPC_STL r30,21*SZL(r3) + PPC_STL r31,22*SZL(r3) + li r3,0 + blr + +_GLOBAL(longjmp) + PPC_LCMPI r4,0 + bne 1f + li r4,1 +1: PPC_LL r13,4*SZL(r3) + PPC_LL r14,5*SZL(r3) + PPC_LL r15,6*SZL(r3) + PPC_LL r16,7*SZL(r3) + PPC_LL r17,8*SZL(r3) + PPC_LL r18,9*SZL(r3) + PPC_LL r19,10*SZL(r3) + PPC_LL r20,11*SZL(r3) + PPC_LL r21,12*SZL(r3) + PPC_LL r22,13*SZL(r3) + PPC_LL r23,14*SZL(r3) + PPC_LL r24,15*SZL(r3) + PPC_LL r25,16*SZL(r3) + PPC_LL r26,17*SZL(r3) + PPC_LL r27,18*SZL(r3) + PPC_LL r28,19*SZL(r3) + PPC_LL r29,20*SZL(r3) + PPC_LL r30,21*SZL(r3) + PPC_LL r31,22*SZL(r3) + PPC_LL r0,3*SZL(r3) + mtcrf 0x38,r0 + PPC_LL r0,0(r3) + PPC_LL r1,SZL(r3) + PPC_LL r2,2*SZL(r3) + mtlr r0 + mr r3,r4 + blr diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 1930f393d01..52750745edf 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -357,7 +357,6 @@ void __devinit scan_phb(struct pci_controller *hose) struct pci_bus *bus; struct device_node *node = hose->dn; int i, mode; - struct resource *res; DBG("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); @@ -375,12 +374,10 @@ void __devinit scan_phb(struct pci_controller *hose) pcibios_map_io_space(bus); /* Wire up PHB bus resources */ - if (hose->io_resource.flags) { - DBG("PCI: PHB IO resource = %016lx-%016lx [%lx]\n", - hose->io_resource.start, hose->io_resource.end, - hose->io_resource.flags); - bus->resource[0] = res = &hose->io_resource; - } + DBG("PCI: PHB IO resource = %016lx-%016lx [%lx]\n", + hose->io_resource.start, hose->io_resource.end, + hose->io_resource.flags); + bus->resource[0] = &hose->io_resource; for (i = 0; i < 3; ++i) { DBG("PCI: PHB MEM resource %d = %016lx-%016lx [%lx]\n", i, hose->mem_resources[i].start, diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 13ebeb2d71e..aa9ff35b0e6 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -59,6 +59,7 @@ extern void single_step_exception(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); EXPORT_SYMBOL(clear_pages); +EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 338950aeb6f..be35ffae10f 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -76,6 +76,8 @@ void smp_call_function_interrupt(void); int smt_enabled_at_boot = 1; +static int ipi_fail_ok; + static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; #ifdef CONFIG_PPC64 @@ -181,12 +183,13 @@ static struct call_data_struct { * <wait> If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <<func>> or are or have executed. + * <map> is a cpu map of the cpus to send IPI to. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, - int wait, cpumask_t map) +static int __smp_call_function_map(void (*func) (void *info), void *info, + int nonatomic, int wait, cpumask_t map) { struct call_data_struct data; int ret = -1, num_cpus; @@ -203,8 +206,6 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); - /* remove 'self' from the map */ if (cpu_isset(smp_processor_id(), map)) cpu_clear(smp_processor_id(), map); @@ -231,7 +232,8 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, printk("smp_call_function on cpu %d: other cpus not " "responding (%d)\n", smp_processor_id(), atomic_read(&data.started)); - debugger(NULL); + if (!ipi_fail_ok) + debugger(NULL); goto out; } } @@ -258,14 +260,18 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, out: call_data = NULL; HMT_medium(); - spin_unlock(&call_lock); return ret; } static int __smp_call_function(void (*func)(void *info), void *info, int nonatomic, int wait) { - return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map); + int ret; + spin_lock(&call_lock); + ret =__smp_call_function_map(func, info, nonatomic, wait, + cpu_online_map); + spin_unlock(&call_lock); + return ret; } int smp_call_function(void (*func) (void *info), void *info, int nonatomic, @@ -278,8 +284,8 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic, } EXPORT_SYMBOL(smp_call_function); -int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, - int wait) +int smp_call_function_single(int cpu, void (*func) (void *info), void *info, + int nonatomic, int wait) { cpumask_t map = CPU_MASK_NONE; int ret = 0; @@ -291,9 +297,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int return -EINVAL; cpu_set(cpu, map); - if (cpu != get_cpu()) - ret = smp_call_function_map(func,info,nonatomic,wait,map); - else { + if (cpu != get_cpu()) { + spin_lock(&call_lock); + ret = __smp_call_function_map(func, info, nonatomic, wait, map); + spin_unlock(&call_lock); + } else { local_irq_disable(); func(info); local_irq_enable(); @@ -305,7 +313,22 @@ EXPORT_SYMBOL(smp_call_function_single); void smp_send_stop(void) { - __smp_call_function(stop_this_cpu, NULL, 1, 0); + int nolock; + + /* It's OK to fail sending the IPI, since the alternative is to + * be stuck forever waiting on the other CPU to take the interrupt. + * + * It's better to at least continue and go through reboot, since this + * function is usually called at panic or reboot time in the first + * place. + */ + ipi_fail_ok = 1; + + /* Don't deadlock in case we got called through panic */ + nolock = !spin_trylock(&call_lock); + __smp_call_function_map(stop_this_cpu, NULL, 1, 0, cpu_online_map); + if (!nolock) + spin_unlock(&call_lock); } void smp_call_function_interrupt(void) diff --git a/arch/powerpc/kernel/systbl_chk.c b/arch/powerpc/kernel/systbl_chk.c index 77824d1cb15..238aa63ced8 100644 --- a/arch/powerpc/kernel/systbl_chk.c +++ b/arch/powerpc/kernel/systbl_chk.c @@ -6,7 +6,7 @@ * Unfortunately, we cannot check for the correct ordering of entries * using SYSX(). * - * Copyright © IBM Corporation + * Copyright © IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/arch/powerpc/kernel/systbl_chk.sh b/arch/powerpc/kernel/systbl_chk.sh index 367d208301d..19415e7674a 100644 --- a/arch/powerpc/kernel/systbl_chk.sh +++ b/arch/powerpc/kernel/systbl_chk.sh @@ -3,7 +3,7 @@ # Just process the CPP output from systbl_chk.c and complain # if anything is out of order. # -# Copyright © 2008 IBM Corporation +# Copyright © 2008 IBM Corporation # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 10dda224a36..7b251079926 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (notify_page_fault(regs)) return 0; - if (trap == 0x300) { - if (debugger_fault_handler(regs)) - return 0; - } + if (unlikely(debugger_fault_handler(regs))) + return 0; /* On a kernel SLB miss we can only check for a valid exception entry */ if (!user_mode(regs) && (address >= TASK_SIZE)) diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index bceb5e13da5..eb2a94b0dc4 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -310,8 +310,8 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz { struct page *page; int ret, i; - unsigned long reg, segments, pages_per_segment, ptab_size, n_pte_pages; - unsigned long xlate_base; + unsigned long reg, segments, pages_per_segment, ptab_size, stab_size, + n_pte_pages, xlate_base; unsigned int virq; if (cell_iommu_find_ioc(iommu->nid, &xlate_base)) @@ -328,7 +328,8 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz __FUNCTION__, iommu->nid, segments, pages_per_segment); /* set up the segment table */ - page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0); + stab_size = segments * sizeof(unsigned long); + page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(stab_size)); BUG_ON(!page); iommu->stab = page_address(page); clear_page(iommu->stab); @@ -490,15 +491,18 @@ static struct cbe_iommu *cell_iommu_for_node(int nid) return NULL; } +static unsigned long cell_dma_direct_offset; + static void cell_dma_dev_setup(struct device *dev) { struct iommu_window *window; struct cbe_iommu *iommu; struct dev_archdata *archdata = &dev->archdata; - /* If we run without iommu, no need to do anything */ - if (get_pci_dma_ops() == &dma_direct_ops) + if (get_pci_dma_ops() == &dma_direct_ops) { + archdata->dma_data = (void *)cell_dma_direct_offset; return; + } /* Current implementation uses the first window available in that * node's iommu. We -might- do something smarter later though it may @@ -654,7 +658,7 @@ static int __init cell_iommu_init_disabled(void) /* If we have no Axon, we set up the spider DMA magic offset */ if (of_find_node_by_name(NULL, "axon") == NULL) - dma_direct_offset = SPIDER_DMA_OFFSET; + cell_dma_direct_offset = SPIDER_DMA_OFFSET; /* Now we need to check to see where the memory is mapped * in PCI space. We assume that all busses use the same dma @@ -688,10 +692,13 @@ static int __init cell_iommu_init_disabled(void) return -ENODEV; } - dma_direct_offset += base; + cell_dma_direct_offset += base; + + if (cell_dma_direct_offset != 0) + ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup; printk("iommu: disabled, direct DMA offset is 0x%lx\n", - dma_direct_offset); + cell_dma_direct_offset); return 0; } diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c index 41e1e6f8e05..93b0efddd65 100644 --- a/arch/powerpc/platforms/celleb/iommu.c +++ b/arch/powerpc/platforms/celleb/iommu.c @@ -52,6 +52,8 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid, return 0; } +static unsigned long celleb_dma_direct_offset; + static void __init celleb_init_direct_mapping(void) { u64 lpar_addr, io_addr; @@ -69,7 +71,18 @@ static void __init celleb_init_direct_mapping(void) ioid, DMA_FLAGS); } - dma_direct_offset = dma_base; + celleb_dma_direct_offset = dma_base; +} + +static void celleb_dma_dev_setup(struct device *dev) +{ + dev->archdata.dma_ops = get_pci_dma_ops(); + dev->archdata.dma_data = (void *)celleb_dma_direct_offset; +} + +static void celleb_pci_dma_dev_setup(struct pci_dev *pdev) +{ + celleb_dma_dev_setup(&pdev->dev); } static int celleb_of_bus_notify(struct notifier_block *nb, @@ -81,7 +94,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb, if (action != BUS_NOTIFY_ADD_DEVICE) return 0; - dev->archdata.dma_ops = get_pci_dma_ops(); + celleb_dma_dev_setup(dev); return 0; } @@ -94,6 +107,7 @@ static int __init celleb_init_iommu(void) { celleb_init_direct_mapping(); set_pci_dma_ops(&dma_direct_ops); + ppc_md.pci_dma_dev_setup = celleb_pci_dma_dev_setup; bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); return 0; diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d51f83aeef7..609c46db4a1 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -354,7 +354,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, * mode as well. The same fixup must be done to the class-code property in * the IDE node /pci@80000000/ide@C,1 */ -static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) +static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) { u8 progif; struct pci_dev *viaisa; @@ -375,4 +375,4 @@ static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) pci_dev_put(viaisa); } -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 42a21bab76c..116babbaaf8 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -256,6 +256,57 @@ static void briq_restart(char *cmd) for(;;); } +/* + * Per default, input/output-device points to the keyboard/screen + * If no card is installed, the built-in serial port is used as a fallback. + * But unfortunately, the firmware does not connect /chosen/{stdin,stdout} + * the the built-in serial node. Instead, a /failsafe node is created. + */ +static void chrp_init_early(void) +{ + struct device_node *node; + const char *property; + + if (strstr(cmd_line, "console=")) + return; + /* find the boot console from /chosen/stdout */ + if (!of_chosen) + return; + node = of_find_node_by_path("/"); + if (!node) + return; + property = of_get_property(node, "model", NULL); + if (!property) + goto out_put; + if (strcmp(property, "Pegasos2")) + goto out_put; + /* this is a Pegasos2 */ + property = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (!property) + goto out_put; + of_node_put(node); + node = of_find_node_by_path(property); + if (!node) + return; + property = of_get_property(node, "device_type", NULL); + if (!property) + goto out_put; + if (strcmp(property, "serial")) + goto out_put; + /* + * The 9pin connector is either /failsafe + * or /pci@80000000/isa@C/serial@i2F8 + * The optional graphics card has also type 'serial' in VGA mode. + */ + property = of_get_property(node, "name", NULL); + if (!property) + goto out_put; + if (!strcmp(property, "failsafe") || !strcmp(property, "serial")) + add_preferred_console("ttyS", 0, NULL); +out_put: + of_node_put(node); +} + void __init chrp_setup_arch(void) { struct device_node *root = of_find_node_by_path("/"); @@ -599,6 +650,7 @@ define_machine(chrp) { .probe = chrp_probe, .setup_arch = chrp_setup_arch, .init = chrp_init2, + .init_early = chrp_init_early, .show_cpuinfo = chrp_show_cpuinfo, .init_IRQ = chrp_init_IRQ, .restart = rtas_restart, diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 298f1c9679f..a5f4e95dfc3 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -61,17 +61,6 @@ config PS3_DYNAMIC_DMA This support is mainly for Linux kernel development. If unsure, say N. -config PS3_USE_LPAR_ADDR - depends on PPC_PS3 && EXPERIMENTAL - bool "PS3 use lpar address space" - default y - help - This option is solely for experimentation by experts. Disables - translation of lpar addresses. SPE support currently won't work - without this set to y. - - If you have any doubt, choose the default y. - config PS3_VUART depends on PPC_PS3 tristate @@ -138,4 +127,17 @@ config PS3_FLASH be disabled on the kernel command line using "ps3flash=off", to not allocate this fixed buffer. +config PS3_LPM + tristate "PS3 Logical Performance Monitor support" + depends on PPC_PS3 + help + Include support for the PS3 Logical Performance Monitor. + + This support is required to use the logical performance monitor + of the PS3's LV1 hypervisor. + + If you intend to use the advanced performance monitoring and + profiling support of the Cell processor with programs like + oprofile and perfmon2, then say Y or M, otherwise say N. + endmenu diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index fd063fe0c9b..9d251d0ca8c 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/init.h> +#include <linux/reboot.h> #include <asm/firmware.h> #include <asm/lv1call.h> @@ -30,6 +31,89 @@ #include "platform.h" +static int __init ps3_register_lpm_devices(void) +{ + int result; + u64 tmp1; + u64 tmp2; + struct ps3_system_bus_device *dev; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->match_id = PS3_MATCH_ID_LPM; + dev->dev_type = PS3_DEVICE_TYPE_LPM; + + /* The current lpm driver only supports a single BE processor. */ + + result = ps3_repository_read_be_node_id(0, &dev->lpm.node_id); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_be_node_id failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + result = ps3_repository_read_lpm_privileges(dev->lpm.node_id, &tmp1, + &dev->lpm.rights); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_lpm_privleges failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + lv1_get_logical_partition_id(&tmp2); + + if (tmp1 != tmp2) { + pr_debug("%s:%d: wrong lpar\n", + __func__, __LINE__); + result = -ENODEV; + goto fail_rights; + } + + if (!(dev->lpm.rights & PS3_LPM_RIGHTS_USE_LPM)) { + pr_debug("%s:%d: don't have rights to use lpm\n", + __func__, __LINE__); + result = -EPERM; + goto fail_rights; + } + + pr_debug("%s:%d: pu_id %lu, rights %lu(%lxh)\n", + __func__, __LINE__, dev->lpm.pu_id, dev->lpm.rights, + dev->lpm.rights); + + result = ps3_repository_read_pu_id(0, &dev->lpm.pu_id); + + if (result) { + pr_debug("%s:%d: ps3_repository_read_pu_id failed \n", + __func__, __LINE__); + goto fail_read_repo; + } + + result = ps3_system_bus_device_register(dev); + + if (result) { + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + goto fail_register; + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + + +fail_register: +fail_rights: +fail_read_repo: + kfree(dev); + pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); + return result; +} + /** * ps3_setup_gelic_device - Setup and register a gelic device instance. * @@ -238,166 +322,6 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, return result; } -static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, - unsigned int timeout) -{ - int result = -1; - unsigned int retries = 0; - u64 status; - - for (retries = 0; retries < timeout; retries++) { - result = lv1_storage_check_async_status(dev_id, tag, &status); - if (!result) - break; - - msleep(1); - } - - if (result) - pr_debug("%s:%u: check_async_status: %s, status %lx\n", - __func__, __LINE__, ps3_result(result), status); - - return result; -} - -/** - * ps3_storage_wait_for_device - Wait for a storage device to become ready. - * @repo: The repository device to wait for. - * - * Uses the hypervisor's storage device notification mechanism to wait until - * a storage device is ready. The device notification mechanism uses a - * psuedo device (id = -1) to asynchronously notify the guest when storage - * devices become ready. The notification device has a block size of 512 - * bytes. - */ - -static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) -{ - int error = -ENODEV; - int result; - const u64 notification_dev_id = (u64)-1LL; - const unsigned int timeout = HZ; - u64 lpar; - u64 tag; - void *buf; - enum ps3_notify_type { - notify_device_ready = 0, - notify_region_probe = 1, - notify_region_update = 2, - }; - struct { - u64 operation_code; /* must be zero */ - u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ - } *notify_cmd; - struct { - u64 event_type; /* enum ps3_notify_type */ - u64 bus_id; - u64 dev_id; - u64 dev_type; - u64 dev_port; - } *notify_event; - - pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, - repo->dev_id, repo->dev_type); - - buf = kzalloc(512, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - lpar = ps3_mm_phys_to_lpar(__pa(buf)); - notify_cmd = buf; - notify_event = buf; - - result = lv1_open_device(repo->bus_id, notification_dev_id, 0); - if (result) { - printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, - __LINE__, ps3_result(result)); - goto fail_free; - } - - /* Setup and write the request for device notification. */ - - notify_cmd->operation_code = 0; /* must be zero */ - notify_cmd->event_mask = 1UL << notify_region_probe; - - result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, - &tag); - if (result) { - printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, - ps3_result(result)); - goto fail_close; - } - - /* Wait for the write completion */ - - result = ps3stor_wait_for_completion(notification_dev_id, tag, - timeout); - if (result) { - printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, - __LINE__, ps3_result(result)); - goto fail_close; - } - - /* Loop here processing the requested notification events. */ - - while (1) { - memset(notify_event, 0, sizeof(*notify_event)); - - result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, - lpar, &tag); - if (result) { - printk(KERN_ERR "%s:%u: write failed %s\n", __func__, - __LINE__, ps3_result(result)); - break; - } - - result = ps3stor_wait_for_completion(notification_dev_id, tag, - timeout); - if (result) { - printk(KERN_ERR "%s:%u: read not completed %s\n", - __func__, __LINE__, ps3_result(result)); - break; - } - - pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " - "port %lu\n", __func__, __LINE__, repo->bus_index, - repo->dev_index, repo->dev_type, - notify_event->event_type, notify_event->dev_port); - - if (notify_event->event_type != notify_region_probe || - notify_event->bus_id != repo->bus_id) { - pr_debug("%s:%u: bad notify_event: event %lu, " - "dev_id %lu, dev_type %lu\n", - __func__, __LINE__, notify_event->event_type, - notify_event->dev_id, notify_event->dev_type); - break; - } - - if (notify_event->dev_id == repo->dev_id && - notify_event->dev_type == repo->dev_type) { - pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, - __LINE__, repo->bus_index, repo->dev_index, - repo->dev_type); - error = 0; - break; - } - - if (notify_event->dev_id == repo->dev_id && - notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { - pr_debug("%s:%u: no access: dev_id %u\n", __func__, - __LINE__, repo->dev_id); - break; - } - } - -fail_close: - lv1_close_device(repo->bus_id, notification_dev_id); -fail_free: - kfree(buf); - pr_debug(" <- %s:%u\n", __func__, __LINE__); - return error; -} - static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, enum ps3_match_id match_id) { @@ -449,16 +373,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, goto fail_find_interrupt; } - /* FIXME: Arrange to only do this on a 'cold' boot */ - - result = ps3_storage_wait_for_device(repo); - if (result) { - printk(KERN_ERR "%s:%u: storage_notification failed %d\n", - __func__, __LINE__, result); - result = -ENODEV; - goto fail_probe_notification; - } - for (i = 0; i < num_regions; i++) { unsigned int id; u64 start, size; @@ -494,7 +408,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, fail_device_register: fail_read_region: -fail_probe_notification: fail_find_interrupt: kfree(p); fail_malloc: @@ -659,62 +572,268 @@ static int ps3_register_repository_device( return result; } +static void ps3_find_and_add_device(u64 bus_id, u64 dev_id) +{ + struct ps3_repository_device repo; + int res; + unsigned int retries; + unsigned long rem; + + /* + * On some firmware versions (e.g. 1.90), the device may not show up + * in the repository immediately + */ + for (retries = 0; retries < 10; retries++) { + res = ps3_repository_find_device_by_id(&repo, bus_id, dev_id); + if (!res) + goto found; + + rem = msleep_interruptible(100); + if (rem) + break; + } + pr_warning("%s:%u: device %lu:%lu not found\n", __func__, __LINE__, + bus_id, dev_id); + return; + +found: + if (retries) + pr_debug("%s:%u: device %lu:%lu found after %u retries\n", + __func__, __LINE__, bus_id, dev_id, retries); + + ps3_register_repository_device(&repo); + return; +} + +#define PS3_NOTIFICATION_DEV_ID ULONG_MAX +#define PS3_NOTIFICATION_INTERRUPT_ID 0 + +struct ps3_notification_device { + struct ps3_system_bus_device sbd; + spinlock_t lock; + u64 tag; + u64 lv1_status; + struct completion done; +}; + +enum ps3_notify_type { + notify_device_ready = 0, + notify_region_probe = 1, + notify_region_update = 2, +}; + +struct ps3_notify_cmd { + u64 operation_code; /* must be zero */ + u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ +}; + +struct ps3_notify_event { + u64 event_type; /* enum ps3_notify_type */ + u64 bus_id; + u64 dev_id; + u64 dev_type; + u64 dev_port; +}; + +static irqreturn_t ps3_notification_interrupt(int irq, void *data) +{ + struct ps3_notification_device *dev = data; + int res; + u64 tag, status; + + spin_lock(&dev->lock); + res = lv1_storage_get_async_status(PS3_NOTIFICATION_DEV_ID, &tag, + &status); + if (tag != dev->tag) + pr_err("%s:%u: tag mismatch, got %lx, expected %lx\n", + __func__, __LINE__, tag, dev->tag); + + if (res) { + pr_err("%s:%u: res %d status 0x%lx\n", __func__, __LINE__, res, + status); + } else { + pr_debug("%s:%u: completed, status 0x%lx\n", __func__, + __LINE__, status); + dev->lv1_status = status; + complete(&dev->done); + } + spin_unlock(&dev->lock); + return IRQ_HANDLED; +} + +static int ps3_notification_read_write(struct ps3_notification_device *dev, + u64 lpar, int write) +{ + const char *op = write ? "write" : "read"; + unsigned long flags; + int res; + + init_completion(&dev->done); + spin_lock_irqsave(&dev->lock, flags); + res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar, + &dev->tag) + : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar, + &dev->tag); + spin_unlock_irqrestore(&dev->lock, flags); + if (res) { + pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res); + return -EPERM; + } + pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op); + + res = wait_event_interruptible(dev->done.wait, + dev->done.done || kthread_should_stop()); + if (kthread_should_stop()) + res = -EINTR; + if (res) { + pr_debug("%s:%u: interrupted %s\n", __func__, __LINE__, op); + return res; + } + + if (dev->lv1_status) { + pr_err("%s:%u: %s not completed, status 0x%lx\n", __func__, + __LINE__, op, dev->lv1_status); + return -EIO; + } + pr_debug("%s:%u: notification %s completed\n", __func__, __LINE__, op); + + return 0; +} + +static struct task_struct *probe_task; + /** * ps3_probe_thread - Background repository probing at system startup. * * This implementation only supports background probing on a single bus. + * It uses the hypervisor's storage device notification mechanism to wait until + * a storage device is ready. The device notification mechanism uses a + * pseudo device to asynchronously notify the guest when storage devices become + * ready. The notification device has a block size of 512 bytes. */ static int ps3_probe_thread(void *data) { - struct ps3_repository_device *repo = data; - int result; - unsigned int ms = 250; + struct ps3_notification_device dev; + int res; + unsigned int irq; + u64 lpar; + void *buf; + struct ps3_notify_cmd *notify_cmd; + struct ps3_notify_event *notify_event; pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); + buf = kzalloc(512, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + lpar = ps3_mm_phys_to_lpar(__pa(buf)); + notify_cmd = buf; + notify_event = buf; + + /* dummy system bus device */ + dev.sbd.bus_id = (u64)data; + dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID; + dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID; + + res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0); + if (res) { + pr_err("%s:%u: lv1_open_device failed %s\n", __func__, + __LINE__, ps3_result(res)); + goto fail_free; + } + + res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY, + &irq); + if (res) { + pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n", + __func__, __LINE__, res); + goto fail_close_device; + } + + spin_lock_init(&dev.lock); + + res = request_irq(irq, ps3_notification_interrupt, IRQF_DISABLED, + "ps3_notification", &dev); + if (res) { + pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__, + res); + goto fail_sb_event_receive_port_destroy; + } + + /* Setup and write the request for device notification. */ + notify_cmd->operation_code = 0; /* must be zero */ + notify_cmd->event_mask = 1UL << notify_region_probe; + + res = ps3_notification_read_write(&dev, lpar, 1); + if (res) + goto fail_free_irq; + + /* Loop here processing the requested notification events. */ do { try_to_freeze(); - pr_debug("%s:%u: probing...\n", __func__, __LINE__); - - do { - result = ps3_repository_find_device(repo); - - if (result == -ENODEV) - pr_debug("%s:%u: nothing new\n", __func__, - __LINE__); - else if (result) - pr_debug("%s:%u: find device error.\n", - __func__, __LINE__); - else { - pr_debug("%s:%u: found device (%u:%u:%u)\n", - __func__, __LINE__, repo->bus_index, - repo->dev_index, repo->dev_type); - ps3_register_repository_device(repo); - ps3_repository_bump_device(repo); - ms = 250; - } - } while (!result); - - pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms); - - if ( ms > 60000) + memset(notify_event, 0, sizeof(*notify_event)); + + res = ps3_notification_read_write(&dev, lpar, 0); + if (res) break; - msleep_interruptible(ms); + pr_debug("%s:%u: notify event type 0x%lx bus id %lu dev id %lu" + " type %lu port %lu\n", __func__, __LINE__, + notify_event->event_type, notify_event->bus_id, + notify_event->dev_id, notify_event->dev_type, + notify_event->dev_port); - /* An exponential backoff. */ - ms <<= 1; + if (notify_event->event_type != notify_region_probe || + notify_event->bus_id != dev.sbd.bus_id) { + pr_warning("%s:%u: bad notify_event: event %lu, " + "dev_id %lu, dev_type %lu\n", + __func__, __LINE__, notify_event->event_type, + notify_event->dev_id, + notify_event->dev_type); + continue; + } + + ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id); } while (!kthread_should_stop()); +fail_free_irq: + free_irq(irq, &dev); +fail_sb_event_receive_port_destroy: + ps3_sb_event_receive_port_destroy(&dev.sbd, irq); +fail_close_device: + lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id); +fail_free: + kfree(buf); + + probe_task = NULL; + pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); return 0; } /** + * ps3_stop_probe_thread - Stops the background probe thread. + * + */ + +static int ps3_stop_probe_thread(struct notifier_block *nb, unsigned long code, + void *data) +{ + if (probe_task) + kthread_stop(probe_task); + return 0; +} + +static struct notifier_block nb = { + .notifier_call = ps3_stop_probe_thread +}; + +/** * ps3_start_probe_thread - Starts the background probe thread. * */ @@ -723,7 +842,7 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) { int result; struct task_struct *task; - static struct ps3_repository_device repo; /* must be static */ + struct ps3_repository_device repo; pr_debug(" -> %s:%d\n", __func__, __LINE__); @@ -746,7 +865,8 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) return -ENODEV; } - task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type); + task = kthread_run(ps3_probe_thread, (void *)repo.bus_id, + "ps3-probe-%u", bus_type); if (IS_ERR(task)) { result = PTR_ERR(task); @@ -755,6 +875,9 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) return result; } + probe_task = task; + register_reboot_notifier(&nb); + pr_debug(" <- %s:%d\n", __func__, __LINE__); return 0; } @@ -787,6 +910,8 @@ static int __init ps3_register_devices(void) ps3_register_sound_devices(); + ps3_register_lpm_devices(); + pr_debug(" <- %s:%d\n", __func__, __LINE__); return 0; } diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 7bb3e162097..68900476c84 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -36,11 +36,6 @@ #endif enum { -#if defined(CONFIG_PS3_USE_LPAR_ADDR) - USE_LPAR_ADDR = 1, -#else - USE_LPAR_ADDR = 0, -#endif #if defined(CONFIG_PS3_DYNAMIC_DMA) USE_DYNAMIC_DMA = 1, #else @@ -137,11 +132,8 @@ static struct map map; unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr) { BUG_ON(is_kernel_addr(phys_addr)); - if (USE_LPAR_ADDR) - return phys_addr; - else - return (phys_addr < map.rm.size || phys_addr >= map.total) - ? phys_addr : phys_addr + map.r1.offset; + return (phys_addr < map.rm.size || phys_addr >= map.total) + ? phys_addr : phys_addr + map.r1.offset; } EXPORT_SYMBOL(ps3_mm_phys_to_lpar); @@ -309,7 +301,7 @@ static int __init ps3_mm_add_memory(void) BUG_ON(!mem_init_done); - start_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; + start_addr = map.rm.size; start_pfn = start_addr >> PAGE_SHIFT; nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -359,7 +351,7 @@ static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, const char *func, int line) { - DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + DBG("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, r->dev->dev_id); DBG("%s:%d: page_size %u\n", func, line, r->page_size); DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); @@ -394,7 +386,7 @@ struct dma_chunk { static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, int line) { - DBG("%s:%d: r.dev %u:%u\n", func, line, + DBG("%s:%d: r.dev %lu:%lu\n", func, line, c->region->dev->bus_id, c->region->dev->dev_id); DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); @@ -658,7 +650,7 @@ static int dma_sb_region_create(struct ps3_dma_region *r) BUG_ON(!r); if (!r->dev->bus_id) { - pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, r->dev->bus_id, r->dev->dev_id); return 0; } @@ -724,7 +716,7 @@ static int dma_sb_region_free(struct ps3_dma_region *r) BUG_ON(!r); if (!r->dev->bus_id) { - pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, r->dev->bus_id, r->dev->dev_id); return 0; } @@ -1007,7 +999,7 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) if (r->offset + r->len > map.rm.size) { /* Map (part of) 2nd RAM chunk */ - virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; + virt_addr = map.rm.size; len = r->len; if (r->offset >= map.rm.size) virt_addr += r->offset - map.rm.size; diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 01f0c9506e1..235c13ebacd 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -89,13 +89,11 @@ enum ps3_dev_type { PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ PS3_DEV_TYPE_SB_GPIO = 6, PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ - PS3_DEV_TYPE_STOR_DUMMY = 32, - PS3_DEV_TYPE_NOACCESS = 255, }; int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, u64 *value); -int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); +int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id); int ps3_repository_read_bus_type(unsigned int bus_index, enum ps3_bus_type *bus_type); int ps3_repository_read_bus_num_dev(unsigned int bus_index, @@ -119,7 +117,7 @@ enum ps3_reg_type { int ps3_repository_read_dev_str(unsigned int bus_index, unsigned int dev_index, const char *dev_str, u64 *value); int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, - unsigned int *dev_id); + u64 *dev_id); int ps3_repository_read_dev_type(unsigned int bus_index, unsigned int dev_index, enum ps3_dev_type *dev_type); int ps3_repository_read_dev_intr(unsigned int bus_index, @@ -138,21 +136,17 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, /* repository bus enumerators */ struct ps3_repository_device { - enum ps3_bus_type bus_type; unsigned int bus_index; - unsigned int bus_id; - enum ps3_dev_type dev_type; unsigned int dev_index; - unsigned int dev_id; + enum ps3_bus_type bus_type; + enum ps3_dev_type dev_type; + u64 bus_id; + u64 dev_id; }; -static inline struct ps3_repository_device *ps3_repository_bump_device( - struct ps3_repository_device *repo) -{ - repo->dev_index++; - return repo; -} int ps3_repository_find_device(struct ps3_repository_device *repo); +int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, + u64 bus_id, u64 dev_id); int ps3_repository_find_devices(enum ps3_bus_type bus_type, int (*callback)(const struct ps3_repository_device *repo)); int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, @@ -186,10 +180,10 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, unsigned int dev_index, unsigned int region_index, unsigned int *region_id, u64 *region_start, u64 *region_size); -/* repository pu and memory info */ +/* repository logical pu and memory info */ -int ps3_repository_read_num_pu(unsigned int *num_pu); -int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); +int ps3_repository_read_num_pu(u64 *num_pu); +int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id); int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); int ps3_repository_read_region_total(u64 *region_total); @@ -200,9 +194,15 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, int ps3_repository_read_num_be(unsigned int *num_be); int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); +int ps3_repository_read_be_id(u64 node_id, u64 *be_id); int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); +/* repository performance monitor info */ + +int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, + u64 *rights); + /* repository 'Other OS' area */ int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 1c94824f7b6..22063adeb38 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -33,7 +33,7 @@ enum ps3_lpar_id { }; #define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__) -static void _dump_field(const char *hdr, u64 n, const char* func, int line) +static void _dump_field(const char *hdr, u64 n, const char *func, int line) { #if defined(DEBUG) char s[16]; @@ -50,8 +50,8 @@ static void _dump_field(const char *hdr, u64 n, const char* func, int line) #define dump_node_name(_a, _b, _c, _d, _e) \ _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__) -static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, - u64 n4, const char* func, int line) +static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, + u64 n4, const char *func, int line) { pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); _dump_field("n1: ", n1, func, line); @@ -63,7 +63,7 @@ static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, #define dump_node(_a, _b, _c, _d, _e, _f, _g) \ _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, - u64 v1, u64 v2, const char* func, int line) + u64 v1, u64 v2, const char *func, int line) { pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); _dump_field("n1: ", n1, func, line); @@ -165,21 +165,18 @@ int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, make_first_field("bus", bus_index), make_field(bus_str, 0), 0, 0, - value, 0); + value, NULL); } -int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id) +int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id) { int result; - u64 v1; - u64 v2; /* unused */ result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("id", 0), 0, 0, - &v1, &v2); - *bus_id = v1; + bus_id, NULL); return result; } @@ -193,7 +190,7 @@ int ps3_repository_read_bus_type(unsigned int bus_index, make_first_field("bus", bus_index), make_field("type", 0), 0, 0, - &v1, 0); + &v1, NULL); *bus_type = v1; return result; } @@ -208,7 +205,7 @@ int ps3_repository_read_bus_num_dev(unsigned int bus_index, make_first_field("bus", bus_index), make_field("num_dev", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_dev = v1; return result; } @@ -221,22 +218,20 @@ int ps3_repository_read_dev_str(unsigned int bus_index, make_field("dev", dev_index), make_field(dev_str, 0), 0, - value, 0); + value, NULL); } int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, - unsigned int *dev_id) + u64 *dev_id) { int result; - u64 v1; result = read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("id", 0), 0, - &v1, 0); - *dev_id = v1; + dev_id, NULL); return result; } @@ -251,14 +246,14 @@ int ps3_repository_read_dev_type(unsigned int bus_index, make_field("dev", dev_index), make_field("type", 0), 0, - &v1, 0); + &v1, NULL); *dev_type = v1; return result; } int ps3_repository_read_dev_intr(unsigned int bus_index, unsigned int dev_index, unsigned int intr_index, - enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id) + enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id) { int result; u64 v1; @@ -287,7 +282,7 @@ int ps3_repository_read_dev_reg_type(unsigned int bus_index, make_field("dev", dev_index), make_field("reg", reg_index), make_field("type", 0), - &v1, 0); + &v1, NULL); *reg_type = v1; return result; } @@ -332,7 +327,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) return result; } - pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", + pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %lu, num_dev %u\n", __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, num_dev); @@ -349,47 +344,95 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) return result; } - if (tmp.bus_type == PS3_BUS_TYPE_STORAGE) { - /* - * A storage device may show up in the repository before the - * hypervisor has finished probing its type and regions - */ - unsigned int num_regions; - - if (tmp.dev_type == PS3_DEV_TYPE_STOR_DUMMY) { - pr_debug("%s:%u storage device not ready\n", __func__, - __LINE__); - return -ENODEV; - } + result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, + &tmp.dev_id); - result = ps3_repository_read_stor_dev_num_regions(tmp.bus_index, - tmp.dev_index, - &num_regions); + if (result) { + pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, + __LINE__); + return result; + } + + pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %lu\n", + __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); + + *repo = tmp; + return 0; +} + +int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, + u64 bus_id, u64 dev_id) +{ + int result = -ENODEV; + struct ps3_repository_device tmp; + unsigned int num_dev; + + pr_debug(" -> %s:%u: find device by id %lu:%lu\n", __func__, __LINE__, + bus_id, dev_id); + + for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) { + result = ps3_repository_read_bus_id(tmp.bus_index, + &tmp.bus_id); if (result) { - pr_debug("%s:%d read_stor_dev_num_regions failed\n", - __func__, __LINE__); + pr_debug("%s:%u read_bus_id(%u) failed\n", __func__, + __LINE__, tmp.bus_index); return result; } - if (!num_regions) { - pr_debug("%s:%u storage device has no regions yet\n", - __func__, __LINE__); - return -ENODEV; - } + if (tmp.bus_id == bus_id) + goto found_bus; + + pr_debug("%s:%u: skip, bus_id %lu\n", __func__, __LINE__, + tmp.bus_id); } + pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); + return result; - result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, - &tmp.dev_id); +found_bus: + result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type); + if (result) { + pr_debug("%s:%u read_bus_type(%u) failed\n", __func__, + __LINE__, tmp.bus_index); + return result; + } + result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); if (result) { - pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, - __LINE__); + pr_debug("%s:%u read_bus_num_dev failed\n", __func__, + __LINE__); return result; } - pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", - __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); + for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) { + result = ps3_repository_read_dev_id(tmp.bus_index, + tmp.dev_index, + &tmp.dev_id); + if (result) { + pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__, + __LINE__, tmp.bus_index, tmp.dev_index); + return result; + } + if (tmp.dev_id == dev_id) + goto found_dev; + + pr_debug("%s:%u: skip, dev_id %lu\n", __func__, __LINE__, + tmp.dev_id); + } + pr_debug(" <- %s:%u: dev not found\n", __func__, __LINE__); + return result; + +found_dev: + result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, + &tmp.dev_type); + if (result) { + pr_debug("%s:%u read_dev_type failed\n", __func__, __LINE__); + return result; + } + + pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%lu:%lu)\n", + __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index, + tmp.dev_index, tmp.bus_id, tmp.dev_id); *repo = tmp; return 0; } @@ -402,50 +445,34 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); - for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { + repo.bus_type = bus_type; + result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); + if (result) { + pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); + return result; + } - result = ps3_repository_read_bus_type(repo.bus_index, - &repo.bus_type); + result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); + if (result) { + pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, + repo.bus_index); + return result; + } - if (result) { - pr_debug("%s:%d read_bus_type(%u) failed\n", - __func__, __LINE__, repo.bus_index); + for (repo.dev_index = 0; ; repo.dev_index++) { + result = ps3_repository_find_device(&repo); + if (result == -ENODEV) { + result = 0; + break; + } else if (result) break; - } - - if (repo.bus_type != bus_type) { - pr_debug("%s:%d: skip, bus_type %u\n", __func__, - __LINE__, repo.bus_type); - continue; - } - - result = ps3_repository_read_bus_id(repo.bus_index, - &repo.bus_id); + result = callback(&repo); if (result) { - pr_debug("%s:%d read_bus_id(%u) failed\n", - __func__, __LINE__, repo.bus_index); - continue; - } - - for (repo.dev_index = 0; ; repo.dev_index++) { - result = ps3_repository_find_device(&repo); - - if (result == -ENODEV) { - result = 0; - break; - } else if (result) - break; - - result = callback(&repo); - - if (result) { - pr_debug("%s:%d: abort at callback\n", __func__, - __LINE__); - break; - } + pr_debug("%s:%d: abort at callback\n", __func__, + __LINE__); + break; } - break; } pr_debug(" <- %s:%d\n", __func__, __LINE__); @@ -561,7 +588,7 @@ int ps3_repository_read_stor_dev_port(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("port", 0), - 0, port, 0); + 0, port, NULL); } int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, @@ -571,7 +598,7 @@ int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("blk_size", 0), - 0, blk_size, 0); + 0, blk_size, NULL); } int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, @@ -581,7 +608,7 @@ int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("n_blocks", 0), - 0, num_blocks, 0); + 0, num_blocks, NULL); } int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, @@ -594,7 +621,7 @@ int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, make_first_field("bus", bus_index), make_field("dev", dev_index), make_field("n_regs", 0), - 0, &v1, 0); + 0, &v1, NULL); *num_regions = v1; return result; } @@ -611,7 +638,7 @@ int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("id", 0), - &v1, 0); + &v1, NULL); *region_id = v1; return result; } @@ -624,7 +651,7 @@ int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("size", 0), - region_size, 0); + region_size, NULL); } int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, @@ -635,7 +662,7 @@ int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, make_field("dev", dev_index), make_field("region", region_index), make_field("start", 0), - region_start, 0); + region_start, NULL); } int ps3_repository_read_stor_dev_info(unsigned int bus_index, @@ -684,6 +711,35 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, return result; } +/** + * ps3_repository_read_num_pu - Number of logical PU processors for this lpar. + */ + +int ps3_repository_read_num_pu(u64 *num_pu) +{ + *num_pu = 0; + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("pun", 0), + 0, 0, + num_pu, NULL); +} + +/** + * ps3_repository_read_pu_id - Read the logical PU id. + * @pu_index: Zero based index. + * @pu_id: The logical PU id. + */ + +int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id) +{ + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("pu", pu_index), + 0, 0, + pu_id, NULL); +} + int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) { return read_node(PS3_LPAR_ID_CURRENT, @@ -691,7 +747,7 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) make_field("pu", 0), ppe_id, make_field("rm_size", 0), - rm_size, 0); + rm_size, NULL); } int ps3_repository_read_region_total(u64 *region_total) @@ -700,7 +756,7 @@ int ps3_repository_read_region_total(u64 *region_total) make_first_field("bi", 0), make_field("rgntotal", 0), 0, 0, - region_total, 0); + region_total, NULL); } /** @@ -736,7 +792,7 @@ int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved) make_first_field("bi", 0), make_field("spun", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_spu_reserved = v1; return result; } @@ -755,7 +811,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) make_first_field("bi", 0), make_field("spursvn", 0), 0, 0, - &v1, 0); + &v1, NULL); *num_resource_id = v1; return result; } @@ -768,7 +824,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) */ int ps3_repository_read_spu_resource_id(unsigned int res_index, - enum ps3_spu_resource_type* resource_type, unsigned int *resource_id) + enum ps3_spu_resource_type *resource_type, unsigned int *resource_id) { int result; u64 v1; @@ -785,14 +841,14 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index, return result; } -int ps3_repository_read_boot_dat_address(u64 *address) +static int ps3_repository_read_boot_dat_address(u64 *address) { return read_node(PS3_LPAR_ID_CURRENT, make_first_field("bi", 0), make_field("boot_dat", 0), make_field("address", 0), 0, - address, 0); + address, NULL); } int ps3_repository_read_boot_dat_size(unsigned int *size) @@ -805,7 +861,7 @@ int ps3_repository_read_boot_dat_size(unsigned int *size) make_field("boot_dat", 0), make_field("size", 0), 0, - &v1, 0); + &v1, NULL); *size = v1; return result; } @@ -820,7 +876,7 @@ int ps3_repository_read_vuart_av_port(unsigned int *port) make_field("vir_uart", 0), make_field("port", 0), make_field("avset", 0), - &v1, 0); + &v1, NULL); *port = v1; return result; } @@ -835,7 +891,7 @@ int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) make_field("vir_uart", 0), make_field("port", 0), make_field("sysmgr", 0), - &v1, 0); + &v1, NULL); *port = v1; return result; } @@ -856,6 +912,10 @@ int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size) : ps3_repository_read_boot_dat_size(size); } +/** + * ps3_repository_read_num_be - Number of physical BE processors in the system. + */ + int ps3_repository_read_num_be(unsigned int *num_be) { int result; @@ -866,11 +926,17 @@ int ps3_repository_read_num_be(unsigned int *num_be) 0, 0, 0, - &v1, 0); + &v1, NULL); *num_be = v1; return result; } +/** + * ps3_repository_read_be_node_id - Read the physical BE processor node id. + * @be_index: Zero based index. + * @node_id: The BE processor node id. + */ + int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) { return read_node(PS3_LPAR_ID_PME, @@ -878,7 +944,23 @@ int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) 0, 0, 0, - node_id, 0); + node_id, NULL); +} + +/** + * ps3_repository_read_be_id - Read the physical BE processor id. + * @node_id: The BE processor node id. + * @be_id: The BE processor id. + */ + +int ps3_repository_read_be_id(u64 node_id, u64 *be_id) +{ + return read_node(PS3_LPAR_ID_PME, + make_first_field("be", 0), + node_id, + 0, + 0, + be_id, NULL); } int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) @@ -888,7 +970,7 @@ int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) node_id, make_field("clock", 0), 0, - tb_freq, 0); + tb_freq, NULL); } int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) @@ -897,11 +979,29 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) u64 node_id; *tb_freq = 0; - result = ps3_repository_read_be_node_id(0, &node_id); + result = ps3_repository_read_be_node_id(be_index, &node_id); return result ? result : ps3_repository_read_tb_freq(node_id, tb_freq); } +int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, + u64 *rights) +{ + int result; + u64 node_id; + + *lpar = 0; + *rights = 0; + result = ps3_repository_read_be_node_id(be_index, &node_id); + return result ? result + : read_node(PS3_LPAR_ID_PME, + make_first_field("be", 0), + node_id, + make_field("lpm", 0), + make_field("priv", 0), + lpar, rights); +} + #if defined(DEBUG) int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) @@ -1034,7 +1134,7 @@ static int dump_device_info(struct ps3_repository_device *repo, continue; } - pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, + pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__, __LINE__, repo->bus_index, repo->dev_index, repo->dev_type, repo->dev_id); @@ -1091,7 +1191,7 @@ int ps3_repository_dump_bus_info(void) continue; } - pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", + pr_debug("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", __func__, __LINE__, repo.bus_index, repo.bus_type, repo.bus_id, num_dev); diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6405f4a3676..43c493fca2d 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -42,8 +42,8 @@ struct { int gpu; } static usage_hack; -static int ps3_is_device(struct ps3_system_bus_device *dev, - unsigned int bus_id, unsigned int dev_id) +static int ps3_is_device(struct ps3_system_bus_device *dev, u64 bus_id, + u64 dev_id) { return dev->bus_id == bus_id && dev->dev_id == dev_id; } @@ -182,8 +182,8 @@ int ps3_open_hv_device(struct ps3_system_bus_device *dev) case PS3_MATCH_ID_SYSTEM_MANAGER: pr_debug("%s:%d: unsupported match_id: %u\n", __func__, __LINE__, dev->match_id); - pr_debug("%s:%d: bus_id: %u\n", __func__, - __LINE__, dev->bus_id); + pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, + dev->bus_id); BUG(); return -EINVAL; @@ -220,8 +220,8 @@ int ps3_close_hv_device(struct ps3_system_bus_device *dev) case PS3_MATCH_ID_SYSTEM_MANAGER: pr_debug("%s:%d: unsupported match_id: %u\n", __func__, __LINE__, dev->match_id); - pr_debug("%s:%d: bus_id: %u\n", __func__, - __LINE__, dev->bus_id); + pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, + dev->bus_id); BUG(); return -EINVAL; @@ -240,7 +240,7 @@ EXPORT_SYMBOL_GPL(ps3_close_hv_device); static void _dump_mmio_region(const struct ps3_mmio_region* r, const char* func, int line) { - pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + pr_debug("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, r->dev->dev_id); pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); pr_debug("%s:%d: len %lxh\n", func, line, r->len); @@ -715,6 +715,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) static unsigned int dev_ioc0_count; static unsigned int dev_sb_count; static unsigned int dev_vuart_count; + static unsigned int dev_lpm_count; if (!dev->core.parent) dev->core.parent = &ps3_system_bus; @@ -737,6 +738,10 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", ++dev_vuart_count); break; + case PS3_DEVICE_TYPE_LPM: + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), + "lpm_%02x", ++dev_lpm_count); + break; default: BUG(); }; diff --git a/arch/powerpc/xmon/setjmp.S b/arch/powerpc/xmon/setjmp.S index 96a91f10e2e..04c0b305ad4 100644 --- a/arch/powerpc/xmon/setjmp.S +++ b/arch/powerpc/xmon/setjmp.S @@ -12,67 +12,6 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> -_GLOBAL(xmon_setjmp) - mflr r0 - PPC_STL r0,0(r3) - PPC_STL r1,SZL(r3) - PPC_STL r2,2*SZL(r3) - mfcr r0 - PPC_STL r0,3*SZL(r3) - PPC_STL r13,4*SZL(r3) - PPC_STL r14,5*SZL(r3) - PPC_STL r15,6*SZL(r3) - PPC_STL r16,7*SZL(r3) - PPC_STL r17,8*SZL(r3) - PPC_STL r18,9*SZL(r3) - PPC_STL r19,10*SZL(r3) - PPC_STL r20,11*SZL(r3) - PPC_STL r21,12*SZL(r3) - PPC_STL r22,13*SZL(r3) - PPC_STL r23,14*SZL(r3) - PPC_STL r24,15*SZL(r3) - PPC_STL r25,16*SZL(r3) - PPC_STL r26,17*SZL(r3) - PPC_STL r27,18*SZL(r3) - PPC_STL r28,19*SZL(r3) - PPC_STL r29,20*SZL(r3) - PPC_STL r30,21*SZL(r3) - PPC_STL r31,22*SZL(r3) - li r3,0 - blr - -_GLOBAL(xmon_longjmp) - PPC_LCMPI r4,0 - bne 1f - li r4,1 -1: PPC_LL r13,4*SZL(r3) - PPC_LL r14,5*SZL(r3) - PPC_LL r15,6*SZL(r3) - PPC_LL r16,7*SZL(r3) - PPC_LL r17,8*SZL(r3) - PPC_LL r18,9*SZL(r3) - PPC_LL r19,10*SZL(r3) - PPC_LL r20,11*SZL(r3) - PPC_LL r21,12*SZL(r3) - PPC_LL r22,13*SZL(r3) - PPC_LL r23,14*SZL(r3) - PPC_LL r24,15*SZL(r3) - PPC_LL r25,16*SZL(r3) - PPC_LL r26,17*SZL(r3) - PPC_LL r27,18*SZL(r3) - PPC_LL r28,19*SZL(r3) - PPC_LL r29,20*SZL(r3) - PPC_LL r30,21*SZL(r3) - PPC_LL r31,22*SZL(r3) - PPC_LL r0,3*SZL(r3) - mtcrf 0x38,r0 - PPC_LL r0,0(r3) - PPC_LL r1,SZL(r3) - PPC_LL r2,2*SZL(r3) - mtlr r0 - mr r3,r4 - blr - /* * Grab the register values as they are now. * This won't do a particularily good job because we really diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 865e36751f2..a34172ddc46 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -40,6 +40,7 @@ #include <asm/spu.h> #include <asm/spu_priv1.h> #include <asm/firmware.h> +#include <asm/setjmp.h> #ifdef CONFIG_PPC64 #include <asm/hvcall.h> @@ -71,12 +72,9 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; -#define JMP_BUF_LEN 23 static long bus_error_jmp[JMP_BUF_LEN]; static int catch_memory_errors; static long *xmon_fault_jmp[NR_CPUS]; -#define setjmp xmon_setjmp -#define longjmp xmon_longjmp /* Breakpoint stuff */ struct bpt { @@ -162,8 +160,6 @@ int xmon_no_auto_backtrace; extern void xmon_enter(void); extern void xmon_leave(void); -extern long setjmp(long *); -extern void longjmp(long *, long); extern void xmon_save_regs(struct pt_regs *); #ifdef CONFIG_PPC64 |