Merge branch 'for-2.6.25' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
authorPaul Mackerras <paulus@samba.org>
Sat, 26 Jan 2008 04:30:35 +0000 (15:30 +1100)
committerPaul Mackerras <paulus@samba.org>
Sat, 26 Jan 2008 04:30:35 +0000 (15:30 +1100)
34 files changed:
arch/powerpc/configs/ps3_defconfig
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/dma_64.c
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/misc.S
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/systbl_chk.c
arch/powerpc/kernel/systbl_chk.sh
arch/powerpc/mm/fault.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/celleb/iommu.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/ps3/device-init.c
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/repository.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/xmon/setjmp.S
arch/powerpc/xmon/xmon.c
drivers/net/ps3_gelic_net.c
drivers/ps3/Makefile
drivers/ps3/ps3-lpm.c [new file with mode: 0644]
drivers/ps3/ps3-sys-manager.c
drivers/ps3/ps3-vuart.c
include/asm-powerpc/dma-mapping.h
include/asm-powerpc/kexec.h
include/asm-powerpc/ps3.h
include/asm-powerpc/reg.h
include/asm-powerpc/setjmp.h [new file with mode: 0644]
include/asm-powerpc/sparsemem.h

index 0b5469fb6e0fa9b65f36ef44bab25c331f5eaa08..7994955c29d324ba4e58b6d01acee6bb247bb620 100644 (file)
@@ -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
 
index 77c749a1337818190d56d9bbf04dcf36864951b8..571132ed12c1e4f74961eef16815533fa78c8351 100644 (file)
@@ -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
index 14206e3f0819a963d65fc5e6d3f26846b154f336..84239076a5b8e8092e7ad2d607ba16b0e0cff7a9 100644 (file)
@@ -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;
        }
 
index fd5ae8d17c96e2d586c03e75f8e6f6d520283629..2f50bb5d00f936e6f55c4dc5c41b10b0182a9c19 100644 (file)
@@ -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);
 
index 74ce0c7a7b1e7f481828f451ef478719d611c0b8..7b91602206985b0bf23a9b530f937b2b954f7fdb 100644 (file)
@@ -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
index 1930f393d01c9275a87025f0fcd0f76a5dcdec5b..52750745edfde77b8fa8f79f612b8cb892728db7 100644 (file)
@@ -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,
index 13ebeb2d71e629c0b53afe86fd52ab275a88a28e..aa9ff35b0e630e86d04ef5611188570c5ed5b958 100644 (file)
@@ -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);
index 338950aeb6f6e3f3d19511e87cc992ad4e3535e4..be35ffae10f0726b5e2ac3746b80f464f976222c 100644 (file)
@@ -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)
index 77824d1cb1501e5aace91bcba6527496f285a4ed..238aa63ced8f97270a764757c77ddc3ccca17584 100644 (file)
@@ -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
index 367d208301d2dd760523c745414fe700d1e56c6a..19415e7674a50fb21091e485b22703242835513b 100644 (file)
@@ -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
index 10dda224a3611128913cca2357affd92ca7ff48a..7b2510799266654e4fb8ec1283adfbbbfb159158 100644 (file)
@@ -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))
index bceb5e13da5c7d0cf502eed6aee71fde4ae9a152..eb2a94b0dc4cb9917ed95226f629583df61e238c 100644 (file)
@@ -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;
 }
index 41e1e6f8e05915fa14b558886ab9a4d2b58b6637..93b0efddd658dfef78de8b18abfe3bd58063dab2 100644 (file)
@@ -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;
index d51f83aeef7ff2d9c6f6ae5914d52298d02372e3..609c46db4a1bc36e493250ee9231697656bd4da8 100644 (file)
@@ -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);
index 42a21bab76c860e51f97fdee3b6b32317f37e803..116babbaaf81f6ea77c6e405da8b71699f187bfd 100644 (file)
@@ -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,
index 298f1c9679fbd0b3b3e9d16b964c746230a0515c..a5f4e95dfc3d277732767f2c887ac56bd0e56187 100644 (file)
@@ -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
index fd063fe0c9b382f91db12456d596e86dbf7f0ac7..9d251d0ca8c6786673a5ed0be141288b9dbf9c2d 100644 (file)
@@ -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>
 
 #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,61 +572,267 @@ 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;
 }
index 7bb3e1620974d0b14c076ded52205b0973474233..68900476c8425881b0514f0f077e302ea4b10e88 100644 (file)
 #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;
index 01f0c9506e11efec1ea93777abf385b24a8a61c0..235c13ebacd9a459b2a584de9d536828e945c690 100644 (file)
@@ -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);
index 1c94824f7b6311c632440ceaffbd78d453a8aa90..22063adeb38be567e844482877251f89cf0d4fe6 100644 (file)
@@ -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 charfunc, 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 charfunc, 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 charfunc, 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 intinterrupt_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_typeresource_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);
 
index 6405f4a36763b00df384c1db6153e6125db0d822..43c493fca2d03811c6c2c619e411d1a186bc38d2 100644 (file)
@@ -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();
        };
index 96a91f10e2ec52ed5e05f3cdda3841e37c5fd61a..04c0b305ad4ad65ba5722c7c0813be912ef0fdb6 100644 (file)
 #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
index 865e36751f21c434d107e8d4b2dbadcce232e56d..a34172ddc4683064c818608b86fb506ba59e4c2f 100644 (file)
@@ -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
index 0a42bf5174658fa71b050bef8225597a04e531b3..055af081e0272fe7dae08eb965ba5e7d0c420bff 100644 (file)
@@ -58,11 +58,11 @@ static inline struct device *ctodev(struct gelic_net_card *card)
 {
        return &card->dev->core;
 }
-static inline unsigned int bus_id(struct gelic_net_card *card)
+static inline u64 bus_id(struct gelic_net_card *card)
 {
        return card->dev->bus_id;
 }
-static inline unsigned int dev_id(struct gelic_net_card *card)
+static inline u64 dev_id(struct gelic_net_card *card)
 {
        return card->dev->dev_id;
 }
index 1f5a2d33bf5b5a7d8407d9e8a04b8288c01f6d06..ccea15c11c195af85e42a0e1bc1918e4c2414b7b 100644 (file)
@@ -4,3 +4,4 @@ ps3av_mod-objs          += ps3av.o ps3av_cmd.o
 obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
 obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
 obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
+obj-$(CONFIG_PS3_LPM) += ps3-lpm.o
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
new file mode 100644 (file)
index 0000000..4c06654
--- /dev/null
@@ -0,0 +1,1248 @@
+/*
+ * PS3 Logical Performance Monitor.
+ *
+ *  Copyright (C) 2007 Sony Computer Entertainment Inc.
+ *  Copyright 2007 Sony 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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+#include <asm/cell-pmu.h>
+
+
+/* BOOKMARK tag macros */
+#define PS3_PM_BOOKMARK_START                    0x8000000000000000ULL
+#define PS3_PM_BOOKMARK_STOP                     0x4000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_KERNEL               0x1000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_USER                 0x3000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_HI              0xF000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_LO              0x0F00000000000000ULL
+
+/* CBE PM CONTROL register macros */
+#define PS3_PM_CONTROL_PPU_TH0_BOOKMARK          0x00001000
+#define PS3_PM_CONTROL_PPU_TH1_BOOKMARK          0x00000800
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_MASK       0x000C0000
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_PROBLEM    0x00080000
+#define PS3_WRITE_PM_MASK                        0xFFFFFFFFFFFFFFFFULL
+
+/* CBE PM START STOP register macros */
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START 0x02000000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START 0x01000000
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP  0x00020000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP  0x00010000
+#define PS3_PM_START_STOP_START_MASK             0xFF000000
+#define PS3_PM_START_STOP_STOP_MASK              0x00FF0000
+
+/* CBE PM COUNTER register macres */
+#define PS3_PM_COUNTER_MASK_HI                   0xFFFFFFFF00000000ULL
+#define PS3_PM_COUNTER_MASK_LO                   0x00000000FFFFFFFFULL
+
+/* BASE SIGNAL GROUP NUMBER macros */
+#define PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER  0
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER1      6
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER2      7
+#define PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER  7
+#define PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER  15
+#define PM_SPU_TRIGGER_SIGNAL_GROUP_NUMBER   17
+#define PM_SPU_EVENT_SIGNAL_GROUP_NUMBER     18
+#define PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER  18
+#define PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER  24
+#define PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER  49
+#define PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER  52
+#define PM_SIG_GROUP_SPU                     41
+#define PM_SIG_GROUP_SPU_TRIGGER             42
+#define PM_SIG_GROUP_SPU_EVENT               43
+#define PM_SIG_GROUP_MFC_MAX                 60
+
+/**
+ * struct ps3_lpm_shadow_regs - Performance monitor shadow registers.
+ *
+ * @pm_control: Shadow of the processor's pm_control register.
+ * @pm_start_stop: Shadow of the processor's pm_start_stop register.
+ * @pm_interval: Shadow of the processor's pm_interval register.
+ * @group_control: Shadow of the processor's group_control register.
+ * @debug_bus_control: Shadow of the processor's debug_bus_control register.
+ *
+ * The logical performance monitor provides a write-only interface to
+ * these processor registers.  These shadow variables cache the processor
+ * register values for reading.
+ *
+ * The initial value of the shadow registers at lpm creation is
+ * PS3_LPM_SHADOW_REG_INIT.
+ */
+
+struct ps3_lpm_shadow_regs {
+       u64 pm_control;
+       u64 pm_start_stop;
+       u64 pm_interval;
+       u64 group_control;
+       u64 debug_bus_control;
+};
+
+#define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
+
+/**
+ * struct ps3_lpm_priv - Private lpm device data.
+ *
+ * @open: An atomic variable indicating the lpm driver has been opened.
+ * @rights: The lpm rigths granted by the system policy module.  A logical
+ *  OR of enum ps3_lpm_rights.
+ * @node_id: The node id of a BE prosessor whose performance monitor this
+ *  lpar has the right to use.
+ * @pu_id: The lv1 id of the logical PU.
+ * @lpm_id: The lv1 id of this lpm instance.
+ * @outlet_id: The outlet created by lv1 for this lpm instance.
+ * @tb_count: The number of bytes of data held in the lv1 trace buffer.
+ * @tb_cache: Kernel buffer to receive the data from the lv1 trace buffer.
+ *  Must be 128 byte aligned.
+ * @tb_cache_size: Size of the kernel @tb_cache buffer.  Must be 128 byte
+ *  aligned.
+ * @tb_cache_internal: An unaligned buffer allocated by this driver to be
+ *  used for the trace buffer cache when ps3_lpm_open() is called with a
+ *  NULL tb_cache argument.  Otherwise unused.
+ * @shadow: Processor register shadow of type struct ps3_lpm_shadow_regs.
+ * @sbd: The struct ps3_system_bus_device attached to this driver.
+ *
+ * The trace buffer is a buffer allocated and used internally to the lv1
+ * hypervisor to collect trace data.  The trace buffer cache is a guest
+ * buffer that accepts the trace data from the trace buffer.
+ */
+
+struct ps3_lpm_priv {
+       atomic_t open;
+       u64 rights;
+       u64 node_id;
+       u64 pu_id;
+       u64 lpm_id;
+       u64 outlet_id;
+       u64 tb_count;
+       void *tb_cache;
+       u64 tb_cache_size;
+       void *tb_cache_internal;
+       struct ps3_lpm_shadow_regs shadow;
+       struct ps3_system_bus_device *sbd;
+};
+
+enum {
+       PS3_LPM_DEFAULT_TB_CACHE_SIZE = 0x4000,
+};
+
+/**
+ * lpm_priv - Static instance of the lpm data.
+ *
+ * Since the exported routines don't support the notion of a device
+ * instance we need to hold the instance in this static variable
+ * and then only allow at most one instance at a time to be created.
+ */
+
+static struct ps3_lpm_priv *lpm_priv;
+
+static struct device *sbd_core(void)
+{
+       BUG_ON(!lpm_priv || !lpm_priv->sbd);
+       return &lpm_priv->sbd->core;
+}
+
+/**
+ * use_start_stop_bookmark - Enable the PPU bookmark trace.
+ *
+ * And it enables PPU bookmark triggers ONLY if the other triggers are not set.
+ * The start/stop bookmarks are inserted at ps3_enable_pm() and ps3_disable_pm()
+ * to start/stop LPM.
+ *
+ * Used to get good quality of the performance counter.
+ */
+
+enum {use_start_stop_bookmark = 1,};
+
+void ps3_set_bookmark(u64 bookmark)
+{
+       /*
+        * As per the PPE book IV, to avoid bookmark loss there must
+        * not be a traced branch within 10 cycles of setting the
+        * SPRN_BKMK register.  The actual text is unclear if 'within'
+        * includes cycles before the call.
+        */
+
+       asm volatile("or 29, 29, 29;"); /* db10cyc */
+       mtspr(SPRN_BKMK, bookmark);
+       asm volatile("or 29, 29, 29;"); /* db10cyc */
+}
+EXPORT_SYMBOL_GPL(ps3_set_bookmark);
+
+void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
+{
+       u64 bookmark;
+
+       bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
+               PS3_PM_BOOKMARK_TAG_KERNEL;
+       bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
+               (incident << 48) | (th_id << 32) | bookmark;
+       ps3_set_bookmark(bookmark);
+}
+EXPORT_SYMBOL_GPL(ps3_set_pm_bookmark);
+
+/**
+ * ps3_read_phys_ctr - Read physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr)
+{
+       int result;
+       u64 counter0415;
+       u64 counter2637;
+
+       if (phys_ctr >= NR_PHYS_CTRS) {
+               dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+                       __LINE__, phys_ctr);
+               return 0;
+       }
+
+       result = lv1_set_lpm_counter(lpm_priv->lpm_id, 0, 0, 0, 0, &counter0415,
+                                    &counter2637);
+       if (result) {
+               dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+                       "phys_ctr %u, %s\n", __func__, __LINE__, phys_ctr,
+                       ps3_result(result));
+               return 0;
+       }
+
+       switch (phys_ctr) {
+       case 0:
+               return counter0415 >> 32;
+       case 1:
+               return counter0415 & PS3_PM_COUNTER_MASK_LO;
+       case 2:
+               return counter2637 >> 32;
+       case 3:
+               return counter2637 & PS3_PM_COUNTER_MASK_LO;
+       default:
+               BUG();
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_phys_ctr);
+
+/**
+ * ps3_write_phys_ctr - Write physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
+{
+       u64 counter0415;
+       u64 counter0415_mask;
+       u64 counter2637;
+       u64 counter2637_mask;
+       int result;
+
+       if (phys_ctr >= NR_PHYS_CTRS) {
+               dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+                       __LINE__, phys_ctr);
+               return;
+       }
+
+       switch (phys_ctr) {
+       case 0:
+               counter0415 = (u64)val << 32;
+               counter0415_mask = PS3_PM_COUNTER_MASK_HI;
+               counter2637 = 0x0;
+               counter2637_mask = 0x0;
+               break;
+       case 1:
+               counter0415 = (u64)val;
+               counter0415_mask = PS3_PM_COUNTER_MASK_LO;
+               counter2637 = 0x0;
+               counter2637_mask = 0x0;
+               break;
+       case 2:
+               counter0415 = 0x0;
+               counter0415_mask = 0x0;
+               counter2637 = (u64)val << 32;
+               counter2637_mask = PS3_PM_COUNTER_MASK_HI;
+               break;
+       case 3:
+               counter0415 = 0x0;
+               counter0415_mask = 0x0;
+               counter2637 = (u64)val;
+               counter2637_mask = PS3_PM_COUNTER_MASK_LO;
+               break;
+       default:
+               BUG();
+       }
+
+       result = lv1_set_lpm_counter(lpm_priv->lpm_id,
+                                    counter0415, counter0415_mask,
+                                    counter2637, counter2637_mask,
+                                    &counter0415, &counter2637);
+       if (result)
+               dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+                       "phys_ctr %u, val %u, %s\n", __func__, __LINE__,
+                       phys_ctr, val, ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_phys_ctr);
+
+/**
+ * ps3_read_ctr - Read counter.
+ *
+ * Read 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+u32 ps3_read_ctr(u32 cpu, u32 ctr)
+{
+       u32 val;
+       u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+       val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+       if (ps3_get_ctr_size(cpu, phys_ctr) == 16)
+               val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(ps3_read_ctr);
+
+/**
+ * ps3_write_ctr - Write counter.
+ *
+ * Write 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+void ps3_write_ctr(u32 cpu, u32 ctr, u32 val)
+{
+       u32 phys_ctr;
+       u32 phys_val;
+
+       phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+       if (ps3_get_ctr_size(cpu, phys_ctr) == 16) {
+               phys_val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+               if (ctr < NR_PHYS_CTRS)
+                       val = (val << 16) | (phys_val & 0xffff);
+               else
+                       val = (val & 0xffff) | (phys_val & 0xffff0000);
+       }
+
+       ps3_write_phys_ctr(cpu, phys_ctr, val);
+}
+EXPORT_SYMBOL_GPL(ps3_write_ctr);
+
+/**
+ * ps3_read_pm07_control - Read counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+u32 ps3_read_pm07_control(u32 cpu, u32 ctr)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm07_control);
+
+/**
+ * ps3_write_pm07_control - Write counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val)
+{
+       int result;
+       static const u64 mask = 0xFFFFFFFFFFFFFFFFULL;
+       u64 old_value;
+
+       if (ctr >= NR_CTRS) {
+               dev_dbg(sbd_core(), "%s:%u: ctr too big: %u\n", __func__,
+                       __LINE__, ctr);
+               return;
+       }
+
+       result = lv1_set_lpm_counter_control(lpm_priv->lpm_id, ctr, val, mask,
+                                            &old_value);
+       if (result)
+               dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter_control "
+                       "failed: ctr %u, %s\n", __func__, __LINE__, ctr,
+                       ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm07_control);
+
+/**
+ * ps3_read_pm - Read Other LPM control registers.
+ */
+
+u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg)
+{
+       int result = 0;
+       u64 val = 0;
+
+       switch (reg) {
+       case pm_control:
+               return lpm_priv->shadow.pm_control;
+       case trace_address:
+               return CBE_PM_TRACE_BUF_EMPTY;
+       case pm_start_stop:
+               return lpm_priv->shadow.pm_start_stop;
+       case pm_interval:
+               return lpm_priv->shadow.pm_interval;
+       case group_control:
+               return lpm_priv->shadow.group_control;
+       case debug_bus_control:
+               return lpm_priv->shadow.debug_bus_control;
+       case pm_status:
+               result = lv1_get_lpm_interrupt_status(lpm_priv->lpm_id,
+                                                     &val);
+               if (result) {
+                       val = 0;
+                       dev_dbg(sbd_core(), "%s:%u: lv1 get_lpm_status failed: "
+                               "reg %u, %s\n", __func__, __LINE__, reg,
+                               ps3_result(result));
+               }
+               return (u32)val;
+       case ext_tr_timer:
+               return 0;
+       default:
+               dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+                       __LINE__, reg);
+               BUG();
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm);
+
+/**
+ * ps3_write_pm - Write Other LPM control registers.
+ */
+
+void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
+{
+       int result = 0;
+       u64 dummy;
+
+       switch (reg) {
+       case group_control:
+               if (val != lpm_priv->shadow.group_control)
+                       result = lv1_set_lpm_group_control(lpm_priv->lpm_id,
+                                                          val,
+                                                          PS3_WRITE_PM_MASK,
+                                                          &dummy);
+               lpm_priv->shadow.group_control = val;
+               break;
+       case debug_bus_control:
+               if (val != lpm_priv->shadow.debug_bus_control)
+                       result = lv1_set_lpm_debug_bus_control(lpm_priv->lpm_id,
+                                                             val,
+                                                             PS3_WRITE_PM_MASK,
+                                                             &dummy);
+               lpm_priv->shadow.debug_bus_control = val;
+               break;
+       case pm_control:
+               if (use_start_stop_bookmark)
+                       val |= (PS3_PM_CONTROL_PPU_TH0_BOOKMARK |
+                               PS3_PM_CONTROL_PPU_TH1_BOOKMARK);
+               if (val != lpm_priv->shadow.pm_control)
+                       result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
+                                                            val,
+                                                            PS3_WRITE_PM_MASK,
+                                                            0, 0, &dummy,
+                                                            &dummy);
+               lpm_priv->shadow.pm_control = val;
+               break;
+       case pm_interval:
+               if (val != lpm_priv->shadow.pm_interval)
+                       result = lv1_set_lpm_interval(lpm_priv->lpm_id, val,
+                                                  PS3_WRITE_PM_MASK, &dummy);
+               lpm_priv->shadow.pm_interval = val;
+               break;
+       case pm_start_stop:
+               if (val != lpm_priv->shadow.pm_start_stop)
+                       result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+                                                            val,
+                                                            PS3_WRITE_PM_MASK,
+                                                            &dummy);
+               lpm_priv->shadow.pm_start_stop = val;
+               break;
+       case trace_address:
+       case ext_tr_timer:
+       case pm_status:
+               break;
+       default:
+               dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+                       __LINE__, reg);
+               BUG();
+               break;
+       }
+
+       if (result)
+               dev_err(sbd_core(), "%s:%u: lv1 set_control failed: "
+                       "reg %u, %s\n", __func__, __LINE__, reg,
+                       ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm);
+
+/**
+ * ps3_get_ctr_size - Get the size of a physical counter.
+ *
+ * Returns either 16 or 32.
+ */
+
+u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr)
+{
+       u32 pm_ctrl;
+
+       if (phys_ctr >= NR_PHYS_CTRS) {
+               dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+                       __LINE__, phys_ctr);
+               return 0;
+       }
+
+       pm_ctrl = ps3_read_pm(cpu, pm_control);
+       return (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
+}
+EXPORT_SYMBOL_GPL(ps3_get_ctr_size);
+
+/**
+ * ps3_set_ctr_size - Set the size of a physical counter to 16 or 32 bits.
+ */
+
+void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
+{
+       u32 pm_ctrl;
+
+       if (phys_ctr >= NR_PHYS_CTRS) {
+               dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+                       __LINE__, phys_ctr);
+               return;
+       }
+
+       pm_ctrl = ps3_read_pm(cpu, pm_control);
+
+       switch (ctr_size) {
+       case 16:
+               pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
+               ps3_write_pm(cpu, pm_control, pm_ctrl);
+               break;
+
+       case 32:
+               pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
+               ps3_write_pm(cpu, pm_control, pm_ctrl);
+               break;
+       default:
+               BUG();
+       }
+}
+EXPORT_SYMBOL_GPL(ps3_set_ctr_size);
+
+static u64 pm_translate_signal_group_number_on_island2(u64 subgroup)
+{
+
+       if (subgroup == 2)
+               subgroup = 3;
+
+       if (subgroup <= 6)
+               return PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+       else if (subgroup == 7)
+               return PM_ISLAND2_SIGNAL_GROUP_NUMBER1;
+       else
+               return PM_ISLAND2_SIGNAL_GROUP_NUMBER2;
+}
+
+static u64 pm_translate_signal_group_number_on_island3(u64 subgroup)
+{
+
+       switch (subgroup) {
+       case 2:
+       case 3:
+       case 4:
+               subgroup += 2;
+               break;
+       case 5:
+               subgroup = 8;
+               break;
+       default:
+               break;
+       }
+       return PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
+{
+       return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island5(u64 subgroup)
+{
+
+       switch (subgroup) {
+       case 3:
+               subgroup = 4;
+               break;
+       case 4:
+               subgroup = 6;
+               break;
+       default:
+               break;
+       }
+       return PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island6(u64 subgroup,
+                                                      u64 subsubgroup)
+{
+       switch (subgroup) {
+       case 3:
+       case 4:
+       case 5:
+               subgroup += 1;
+               break;
+       default:
+               break;
+       }
+
+       switch (subsubgroup) {
+       case 4:
+       case 5:
+       case 6:
+               subsubgroup += 2;
+               break;
+       case 7:
+       case 8:
+       case 9:
+       case 10:
+               subsubgroup += 4;
+               break;
+       case 11:
+       case 12:
+       case 13:
+               subsubgroup += 5;
+               break;
+       default:
+               break;
+       }
+
+       if (subgroup <= 5)
+               return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup);
+       else
+               return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup
+                       + subsubgroup - 1);
+}
+
+static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
+{
+       return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
+{
+       return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
+{
+       u64 island;
+       u64 subgroup;
+       u64 subsubgroup;
+
+       subgroup = 0;
+       subsubgroup = 0;
+       island = 0;
+       if (group < 1000) {
+               if (group < 100) {
+                       if (20 <= group && group < 30) {
+                               island = 2;
+                               subgroup = group - 20;
+                       } else if (30 <= group && group < 40) {
+                               island = 3;
+                               subgroup = group - 30;
+                       } else if (40 <= group && group < 50) {
+                               island = 4;
+                               subgroup = group - 40;
+                       } else if (50 <= group && group < 60) {
+                               island = 5;
+                               subgroup = group - 50;
+                       } else if (60 <= group && group < 70) {
+                               island = 6;
+                               subgroup = group - 60;
+                       } else if (70 <= group && group < 80) {
+                               island = 7;
+                               subgroup = group - 70;
+                       } else if (80 <= group && group < 90) {
+                               island = 8;
+                               subgroup = group - 80;
+                       }
+               } else if (200 <= group && group < 300) {
+                       island = 2;
+                       subgroup = group - 200;
+               } else if (600 <= group && group < 700) {
+                       island = 6;
+                       subgroup = 5;
+                       subsubgroup = group - 650;
+               }
+       } else if (6000 <= group && group < 7000) {
+               island = 6;
+               subgroup = 5;
+               subsubgroup = group - 6500;
+       }
+
+       switch (island) {
+       case 2:
+               return pm_translate_signal_group_number_on_island2(subgroup);
+       case 3:
+               return pm_translate_signal_group_number_on_island3(subgroup);
+       case 4:
+               return pm_translate_signal_group_number_on_island4(subgroup);
+       case 5:
+               return pm_translate_signal_group_number_on_island5(subgroup);
+       case 6:
+               return pm_translate_signal_group_number_on_island6(subgroup,
+                                                                  subsubgroup);
+       case 7:
+               return pm_translate_signal_group_number_on_island7(subgroup);
+       case 8:
+               return pm_translate_signal_group_number_on_island8(subgroup);
+       default:
+               dev_dbg(sbd_core(), "%s:%u: island not found: %lu\n", __func__,
+                       __LINE__, group);
+               BUG();
+               break;
+       }
+       return 0;
+}
+
+static u64 pm_bus_word_to_ps3_lv1_bus_word(u8 word)
+{
+
+       switch (word) {
+       case 1:
+               return 0xF000;
+       case 2:
+               return 0x0F00;
+       case 4:
+               return 0x00F0;
+       case 8:
+       default:
+               return 0x000F;
+       }
+}
+
+static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
+                           u64 signal_select, u64 attr1, u64 attr2, u64 attr3)
+{
+       int ret;
+
+       ret = lv1_set_lpm_signal(lpm_priv->lpm_id, lv1_signal_group, bus_select,
+                                signal_select, attr1, attr2, attr3);
+       if (ret)
+               dev_err(sbd_core(),
+                       "%s:%u: error:%d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+                       __func__, __LINE__, ret, lv1_signal_group, bus_select,
+                       signal_select, attr1, attr2, attr3);
+
+       return ret;
+}
+
+int ps3_set_signal(u64 signal_group, u8 signal_bit, u16 sub_unit,
+                  u8 bus_word)
+{
+       int ret;
+       u64 lv1_signal_group;
+       u64 bus_select;
+       u64 signal_select;
+       u64 attr1, attr2, attr3;
+
+       if (signal_group == 0)
+               return __ps3_set_signal(0, 0, 0, 0, 0, 0);
+
+       lv1_signal_group =
+               pm_signal_group_to_ps3_lv1_signal_group(signal_group);
+       bus_select = pm_bus_word_to_ps3_lv1_bus_word(bus_word);
+
+       switch (signal_group) {
+       case PM_SIG_GROUP_SPU_TRIGGER:
+               signal_select = 1;
+               signal_select = signal_select << (63 - signal_bit);
+               break;
+       case PM_SIG_GROUP_SPU_EVENT:
+               signal_select = 1;
+               signal_select = (signal_select << (63 - signal_bit)) | 0x3;
+               break;
+       default:
+               signal_select = 0;
+               break;
+       }
+
+       /*
+        * 0: physical object.
+        * 1: logical object.
+        * This parameter is only used for the PPE and SPE signals.
+        */
+       attr1 = 1;
+
+       /*
+        * This parameter is used to specify the target physical/logical
+        * PPE/SPE object.
+        */
+       if (PM_SIG_GROUP_SPU <= signal_group &&
+               signal_group < PM_SIG_GROUP_MFC_MAX)
+               attr2 = sub_unit;
+       else
+               attr2 = lpm_priv->pu_id;
+
+       /*
+        * This parameter is only used for setting the SPE signal.
+        */
+       attr3 = 0;
+
+       ret = __ps3_set_signal(lv1_signal_group, bus_select, signal_select,
+                              attr1, attr2, attr3);
+       if (ret)
+               dev_err(sbd_core(), "%s:%u: __ps3_set_signal failed: %d\n",
+                       __func__, __LINE__, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ps3_set_signal);
+
+u32 ps3_get_hw_thread_id(int cpu)
+{
+       return get_hard_smp_processor_id(cpu);
+}
+EXPORT_SYMBOL_GPL(ps3_get_hw_thread_id);
+
+/**
+ * ps3_enable_pm - Enable the entire performance monitoring unit.
+ *
+ * When we enable the LPM, all pending writes to counters get committed.
+ */
+
+void ps3_enable_pm(u32 cpu)
+{
+       int result;
+       u64 tmp;
+       int insert_bookmark = 0;
+
+       lpm_priv->tb_count = 0;
+
+       if (use_start_stop_bookmark) {
+               if (!(lpm_priv->shadow.pm_start_stop &
+                       (PS3_PM_START_STOP_START_MASK
+                       | PS3_PM_START_STOP_STOP_MASK))) {
+                       result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+                               (PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START |
+                               PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START |
+                               PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP |
+                               PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP),
+                               0xFFFFFFFFFFFFFFFFULL, &tmp);
+
+                       if (result)
+                               dev_err(sbd_core(), "%s:%u: "
+                                       "lv1_set_lpm_trigger_control failed: "
+                                       "%s\n", __func__, __LINE__,
+                                       ps3_result(result));
+
+                       insert_bookmark = !result;
+               }
+       }
+
+       result = lv1_start_lpm(lpm_priv->lpm_id);
+
+       if (result)
+               dev_err(sbd_core(), "%s:%u: lv1_start_lpm failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       if (use_start_stop_bookmark && !result && insert_bookmark)
+               ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_START);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm);
+
+/**
+ * ps3_disable_pm - Disable the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm(u32 cpu)
+{
+       int result;
+       u64 tmp;
+
+       ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_STOP);
+
+       result = lv1_stop_lpm(lpm_priv->lpm_id, &tmp);
+
+       if (result) {
+               if(result != LV1_WRONG_STATE)
+                       dev_err(sbd_core(), "%s:%u: lv1_stop_lpm failed: %s\n",
+                               __func__, __LINE__, ps3_result(result));
+               return;
+       }
+
+       lpm_priv->tb_count = tmp;
+
+       dev_dbg(sbd_core(), "%s:%u: tb_count %lu (%lxh)\n", __func__, __LINE__,
+               lpm_priv->tb_count, lpm_priv->tb_count);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm);
+
+/**
+ * ps3_lpm_copy_tb - Copy data from the trace buffer to a kernel buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: Copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ *  bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
+                   unsigned long *bytes_copied)
+{
+       int result;
+
+       *bytes_copied = 0;
+
+       if (!lpm_priv->tb_cache)
+               return -EPERM;
+
+       if (offset >= lpm_priv->tb_count)
+               return 0;
+
+       count = min(count, lpm_priv->tb_count - offset);
+
+       while (*bytes_copied < count) {
+               const unsigned long request = count - *bytes_copied;
+               u64 tmp;
+
+               result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+                                                  request, &tmp);
+               if (result) {
+                       dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+                               __func__, __LINE__, request, offset);
+
+                       dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+                               "failed: %s\n", __func__, __LINE__,
+                               ps3_result(result));
+                       return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+               }
+
+               memcpy(buf, lpm_priv->tb_cache, tmp);
+               buf += tmp;
+               *bytes_copied += tmp;
+               offset += tmp;
+       }
+       dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+               *bytes_copied);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb);
+
+/**
+ * ps3_lpm_copy_tb_to_user - Copy data from the trace buffer to a user buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: A __user copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ *  bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
+                           unsigned long count, unsigned long *bytes_copied)
+{
+       int result;
+
+       *bytes_copied = 0;
+
+       if (!lpm_priv->tb_cache)
+               return -EPERM;
+
+       if (offset >= lpm_priv->tb_count)
+               return 0;
+
+       count = min(count, lpm_priv->tb_count - offset);
+
+       while (*bytes_copied < count) {
+               const unsigned long request = count - *bytes_copied;
+               u64 tmp;
+
+               result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+                                                  request, &tmp);
+               if (result) {
+                       dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+                               __func__, __LINE__, request, offset);
+                       dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+                               "failed: %s\n", __func__, __LINE__,
+                               ps3_result(result));
+                       return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+               }
+
+               result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
+
+               if (result) {
+                       dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%p\n",
+                               __func__, __LINE__, tmp, buf);
+                       dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
+                               __func__, __LINE__, result);
+                       return -EFAULT;
+               }
+
+               buf += tmp;
+               *bytes_copied += tmp;
+               offset += tmp;
+       }
+       dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+               *bytes_copied);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb_to_user);
+
+/**
+ * ps3_get_and_clear_pm_interrupts -
+ *
+ * Clearing interrupts for the entire performance monitoring unit.
+ * Reading pm_status clears the interrupt bits.
+ */
+
+u32 ps3_get_and_clear_pm_interrupts(u32 cpu)
+{
+       return ps3_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(ps3_get_and_clear_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Enabling interrupts for the entire performance monitoring unit.
+ * Enables the interrupt bits in the pm_status register.
+ */
+
+void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
+{
+       if (mask)
+               ps3_write_pm(cpu, pm_status, mask);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Disabling interrupts for the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm_interrupts(u32 cpu)
+{
+       ps3_get_and_clear_pm_interrupts(cpu);
+       ps3_write_pm(cpu, pm_status, 0);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts);
+
+/**
+ * ps3_lpm_open - Open the logical performance monitor device.
+ * @tb_type: Specifies the type of trace buffer lv1 sould use for this lpm
+ *  instance, specified by one of enum ps3_lpm_tb_type.
+ * @tb_cache: Optional user supplied buffer to use as the trace buffer cache.
+ *  If NULL, the driver will allocate and manage an internal buffer.
+ *  Unused when when @tb_type is PS3_LPM_TB_TYPE_NONE.
+ * @tb_cache_size: The size in bytes of the user supplied @tb_cache buffer.
+ *  Unused when @tb_cache is NULL or @tb_type is PS3_LPM_TB_TYPE_NONE.
+ */
+
+int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
+       u64 tb_cache_size)
+{
+       int result;
+       u64 tb_size;
+
+       BUG_ON(!lpm_priv);
+       BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
+               && tb_type != PS3_LPM_TB_TYPE_INTERNAL);
+
+       if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
+               dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
+
+       if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
+               dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
+               return -EBUSY;
+       }
+
+       /* Note tb_cache needs 128 byte alignment. */
+
+       if (tb_type == PS3_LPM_TB_TYPE_NONE) {
+               lpm_priv->tb_cache_size = 0;
+               lpm_priv->tb_cache_internal = NULL;
+               lpm_priv->tb_cache = NULL;
+       } else if (tb_cache) {
+               if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128)
+                       || tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) {
+                       dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
+                               __func__, __LINE__);
+                       result = -EINVAL;
+                       goto fail_align;
+               }
+               lpm_priv->tb_cache_size = tb_cache_size;
+               lpm_priv->tb_cache_internal = NULL;
+               lpm_priv->tb_cache = tb_cache;
+       } else {
+               lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
+               lpm_priv->tb_cache_internal = kzalloc(
+                       lpm_priv->tb_cache_size + 127, GFP_KERNEL);
+               if (!lpm_priv->tb_cache_internal) {
+                       dev_err(sbd_core(), "%s:%u: alloc internal tb_cache "
+                               "failed\n", __func__, __LINE__);
+                       result = -ENOMEM;
+                       goto fail_malloc;
+               }
+               lpm_priv->tb_cache = (void *)_ALIGN_UP(
+                       (unsigned long)lpm_priv->tb_cache_internal, 128);
+       }
+
+       result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
+                               ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
+                               lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
+                               &lpm_priv->outlet_id, &tb_size);
+
+       if (result) {
+               dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               result = -EINVAL;
+               goto fail_construct;
+       }
+
+       lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
+       lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
+       lpm_priv->shadow.pm_interval = PS3_LPM_SHADOW_REG_INIT;
+       lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
+       lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
+
+       dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%lx, outlet_id 0x%lx, "
+               "tb_size 0x%lx\n", __func__, __LINE__, lpm_priv->lpm_id,
+               lpm_priv->outlet_id, tb_size);
+
+       return 0;
+
+fail_construct:
+       kfree(lpm_priv->tb_cache_internal);
+       lpm_priv->tb_cache_internal = NULL;
+fail_malloc:
+fail_align:
+       atomic_dec(&lpm_priv->open);
+       return result;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_open);
+
+/**
+ * ps3_lpm_close - Close the lpm device.
+ *
+ */
+
+int ps3_lpm_close(void)
+{
+       dev_dbg(sbd_core(), "%s:%u\n", __func__, __LINE__);
+
+       lv1_destruct_lpm(lpm_priv->lpm_id);
+       lpm_priv->lpm_id = 0;
+
+       kfree(lpm_priv->tb_cache_internal);
+       lpm_priv->tb_cache_internal = NULL;
+
+       atomic_dec(&lpm_priv->open);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_close);
+
+static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
+{
+       dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
+
+       if (lpm_priv) {
+               dev_info(&dev->core, "%s:%u: called twice\n",
+                       __func__, __LINE__);
+               return -EBUSY;
+       }
+
+       lpm_priv = kzalloc(sizeof(*lpm_priv), GFP_KERNEL);
+
+       if (!lpm_priv)
+               return -ENOMEM;
+
+       lpm_priv->sbd = dev;
+       lpm_priv->node_id = dev->lpm.node_id;
+       lpm_priv->pu_id = dev->lpm.pu_id;
+       lpm_priv->rights = dev->lpm.rights;
+
+       dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+
+       return 0;
+}
+
+static int ps3_lpm_remove(struct ps3_system_bus_device *dev)
+{
+       dev_dbg(&dev->core, " -> %s:%u:\n", __func__, __LINE__);
+
+       ps3_lpm_close();
+
+       kfree(lpm_priv);
+       lpm_priv = NULL;
+
+       dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+       return 0;
+}
+
+static struct ps3_system_bus_driver ps3_lpm_driver = {
+       .match_id = PS3_MATCH_ID_LPM,
+       .core.name      = "ps3-lpm",
+       .core.owner     = THIS_MODULE,
+       .probe          = ps3_lpm_probe,
+       .remove         = ps3_lpm_remove,
+       .shutdown       = ps3_lpm_remove,
+};
+
+static int __init ps3_lpm_init(void)
+{
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       return ps3_system_bus_driver_register(&ps3_lpm_driver);
+}
+
+static void __exit ps3_lpm_exit(void)
+{
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       ps3_system_bus_driver_unregister(&ps3_lpm_driver);
+}
+
+module_init(ps3_lpm_init);
+module_exit(ps3_lpm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_LPM);
index 8461b08ab9fb627e06b55bb97367cb783068bec4..c3c3aba3ffce303c43f1b2fc527569a7499cd31d 100644 (file)
@@ -452,7 +452,7 @@ static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
        case PS3_SM_EVENT_THERMAL_ALERT:
                dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
                        __func__, __LINE__, event.value);
-               printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value);
+               pr_info("PS3 Thermal Alert Zone %u\n", event.value);
                break;
        case PS3_SM_EVENT_THERMAL_CLEARED:
                dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
@@ -488,7 +488,7 @@ static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
        result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
        BUG_ON(result && "need to retry here");
 
-       if(result)
+       if (result)
                return result;
 
        if (cmd.version != 1) {
@@ -521,7 +521,7 @@ static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
        result = ps3_vuart_read(dev, &header,
                sizeof(struct ps3_sys_manager_header));
 
-       if(result)
+       if (result)
                return result;
 
        if (header.version != 1) {
@@ -589,9 +589,9 @@ static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
                PS3_SM_WAKE_DEFAULT);
        ps3_sys_manager_send_request_shutdown(dev);
 
-       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       pr_emerg("System Halted, OK to turn off power\n");
 
-       while(1)
+       while (1)
                ps3_sys_manager_handle_msg(dev);
 }
 
@@ -626,9 +626,9 @@ static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
                PS3_SM_WAKE_DEFAULT);
        ps3_sys_manager_send_request_shutdown(dev);
 
-       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       pr_emerg("System Halted, OK to turn off power\n");
 
-       while(1)
+       while (1)
                ps3_sys_manager_handle_msg(dev);
 }
 
index bb8d5b1eec90256a47d524baac8abb51e039c9ef..90c097a7a47ab5fc7a41b298f3beb968dbadd359 100644 (file)
@@ -108,18 +108,18 @@ static struct ps3_vuart_port_priv *to_port_priv(
 struct ports_bmp {
        u64 status;
        u64 unused[3];
-} __attribute__ ((aligned (32)));
+} __attribute__((aligned(32)));
 
 #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
 static void __maybe_unused _dump_ports_bmp(
-       const struct ports_bmp* bmp, const char* func, int line)
+       const struct ports_bmp *bmp, const char *func, int line)
 {
        pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
 }
 
 #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
 static void __maybe_unused _dump_port_params(unsigned int port_number,
-       const charfunc, int line)
+       const char *func, int line)
 {
 #if defined(DEBUG)
        static const char *strings[] = {
@@ -363,7 +363,7 @@ int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev)
  */
 
 static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
-       const voidbuf, unsigned int bytes, unsigned long *bytes_written)
+       const void *buf, unsigned int bytes, unsigned long *bytes_written)
 {
        int result;
        struct ps3_vuart_port_priv *priv = to_port_priv(dev);
@@ -431,7 +431,7 @@ void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
        int result;
        struct ps3_vuart_port_priv *priv = to_port_priv(dev);
        u64 bytes_waiting;
-       voidtmp;
+       void *tmp;
 
        result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting);
 
@@ -526,9 +526,8 @@ int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
 
        lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
 
-       if (!lb) {
+       if (!lb)
                return -ENOMEM;
-       }
 
        memcpy(lb->data, buf, bytes);
        lb->head = lb->data;
@@ -878,7 +877,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev)
 struct vuart_bus_priv {
        struct ports_bmp *bmp;
        unsigned int virq;
-       struct semaphore probe_mutex;
+       struct mutex probe_mutex;
        int use_count;
        struct ps3_system_bus_device *devices[PORT_COUNT];
 } static vuart_bus_priv;
@@ -926,9 +925,8 @@ static int ps3_vuart_bus_interrupt_get(void)
 
        BUG_ON(vuart_bus_priv.use_count > 2);
 
-       if (vuart_bus_priv.use_count != 1) {
+       if (vuart_bus_priv.use_count != 1)
                return 0;
-       }
 
        BUG_ON(vuart_bus_priv.bmp);
 
@@ -1017,7 +1015,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
                return -EINVAL;
        }
 
-       down(&vuart_bus_priv.probe_mutex);
+       mutex_lock(&vuart_bus_priv.probe_mutex);
 
        result = ps3_vuart_bus_interrupt_get();
 
@@ -1077,7 +1075,7 @@ static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
                goto fail_probe;
        }
 
-       up(&vuart_bus_priv.probe_mutex);
+       mutex_unlock(&vuart_bus_priv.probe_mutex);
 
        return result;
 
@@ -1090,7 +1088,7 @@ fail_dev_malloc:
 fail_busy:
        ps3_vuart_bus_interrupt_put();
 fail_setup_interrupt:
-       up(&vuart_bus_priv.probe_mutex);
+       mutex_unlock(&vuart_bus_priv.probe_mutex);
        dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);
        return result;
 }
@@ -1129,7 +1127,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
 
        BUG_ON(!dev);
 
-       down(&vuart_bus_priv.probe_mutex);
+       mutex_lock(&vuart_bus_priv.probe_mutex);
 
        dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
                dev->match_id);
@@ -1137,7 +1135,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
        if (!dev->core.driver) {
                dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
                        __LINE__);
-               up(&vuart_bus_priv.probe_mutex);
+               mutex_unlock(&vuart_bus_priv.probe_mutex);
                return 0;
        }
 
@@ -1160,7 +1158,7 @@ static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
        priv = NULL;
 
        dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
-       up(&vuart_bus_priv.probe_mutex);
+       mutex_unlock(&vuart_bus_priv.probe_mutex);
        return 0;
 }
 
@@ -1180,7 +1178,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
 
        BUG_ON(!dev);
 
-       down(&vuart_bus_priv.probe_mutex);
+       mutex_lock(&vuart_bus_priv.probe_mutex);
 
        dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
                dev->match_id);
@@ -1188,7 +1186,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
        if (!dev->core.driver) {
                dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
                        __LINE__);
-               up(&vuart_bus_priv.probe_mutex);
+               mutex_unlock(&vuart_bus_priv.probe_mutex);
                return 0;
        }
 
@@ -1212,7 +1210,7 @@ static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
 
        dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 
-       up(&vuart_bus_priv.probe_mutex);
+       mutex_unlock(&vuart_bus_priv.probe_mutex);
        return 0;
 }
 
@@ -1223,7 +1221,7 @@ static int __init ps3_vuart_bus_init(void)
        if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
                return -ENODEV;
 
-       init_MUTEX(&vuart_bus_priv.probe_mutex);
+       mutex_init(&vuart_bus_priv.probe_mutex);
 
        return 0;
 }
index e974876e18d2c98c7239981c1c49b693a73b11a6..5eea6dbc0aa2d75c2a7f7846bcc89137b315bc8f 100644 (file)
@@ -189,8 +189,6 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 extern struct dma_mapping_ops dma_iommu_ops;
 extern struct dma_mapping_ops dma_direct_ops;
 
-extern unsigned long dma_direct_offset;
-
 #else /* CONFIG_PPC64 */
 
 #define dma_supported(dev, mask)       (1)
index b6f817b8ba3d3528cb500ffeed16879bcc5fcb2c..701857bc8e242b280706bda8fcc7380a009aafcc 100644 (file)
@@ -123,6 +123,9 @@ struct pt_regs;
 extern void default_machine_kexec(struct kimage *image);
 extern int default_machine_kexec_prepare(struct kimage *image);
 extern void default_machine_crash_shutdown(struct pt_regs *regs);
+typedef void (*crash_shutdown_t)(void);
+extern int crash_shutdown_register(crash_shutdown_t handler);
+extern int crash_shutdown_unregister(crash_shutdown_t handler);
 
 extern void machine_kexec_simple(struct kimage *image);
 extern void crash_kexec_secondary(struct pt_regs *regs);
index f577a16c6728a1a34c363ccfefbc526e5c5f4894..2b693673eff442bcc0726e50f624e462aa85a1d4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
+#include "cell-pmu.h"
 
 union ps3_firmware_version {
        u64 raw;
@@ -317,6 +318,7 @@ enum ps3_match_id {
        PS3_MATCH_ID_STOR_FLASH     = 8,
        PS3_MATCH_ID_SOUND          = 9,
        PS3_MATCH_ID_GRAPHICS       = 10,
+       PS3_MATCH_ID_LPM            = 11,
 };
 
 #define PS3_MODULE_ALIAS_EHCI           "ps3:1"
@@ -329,11 +331,13 @@ enum ps3_match_id {
 #define PS3_MODULE_ALIAS_STOR_FLASH     "ps3:8"
 #define PS3_MODULE_ALIAS_SOUND          "ps3:9"
 #define PS3_MODULE_ALIAS_GRAPHICS       "ps3:10"
+#define PS3_MODULE_ALIAS_LPM            "ps3:11"
 
 enum ps3_system_bus_device_type {
        PS3_DEVICE_TYPE_IOC0 = 1,
        PS3_DEVICE_TYPE_SB,
        PS3_DEVICE_TYPE_VUART,
+       PS3_DEVICE_TYPE_LPM,
 };
 
 /**
@@ -344,12 +348,17 @@ struct ps3_system_bus_device {
        enum ps3_match_id match_id;
        enum ps3_system_bus_device_type dev_type;
 
-       unsigned int bus_id;              /* SB */
-       unsigned int dev_id;              /* SB */
+       u64 bus_id;                       /* SB */
+       u64 dev_id;                       /* SB */
        unsigned int interrupt_id;        /* SB */
        struct ps3_dma_region *d_region;  /* SB, IOC0 */
        struct ps3_mmio_region *m_region; /* SB, IOC0*/
        unsigned int port_number;         /* VUART */
+       struct {                          /* LPM */
+               u64 node_id;
+               u64 pu_id;
+               u64 rights;
+       } lpm;
 
 /*     struct iommu_table *iommu_table; -- waiting for BenH's cleanups */
        struct device core;
@@ -438,5 +447,66 @@ struct ps3_prealloc {
 extern struct ps3_prealloc ps3fb_videomemory;
 extern struct ps3_prealloc ps3flash_bounce_buffer;
 
+/* logical performance monitor */
+
+/**
+ * enum ps3_lpm_rights - Rigths granted by the system policy module.
+ *
+ * @PS3_LPM_RIGHTS_USE_LPM: The right to use the lpm.
+ * @PS3_LPM_RIGHTS_USE_TB: The right to use the internal trace buffer.
+ */
+
+enum ps3_lpm_rights {
+       PS3_LPM_RIGHTS_USE_LPM = 0x001,
+       PS3_LPM_RIGHTS_USE_TB = 0x100,
+};
+
+/**
+ * enum ps3_lpm_tb_type - Type of trace buffer lv1 should use.
+ *
+ * @PS3_LPM_TB_TYPE_NONE: Do not use a trace buffer.
+ * @PS3_LPM_RIGHTS_USE_TB: Use the lv1 internal trace buffer.  Must have
+ *  rights @PS3_LPM_RIGHTS_USE_TB.
+ */
+
+enum ps3_lpm_tb_type {
+       PS3_LPM_TB_TYPE_NONE = 0,
+       PS3_LPM_TB_TYPE_INTERNAL = 1,
+};
+
+int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
+       u64 tb_cache_size);
+int ps3_lpm_close(void);
+int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
+       unsigned long *bytes_copied);
+int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
+       unsigned long count, unsigned long *bytes_copied);
+void ps3_set_bookmark(u64 bookmark);
+void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id);
+int ps3_set_signal(u64 rtas_signal_group, u8 signal_bit, u16 sub_unit,
+       u8 bus_word);
+
+u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr);
+void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
+u32 ps3_read_ctr(u32 cpu, u32 ctr);
+void ps3_write_ctr(u32 cpu, u32 ctr, u32 val);
+
+u32 ps3_read_pm07_control(u32 cpu, u32 ctr);
+void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val);
+u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg);
+void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val);
+
+u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr);
+void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
+
+void ps3_enable_pm(u32 cpu);
+void ps3_disable_pm(u32 cpu);
+void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
+void ps3_disable_pm_interrupts(u32 cpu);
+
+u32 ps3_get_and_clear_pm_interrupts(u32 cpu);
+void ps3_sync_irq(int node);
+u32 ps3_get_hw_thread_id(int cpu);
+u64 ps3_get_spe_id(void *arg);
 
 #endif
index 1f685047c6ffe80c983a5bff36e53777206ff7bb..2408a29507e599fd457a45369fe688e4499e1147 100644 (file)
 #define SPRN_PA6T_BTCR 978     /* Breakpoint and Tagging Control Register */
 #define SPRN_PA6T_IMAAT        979     /* Instruction Match Array Action Table */
 #define SPRN_PA6T_PCCR 1019    /* Power Counter Control Register */
+#define SPRN_BKMK      1020    /* Cell Bookmark Register */
 #define SPRN_PA6T_RPCCR        1021    /* Retire PC Trace Control Register */
 
 
diff --git a/include/asm-powerpc/setjmp.h b/include/asm-powerpc/setjmp.h
new file mode 100644 (file)
index 0000000..279d03a
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2008 Michael Neuling IBM Corporation
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ */
+#ifndef _ASM_POWERPC_SETJMP_H
+#define _ASM_POWERPC_SETJMP_H
+
+#define JMP_BUF_LEN    23
+
+extern long setjmp(long *);
+extern void longjmp(long *, long);
+
+#endif /* _ASM_POWERPC_SETJMP_H */
index 48ad807a0b8a80ce49788e49935d081585166009..e8b493d52b4f68a6807ed25475262b47e4defbd7 100644 (file)
  */
 #define SECTION_SIZE_BITS       24
 
-#if defined(CONFIG_PS3_USE_LPAR_ADDR)
-#define MAX_PHYSADDR_BITS       47
-#define MAX_PHYSMEM_BITS        47
-#else
 #define MAX_PHYSADDR_BITS       44
 #define MAX_PHYSMEM_BITS        44
-#endif
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 extern void create_section_mapping(unsigned long start, unsigned long end);