Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
authorLinus Torvalds <torvalds@woody.osdl.org>
Tue, 12 Dec 2006 02:24:58 +0000 (18:24 -0800)
committerLinus Torvalds <torvalds@woody.osdl.org>
Tue, 12 Dec 2006 02:24:58 +0000 (18:24 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (36 commits)
  [POWERPC] Generic BUG for powerpc
  [PPC] Fix compile failure do to introduction of PHY_POLL
  [POWERPC] Only export __mtdcr/__mfdcr if CONFIG_PPC_DCR is set
  [POWERPC] Remove old dcr.S
  [POWERPC] Fix SPU coredump code for max_fdset removal
  [POWERPC] Fix irq routing on some 32-bit PowerMacs
  [POWERPC] ps3: Add vuart support
  [POWERPC] Support ibm,dynamic-reconfiguration-memory nodes
  [POWERPC] dont allow pSeries_probe to succeed without initialising MMU
  [POWERPC] micro optimise pSeries_probe
  [POWERPC] Add SPURR SPR to sysfs
  [POWERPC] Add DSCR SPR to sysfs
  [POWERPC] Fix 440SPe CPU table entry
  [POWERPC] Add support for FP emulation for the e300c2 core
  [POWERPC] of_device_register: propagate device_create_file return code
  [POWERPC] Fix mmap of PCI resource with hack for X
  [POWERPC] iSeries: head_64.o needs to depend on lparmap.s
  [POWERPC] cbe_thermal: Fix initialization of sysfs attribute_group
  [POWERPC] Remove QE header files from lite5200.c
  [POWERPC] of_platform_make_bus_id(): make `magic' int
  ...

56 files changed:
arch/powerpc/Kconfig
arch/powerpc/configs/ps3_defconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/module_32.c
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/mm/numa.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/cell/cbe_thermal.c
arch/powerpc/platforms/cell/pmu.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/ps3/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/hotplug-cpu.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dcr.S [deleted file]
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/rom.c
arch/powerpc/xmon/xmon.c
arch/ppc/kernel/pci.c
drivers/ps3/Makefile
drivers/ps3/vuart.c [new file with mode: 0644]
drivers/ps3/vuart.h [new file with mode: 0644]
include/asm-powerpc/Kbuild
include/asm-powerpc/bug.h
include/asm-powerpc/cputable.h
include/asm-powerpc/dcr-native.h
include/asm-powerpc/dcr.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/module.h
include/asm-powerpc/pci-bridge.h
include/asm-powerpc/pci.h
include/asm-powerpc/reg.h
include/asm-powerpc/rtas.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/pci.h
include/asm-ppc/reg_booke.h
include/linux/fsl_devices.h

index 56c3c4065eb0c354fab33618ded153b43a1648b7..8699dadcd0966028ed7207b333486b2295a4fc12 100644 (file)
@@ -107,6 +107,11 @@ config AUDIT_ARCH
        bool
        default y
 
+config GENERIC_BUG
+       bool
+       default y
+       depends on BUG
+
 config DEFAULT_UIMAGE
        bool
        help
@@ -478,6 +483,7 @@ config PPC_MAPLE
        select PPC_UDBG_16550
        select PPC_970_NAP
        select PPC_NATIVE
+       select PPC_RTAS
        default n
        help
           This option enables support for the Maple 970FX Evaluation Board.
@@ -714,7 +720,7 @@ config FORCE_MAX_ZONEORDER
 
 config MATH_EMULATION
        bool "Math emulation"
-       depends on 4xx || 8xx || E200 || E500
+       depends on 4xx || 8xx || E200 || PPC_83xx || E500
        ---help---
          Some PowerPC chips designed for embedded applications do not have
          a floating-point unit and therefore do not implement the
index f2d888e014a9f81cbf296ec2ca8af3bf8ef570d9..70ed61337f5c03ad20b3775055c2baf4a99b0466 100644 (file)
@@ -157,6 +157,7 @@ CONFIG_SPU_BASE=y
 CONFIG_PS3_HTAB_SIZE=20
 CONFIG_PS3_DYNAMIC_DMA=y
 CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
 
 #
 # Kernel options
index 4fe53d08ab817e79a4810b1492e3a5e4bff02661..d2ded19e40643f4b7bafdaa28ba89ad0b443462d 100644 (file)
@@ -77,6 +77,7 @@ endif
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 extra-y += lparmap.s
+$(obj)/head_64.o:      $(obj)/lparmap.s
 AFLAGS_head_64.o += -I$(obj)
 endif
 
index 9d1614c3ce67d047adf9573dcb40704602783a5a..b742013bb9da2f6fbc70b86d2fea909e707e6881 100644 (file)
@@ -833,7 +833,7 @@ static struct cpu_spec cpu_specs[] = {
                .pvr_mask               = 0x7fff0000,
                .pvr_value              = 0x00840000,
                .cpu_name               = "e300c2",
-               .cpu_features           = CPU_FTRS_E300,
+               .cpu_features           = CPU_FTRS_E300C2,
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
@@ -1136,8 +1136,7 @@ static struct cpu_spec cpu_specs[] = {
                .pvr_mask               = 0xff000fff,
                .pvr_value              = 0x53000890,
                .cpu_name               = "440SPe Rev. A",
-               .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
-                       CPU_FTR_USE_TB,
+               .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
index d88e182e40b3849ba085ec3f83265adac690e538..9417cf5b4b7e7af4b361b0075a3b3c4d96dd2416 100644 (file)
@@ -437,6 +437,13 @@ Alignment:
 /* Floating-point unavailable */
        . = 0x800
 FPUnavailable:
+BEGIN_FTR_SECTION
+/*
+ * Certain Freescale cores don't have a FPU and treat fp instructions
+ * as a FP Unavailable exception.  Redirect to illegal/emulation handling.
+ */
+       b       ProgramCheck
+END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE)
        EXCEPTION_PROLOG
        bne     load_up_fpu             /* if from user, just load it up */
        addi    r3,r1,STACK_FRAME_OVERHEAD
index e2c3c6a85f33b4180cd8f9d812e831e2f4c4176c..8339fd609de045c6c92777594009f9492391163d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/cache.h>
+#include <linux/bug.h>
 
 #include "setup.h"
 
@@ -290,23 +291,11 @@ int module_finalize(const Elf_Ehdr *hdr,
                    struct module *me)
 {
        const Elf_Shdr *sect;
+       int err;
 
-       me->arch.bug_table = NULL;
-       me->arch.num_bugs = 0;
-
-       /* Find the __bug_table section, if present */
-       sect = find_section(hdr, sechdrs, "__bug_table");
-       if (sect != NULL) {
-               me->arch.bug_table = (void *) sect->sh_addr;
-               me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-       }
-
-       /*
-        * Strictly speaking this should have a spinlock to protect against
-        * traversals, but since we only traverse on BUG()s, a spinlock
-        * could potentially lead to deadlock and thus be counter-productive.
-        */
-       list_add(&me->arch.bug_list, &module_bug_list);
+       err = module_bug_finalize(hdr, sechdrs, me);
+       if (err)                /* never true, currently */
+               return err;
 
        /* Apply feature fixups */
        sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -320,7 +309,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-       list_del(&mod->arch.bug_list);
+       module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
index 8dd1f0aae5d6265809748dcc0e0001b2a55e440e..75c7c4f1928059689353927c2c67d198c62e715f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/moduleloader.h>
 #include <linux/err.h>
 #include <linux/vmalloc.h>
+#include <linux/bug.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
@@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr,
                const Elf_Shdr *sechdrs, struct module *me)
 {
        const Elf_Shdr *sect;
+       int err;
 
-       me->arch.bug_table = NULL;
-       me->arch.num_bugs = 0;
-
-       /* Find the __bug_table section, if present */
-       sect = find_section(hdr, sechdrs, "__bug_table");
-       if (sect != NULL) {
-               me->arch.bug_table = (void *) sect->sh_addr;
-               me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-       }
-
-       /*
-        * Strictly speaking this should have a spinlock to protect against
-        * traversals, but since we only traverse on BUG()s, a spinlock
-        * could potentially lead to deadlock and thus be counter-productive.
-        */
-       list_add(&me->arch.bug_list, &module_bug_list);
+       err = module_bug_finalize(hdr, sechdrs, me);
+       if (err)
+               return err;
 
        /* Apply feature fixups */
        sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-       list_del(&mod->arch.bug_list);
+       module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
index 8a06724e029e4fd1f8cee862b95bd7101839ed20..e921514e655bd45a2b96438151e2a2f07d66b10e 100644 (file)
@@ -109,9 +109,7 @@ int of_device_register(struct of_device *ofdev)
        if (rc)
                return rc;
 
-       device_create_file(&ofdev->dev, &dev_attr_devspec);
-
-       return 0;
+       return device_create_file(&ofdev->dev, &dev_attr_devspec);
 }
 
 void of_device_unregister(struct of_device *ofdev)
index b3189d0161b8d7b4f9a60ac0db8c1804a55584a9..3002ea3a61a24df59fd437ecbd80866af1e3c6d6 100644 (file)
@@ -169,7 +169,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
        char *name = dev->dev.bus_id;
        const u32 *reg;
        u64 addr;
-       long magic;
+       int magic;
 
        /*
         * If it's a DCR based device, use 'd' for native DCRs
index 2f54cd81dea571ce82468d82361ae0a67e397f3e..8336deafc624fd7973c9a36e412787f890e8aeb1 100644 (file)
@@ -736,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
        return NULL;
 }
 
-static int
-scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
+                                              unsigned int devfn)
 {
-       const unsigned int *reg;
-       u8* fdata = (u8*)data;
-       
-       reg = get_property(node, "reg", NULL);
-       if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
-               && ((reg[0] >> 16) & 0xff) == fdata[0])
-               return 1;
-       return 0;
+       struct device_node *np = NULL;
+       const u32 *reg;
+       unsigned int psize;
+
+       while ((np = of_get_next_child(parent, np)) != NULL) {
+               reg = get_property(np, "reg", &psize);
+               if (reg == NULL || psize < 4)
+                       continue;
+               if (((reg[0] >> 8) & 0xff) == devfn)
+                       return np;
+       }
+       return NULL;
 }
 
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+
+static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
 {
-       u8 filter_data[2] = {bus, dev_fn};
+       struct device_node *parent, *np;
+
+       /* Are we a root bus ? */
+       if (bus->self == NULL || bus->parent == NULL) {
+               struct pci_controller *hose = pci_bus_to_hose(bus->number);
+               if (hose == NULL)
+                       return NULL;
+               return of_node_get(hose->arch_data);
+       }
+
+       /* not a root bus, we need to get our parent */
+       parent = scan_OF_for_pci_bus(bus->parent);
+       if (parent == NULL)
+               return NULL;
+
+       /* now iterate for children for a match */
+       np = scan_OF_for_pci_dev(parent, bus->self->devfn);
+       of_node_put(parent);
 
-       return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
+       /* sanity check */
+       if (strcmp(np->type, "pci") != 0)
+               printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n",
+                      np->type, np->full_name);
+
+       return np;
 }
 
 /*
@@ -763,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
 struct device_node *
 pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
 {
-       struct pci_controller *hose;
-       struct device_node *node;
-       int busnr;
+       struct device_node *parent, *np;
 
        if (!have_of)
                return NULL;
-       
-       /* Lookup the hose */
-       busnr = bus->number;
-       hose = pci_bus_to_hose(busnr);
-       if (!hose)
-               return NULL;
 
-       /* Check it has an OF node associated */
-       node = (struct device_node *) hose->arch_data;
-       if (!node)
+       DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn);
+       parent = scan_OF_for_pci_bus(bus);
+       if (parent == NULL)
                return NULL;
-
-       /* Fixup bus number according to what OF think it is. */
-#ifdef CONFIG_PPC_PMAC
-       /* The G5 need a special case here. Basically, we don't remap all
-        * busses on it so we don't create the pci-OF-map. However, we do
-        * remap the AGP bus and so have to deal with it. A future better
-        * fix has to be done by making the remapping per-host and always
-        * filling the pci_to_OF map. --BenH
+       DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>");
+       np = scan_OF_for_pci_dev(parent, devfn);
+       of_node_put(parent);
+       DBG(" result is %s\n", np ? np->full_name : "<NULL>");
+
+       /* XXX most callers don't release the returned node
+        * mostly because ppc64 doesn't increase the refcount,
+        * we need to fix that.
         */
-       if (machine_is(powermac) && busnr >= 0xf0)
-               busnr -= 0xf0;
-       else
-#endif
-       if (pci_to_OF_bus_map)
-               busnr = pci_to_OF_bus_map[busnr];
-       if (busnr == 0xff)
-               return NULL;
-       
-       /* Now, lookup childs of the hose */
-       return scan_OF_childs_for_device(node->child, busnr, devfn);
+       return np;
 }
 EXPORT_SYMBOL(pci_busdev_to_OF_node);
 
@@ -1544,7 +1552,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
 
 
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -1556,7 +1564,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
@@ -1624,9 +1634,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev),
-               (unsigned long long)rp->start, prot);
-
        return __pgprot(prot);
 }
 
@@ -1695,7 +1702,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state,
                        int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1808,22 +1815,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = (void __iomem *)_IO_BASE - hose->io_base_virt
-                       + hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
-                 int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name)
 {
        res->start = start;
        res->end = end;
index 6fa9a0a5c8dbb7f0a700c0e88048e7037caaa63f..a6b7692c72690bc592e1429d08a921e23f9ed946 100644 (file)
@@ -682,7 +682,7 @@ int pci_proc_domain(struct pci_bus *bus)
  * Returns negative error code on failure, zero on success.
  */
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
@@ -694,7 +694,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
@@ -762,9 +764,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
        else
                prot |= _PAGE_GUARDED;
 
-       printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
-              prot);
-
        return __pgprot(prot);
 }
 
@@ -832,7 +831,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1333,20 +1332,41 @@ EXPORT_SYMBOL(pci_read_irq_line);
 
 void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
-                         u64 *start, u64 *end)
+                         resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = pci_io_base - (unsigned long)hose->io_base_virt +
-                       hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - pci_io_base;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
 struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
index 9179f0739ea2c3afb952fad59fa21017bd1fc403..95776b6af4e2892513a70d118a73e70b39d278f9 100644 (file)
@@ -208,7 +208,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
 #endif /* CONFIG_PPC_STD_MMU_32 */
-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+#ifdef CONFIG_PPC_DCR_NATIVE
 EXPORT_SYMBOL(__mtdcr);
 EXPORT_SYMBOL(__mfdcr);
 #endif
index c18dbe77fdc29863eb5a4f3e57c2f5f62e0f93dc..1fc732a552db87ee7a7d0e9aedc4535fc51a8158 100644 (file)
@@ -804,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
        return of_read_ulong(p, s);
 }
 
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Interpret the ibm,dynamic-memory property in the
+ * /ibm,dynamic-reconfiguration-memory node.
+ * This contains a list of memory blocks along with NUMA affinity
+ * information.
+ */
+static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+{
+       cell_t *dm, *ls;
+       unsigned long l, n;
+       unsigned long base, size, lmb_size, flags;
+
+       ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
+       if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
+               return 0;
+       lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
+
+       dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
+       if (dm == NULL || l < sizeof(cell_t))
+               return 0;
+
+       n = *dm++;      /* number of entries */
+       if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
+               return 0;
+
+       for (; n != 0; --n) {
+               base = dt_mem_next_cell(dt_root_addr_cells, &dm);
+               flags = dm[3];
+               /* skip DRC index, pad, assoc. list index, flags */
+               dm += 4;
+               /* skip this block if the reserved bit is set in flags (0x80)
+                  or if the block is not assigned to this partition (0x8) */
+               if ((flags & 0x80) || !(flags & 0x8))
+                       continue;
+               size = lmb_size;
+               if (iommu_is_off) {
+                       if (base >= 0x80000000ul)
+                               continue;
+                       if ((base + size) > 0x80000000ul)
+                               size = 0x80000000ul - base;
+               }
+               lmb_add(base, size);
+       }
+       lmb_dump_all();
+       return 0;
+}
+#else
+#define early_init_dt_scan_drconf_memory(node) 0
+#endif /* CONFIG_PPC_PSERIES */
 
 static int __init early_init_dt_scan_memory(unsigned long node,
                                            const char *uname, int depth, void *data)
@@ -812,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node,
        cell_t *reg, *endp;
        unsigned long l;
 
+       /* Look for the ibm,dynamic-reconfiguration-memory node */
+       if (depth == 1 &&
+           strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
+               return early_init_dt_scan_drconf_memory(node);
+
        /* We are scanning "memory" nodes only */
        if (type == NULL) {
                /*
index 46cf32670ddb67cab23dfe986e686d7bea0ffbb7..520ef42f642ecca95c2f04ce3a4480fa3f913c33 100644 (file)
@@ -679,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = {
        /* option vector 5: PAPR/OF options */
        3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
-       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
index 387ed0d9ad618b3597a7f0931af169993ba103ee..76b5d7ebdcc681fe0b8f4730300b90bc55827fce 100644 (file)
@@ -303,6 +303,12 @@ int rtas_token(const char *service)
 }
 EXPORT_SYMBOL(rtas_token);
 
+int rtas_service_present(const char *service)
+{
+       return rtas_token(service) != RTAS_UNKNOWN_SERVICE;
+}
+EXPORT_SYMBOL(rtas_service_present);
+
 #ifdef CONFIG_RTAS_ERROR_LOGGING
 /*
  * Return the firmware-specified size of the error log buffer
@@ -810,32 +816,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        return 0;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-/* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
-       /* The token is initialized for real in setup_system() */
-       .token = RTAS_UNKNOWN_SERVICE,
-       .nargs = 0,
-       .nret = 1,
-       .rets = &rtas_stop_self_args.args[0],
-};
-
-void rtas_stop_self(void)
-{
-       struct rtas_args *rtas_args = &rtas_stop_self_args;
-
-       local_irq_disable();
-
-       BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE);
-
-       printk("cpu %u (hwid %u) Ready to die...\n",
-              smp_processor_id(), hard_smp_processor_id());
-       enter_rtas(__pa(rtas_args));
-
-       panic("Alas, I survived.\n");
-}
-#endif
-
 /*
  * Call early during boot, before mem init or bootmem, to retrieve the RTAS
  * informations from the device-tree and allocate the RMO buffer for userland
@@ -880,9 +860,6 @@ void __init rtas_initialize(void)
 #endif
        rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       rtas_stop_self_args.token = rtas_token("stop-self");
-#endif /* CONFIG_HOTPLUG_CPU */
 #ifdef CONFIG_RTAS_ERROR_LOGGING
        rtas_last_error_token = rtas_token("rtas-last-error");
 #endif
index 63ed265b7f0936765a1cc7bc9356404acf679e68..400ab2b946e760964bd164f282ec1f270579ac6a 100644 (file)
@@ -181,6 +181,8 @@ SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
 SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
 SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
 SYSFS_PMCSETUP(purr, SPRN_PURR);
+SYSFS_PMCSETUP(spurr, SPRN_SPURR);
+SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
 static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0);
 static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1);
@@ -194,6 +196,8 @@ static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6);
 static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7);
 static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8);
 static SYSDEV_ATTR(purr, 0600, show_purr, NULL);
+static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
+static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
 
 static void register_cpu_online(unsigned int cpu)
 {
@@ -231,6 +235,12 @@ static void register_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_PURR))
                sysdev_create_file(s, &attr_purr);
+
+       if (cpu_has_feature(CPU_FTR_SPURR))
+               sysdev_create_file(s, &attr_spurr);
+
+       if (cpu_has_feature(CPU_FTR_DSCR))
+               sysdev_create_file(s, &attr_dscr);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -272,6 +282,12 @@ static void unregister_cpu_online(unsigned int cpu)
 
        if (cpu_has_feature(CPU_FTR_PURR))
                sysdev_remove_file(s, &attr_purr);
+
+       if (cpu_has_feature(CPU_FTR_SPURR))
+               sysdev_remove_file(s, &attr_spurr);
+
+       if (cpu_has_feature(CPU_FTR_DSCR))
+               sysdev_remove_file(s, &attr_dscr);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
index 0d4e203fa7a05d90751ff0e7e60cb891f413d6af..535f50665647eb490cdc32fd48223c780d55adfd 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
 #include <linux/backlight.h>
+#include <linux/bug.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -727,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs)
        return -EINVAL;
 }
 
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one.  At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x)     NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
+int is_valid_bugaddr(unsigned long addr)
 {
-       struct bug_entry *bug;
-
-       for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
-               if (bugaddr == bug->bug_addr)
-                       return bug;
-       return module_find_bug(bugaddr);
-}
-
-static int check_bug_trap(struct pt_regs *regs)
-{
-       struct bug_entry *bug;
-       unsigned long addr;
-
-       if (regs->msr & MSR_PR)
-               return 0;       /* not in kernel */
-       addr = regs->nip;       /* address of trap instruction */
-       if (addr < PAGE_OFFSET)
-               return 0;
-       bug = find_bug(regs->nip);
-       if (bug == NULL)
-               return 0;
-       if (bug->line & BUG_WARNING_TRAP) {
-               /* this is a WARN_ON rather than BUG/BUG_ON */
-               printk(KERN_ERR "Badness in %s at %s:%ld\n",
-                      bug->function, bug->file,
-                      bug->line & ~BUG_WARNING_TRAP);
-               dump_stack();
-               return 1;
-       }
-       printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
-              bug->function, bug->file, bug->line);
-
-       return 0;
+       return is_kernel_addr(addr);
 }
 
 void __kprobes program_check_exception(struct pt_regs *regs)
@@ -782,6 +738,8 @@ void __kprobes program_check_exception(struct pt_regs *regs)
        unsigned int reason = get_reason(regs);
        extern int do_mathemu(struct pt_regs *regs);
 
+       /* We can now get here via a FP Unavailable exception if the core
+        * has no FPU, in that case no reason flags will be set */
 #ifdef CONFIG_MATH_EMULATION
        /* (reason & REASON_ILLEGAL) would be the obvious thing here,
         * but there seems to be a hardware bug on the 405GP (RevD)
@@ -808,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
                        return;
                if (debugger_bpt(regs))
                        return;
-               if (check_bug_trap(regs)) {
+
+               if (!(regs->msr & MSR_PR) &&  /* not user-mode */
+                   report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
                        regs->nip += 4;
                        return;
                }
index 04b98671a0608d6ced7470712291bde24d3e01ac..04b8e71bf5b0087a814fba70bd47dce22eda717f 100644 (file)
@@ -62,11 +62,7 @@ SECTIONS
                __stop___ex_table = .;
        }
 
-       __bug_table : {
-               __start___bug_table = .;
-               *(__bug_table)
-               __stop___bug_table = .;
-       }
+       BUG_TABLE
 
 /*
  * Init sections discarded at runtime
index 9da01dc8cfd9d3fc0722de803d7cfbfb9e0ab573..262790910ff23900f5bef2ab057feb4ff5a4e636 100644 (file)
@@ -295,6 +295,63 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
        return lmb_end_of_DRAM() - start;
 }
 
+/*
+ * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
+ * node.  This assumes n_mem_{addr,size}_cells have been set.
+ */
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+       const unsigned int *lm, *dm, *aa;
+       unsigned int ls, ld, la;
+       unsigned int n, aam, aalen;
+       unsigned long lmb_size, size;
+       int nid, default_nid = 0;
+       unsigned int start, ai, flags;
+
+       lm = get_property(memory, "ibm,lmb-size", &ls);
+       dm = get_property(memory, "ibm,dynamic-memory", &ld);
+       aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+       if (!lm || !dm || !aa ||
+           ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
+           la < 2 * sizeof(unsigned int))
+               return;
+
+       lmb_size = read_n_cells(n_mem_size_cells, &lm);
+       n = *dm++;              /* number of LMBs */
+       aam = *aa++;            /* number of associativity lists */
+       aalen = *aa++;          /* length of each associativity list */
+       if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) ||
+           la < (aam * aalen + 2) * sizeof(unsigned int))
+               return;
+
+       for (; n != 0; --n) {
+               start = read_n_cells(n_mem_addr_cells, &dm);
+               ai = dm[2];
+               flags = dm[3];
+               dm += 4;
+               /* 0x80 == reserved, 0x8 = assigned to us */
+               if ((flags & 0x80) || !(flags & 0x8))
+                       continue;
+               nid = default_nid;
+               /* flags & 0x40 means associativity index is invalid */
+               if (min_common_depth > 0 && min_common_depth <= aalen &&
+                   (flags & 0x40) == 0 && ai < aam) {
+                       /* this is like of_node_to_nid_single */
+                       nid = aa[ai * aalen + min_common_depth - 1];
+                       if (nid == 0xffff || nid >= MAX_NUMNODES)
+                               nid = default_nid;
+               }
+               node_set_online(nid);
+
+               size = numa_enforce_memory_limit(start, lmb_size);
+               if (!size)
+                       continue;
+
+               add_active_range(nid, start >> PAGE_SHIFT,
+                                (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
+       }
+}
+
 static int __init parse_numa_properties(void)
 {
        struct device_node *cpu = NULL;
@@ -385,6 +442,14 @@ new_range:
                        goto new_range;
        }
 
+       /*
+        * Now do the same thing for each LMB listed in the ibm,dynamic-memory
+        * property in the ibm,dynamic-reconfiguration-memory node.
+        */
+       memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+       if (memory)
+               parse_drconf_memory(memory);
+
        return 0;
 }
 
index a375c15b4315b502517a9d65510fc5eeb509bc84..eaff71e74fb0f8a783465715f73560c877a81c69 100644 (file)
@@ -40,8 +40,6 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
-#include <asm/qe.h>
-#include <asm/qe_ic.h>
 #include <asm/of_platform.h>
 
 #include <asm/mpc52xx.h>
index 616a0a3fd0e2ad9c10330590b3d5c0a785e2317d..70e0d968d30f9e5edd77efdc7ce01451586440e3 100644 (file)
@@ -115,6 +115,7 @@ static struct sysdev_attribute attr_spu_temperature = {
 
 static struct attribute *spu_attributes[] = {
        &attr_spu_temperature.attr,
+       NULL,
 };
 
 static struct attribute_group spu_attribute_group = {
@@ -135,6 +136,7 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
 static struct attribute *ppe_attributes[] = {
        &attr_ppe_temperature0.attr,
        &attr_ppe_temperature1.attr,
+       NULL,
 };
 
 static struct attribute_group ppe_attribute_group = {
index 99c612025e8fa824dc35cb34741fc6672f6a2e39..d04ae1671e6ce5d40f413f820efeb645169d3ba2 100644 (file)
@@ -382,11 +382,14 @@ static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int __init cbe_init_pm_irq(void)
+static int __init cbe_init_pm_irq(void)
 {
        unsigned int irq;
        int rc, node;
 
+       if (!machine_is(cell))
+               return 0;
+
        for_each_node(node) {
                irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
                                               (node << IIC_IRQ_NODE_SHIFT));
index 26945c491f6b21bd7783bff75478df20a9c9aafe..725e19561159dd60bf492d0d87816f3f76767e51 100644 (file)
@@ -147,7 +147,7 @@ static int spufs_arch_notes_size(void)
        struct fdtable *fdt = files_fdtable(current->files);
        int size = 0, fd;
 
-       for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) {
+       for (fd = 0; fd < fdt->max_fds; fd++) {
                if (FD_ISSET(fd, fdt->open_fds)) {
                        struct file *file = fcheck(fd);
 
index 3a32deda765dab3487e1174467f923ceede19fc6..3f6a69f67195a0e7172a072925d6461eedc388fa 100644 (file)
@@ -562,7 +562,7 @@ void __init maple_pci_init(void)
        for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
                if (np->name == NULL)
                        continue;
-               if (strcmp(np->name, "pci") == 0) {
+               if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) {
                        if (add_bridge(np) == 0)
                                of_node_get(np);
                }
index 094989d50babaf0bdfe46db5e4b3ab1cd1531924..f12d5c69e74dea275d772308cdcf311da4f54956 100644 (file)
@@ -60,6 +60,7 @@
 #include <asm/of_device.h>
 #include <asm/lmb.h>
 #include <asm/mpic.h>
+#include <asm/rtas.h>
 #include <asm/udbg.h>
 
 #include "maple.h"
@@ -166,6 +167,16 @@ struct smp_ops_t maple_smp_ops = {
 };
 #endif /* CONFIG_SMP */
 
+static void __init maple_use_rtas_reboot_and_halt_if_present(void)
+{
+       if (rtas_service_present("system-reboot") &&
+           rtas_service_present("power-off")) {
+               ppc_md.restart = rtas_restart;
+               ppc_md.power_off = rtas_power_off;
+               ppc_md.halt = rtas_halt;
+       }
+}
+
 void __init maple_setup_arch(void)
 {
        /* init to some ~sane value until calibrate_delay() runs */
@@ -181,6 +192,7 @@ void __init maple_setup_arch(void)
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
+       maple_use_rtas_reboot_and_halt_if_present();
 
        printk(KERN_DEBUG "Using native/NAP idle loop\n");
 }
index 451bfcd5502e537549937f989bc5b99795d1866c..de52ec4e9e586c7d11e088587beddfb669ce4a6e 100644 (file)
@@ -40,4 +40,15 @@ config PS3_USE_LPAR_ADDR
 
          If you have any doubt, choose the default y.
 
+config PS3_VUART
+       depends on PPC_PS3
+       bool "PS3 Virtual UART support"
+       default y
+       help
+         Include support for the PS3 Virtual UART.
+
+         This support is required for several system services
+         including the System Manager and AV Settings.  In
+         general, all users will say Y.
+
 endmenu
index 997243a91be8778b77b95619e20f385527c7c9ef..69590fbf83daef9ba3a246c7e9f9a14b0d8261b5 100644 (file)
@@ -10,6 +10,8 @@ obj-$(CONFIG_XICS)    += xics.o
 obj-$(CONFIG_SCANLOG)  += scanlog.o
 obj-$(CONFIG_EEH)      += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
 
+obj-$(CONFIG_HOTPLUG_CPU)      += hotplug-cpu.o
+
 obj-$(CONFIG_HVC_CONSOLE)      += hvconsole.o
 obj-$(CONFIG_HVCS)             += hvcserver.o
 obj-$(CONFIG_HCALL_STATS)      += hvCall_inst.o
index 3c2d63ebf787fae9e60e3c98713c36d3e1590d8f..da6e5362e7cd8f13f802729e957538cc491e41b3 100644 (file)
@@ -337,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
                        printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
                                pdn->eeh_check_count);
                        dump_stack();
+                       msleep(5000);
                        
                        /* re-read the slot reset state */
                        if (read_slot_reset_state(pdn, rets) != 0)
index c2bc9904f1cb9af0369b11ceb76bae5fcf12f619..cbd6b0711ab450f1c306930d1ebdb50e3834201d 100644 (file)
@@ -170,14 +170,19 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
 static void eeh_report_resume(struct pci_dev *dev, void *userdata)
 {
        struct pci_driver *driver = dev->driver;
+       struct device_node *dn = pci_device_to_OF_node(dev);
 
        dev->error_state = pci_channel_io_normal;
 
        if (!driver)
                return;
-       if (!driver->err_handler)
-               return;
-       if (!driver->err_handler->resume)
+
+       if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) {
+               PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED;
+               enable_irq(dev->irq);
+       }
+       if (!driver->err_handler ||
+           !driver->err_handler->resume)
                return;
 
        driver->err_handler->resume(dev);
@@ -407,6 +412,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
 
                if (rc)
                        result = PCI_ERS_RESULT_NEED_RESET;
+               else
+                       result = PCI_ERS_RESULT_RECOVERED;
        }
 
        /* If any device has a hard failure, then shut off everything. */
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
new file mode 100644 (file)
index 0000000..f460b9c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * pseries CPU Hotplug infrastructure.
+ *
+ * Split out from arch/powerpc/platforms/pseries/setup.c
+ *  arch/powerpc/kernel/rtas.c, and arch/powerpc/platforms/pseries/smp.c
+ *
+ * Peter Bergner, IBM  March 2001.
+ * Copyright (C) 2001 IBM.
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ * Plus various changes from other IBM teams...
+ *
+ * Copyright (C) 2006 Michael Ellerman, IBM Corporation
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/firmware.h>
+#include <asm/machdep.h>
+#include <asm/vdso_datapage.h>
+#include <asm/pSeries_reconfig.h>
+#include "xics.h"
+
+/* This version can't take the spinlock, because it never returns */
+static struct rtas_args rtas_stop_self_args = {
+       .token = RTAS_UNKNOWN_SERVICE,
+       .nargs = 0,
+       .nret = 1,
+       .rets = &rtas_stop_self_args.args[0],
+};
+
+static void rtas_stop_self(void)
+{
+       struct rtas_args *args = &rtas_stop_self_args;
+
+       local_irq_disable();
+
+       BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+
+       printk("cpu %u (hwid %u) Ready to die...\n",
+              smp_processor_id(), hard_smp_processor_id());
+       enter_rtas(__pa(args));
+
+       panic("Alas, I survived.\n");
+}
+
+static void pseries_mach_cpu_die(void)
+{
+       local_irq_disable();
+       idle_task_exit();
+       xics_teardown_cpu(0);
+       rtas_stop_self();
+       /* Should never get here... */
+       BUG();
+       for(;;);
+}
+
+static int qcss_tok;   /* query-cpu-stopped-state token */
+
+/* Get state of physical CPU.
+ * Return codes:
+ *     0       - The processor is in the RTAS stopped state
+ *     1       - stop-self is in progress
+ *     2       - The processor is not in the RTAS stopped state
+ *     -1      - Hardware Error
+ *     -2      - Hardware Busy, Try again later.
+ */
+static int query_cpu_stopped(unsigned int pcpu)
+{
+       int cpu_status, status;
+
+       status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
+       if (status != 0) {
+               printk(KERN_ERR
+                      "RTAS query-cpu-stopped-state failed: %i\n", status);
+               return status;
+       }
+
+       return cpu_status;
+}
+
+static int pseries_cpu_disable(void)
+{
+       int cpu = smp_processor_id();
+
+       cpu_clear(cpu, cpu_online_map);
+       vdso_data->processorCount--;
+
+       /*fix boot_cpuid here*/
+       if (cpu == boot_cpuid)
+               boot_cpuid = any_online_cpu(cpu_online_map);
+
+       /* FIXME: abstract this to not be platform specific later on */
+       xics_migrate_irqs_away();
+       return 0;
+}
+
+static void pseries_cpu_die(unsigned int cpu)
+{
+       int tries;
+       int cpu_status;
+       unsigned int pcpu = get_hard_smp_processor_id(cpu);
+
+       for (tries = 0; tries < 25; tries++) {
+               cpu_status = query_cpu_stopped(pcpu);
+               if (cpu_status == 0 || cpu_status == -1)
+                       break;
+               msleep(200);
+       }
+       if (cpu_status != 0) {
+               printk("Querying DEAD? cpu %i (%i) shows %i\n",
+                      cpu, pcpu, cpu_status);
+       }
+
+       /* Isolation and deallocation are definatly done by
+        * drslot_chrp_cpu.  If they were not they would be
+        * done here.  Change isolate state to Isolate and
+        * change allocation-state to Unusable.
+        */
+       paca[cpu].cpu_start = 0;
+}
+
+/*
+ * Update cpu_present_map and paca(s) for a new cpu node.  The wrinkle
+ * here is that a cpu device node may represent up to two logical cpus
+ * in the SMT case.  We must honor the assumption in other code that
+ * the logical ids for sibling SMT threads x and y are adjacent, such
+ * that x^1 == y and y^1 == x.
+ */
+static int pseries_add_processor(struct device_node *np)
+{
+       unsigned int cpu;
+       cpumask_t candidate_map, tmp = CPU_MASK_NONE;
+       int err = -ENOSPC, len, nthreads, i;
+       const u32 *intserv;
+
+       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       if (!intserv)
+               return 0;
+
+       nthreads = len / sizeof(u32);
+       for (i = 0; i < nthreads; i++)
+               cpu_set(i, tmp);
+
+       lock_cpu_hotplug();
+
+       BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
+
+       /* Get a bitmap of unoccupied slots. */
+       cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
+       if (cpus_empty(candidate_map)) {
+               /* If we get here, it most likely means that NR_CPUS is
+                * less than the partition's max processors setting.
+                */
+               printk(KERN_ERR "Cannot add cpu %s; this system configuration"
+                      " supports %d logical cpus.\n", np->full_name,
+                      cpus_weight(cpu_possible_map));
+               goto out_unlock;
+       }
+
+       while (!cpus_empty(tmp))
+               if (cpus_subset(tmp, candidate_map))
+                       /* Found a range where we can insert the new cpu(s) */
+                       break;
+               else
+                       cpus_shift_left(tmp, tmp, nthreads);
+
+       if (cpus_empty(tmp)) {
+               printk(KERN_ERR "Unable to find space in cpu_present_map for"
+                      " processor %s with %d thread(s)\n", np->name,
+                      nthreads);
+               goto out_unlock;
+       }
+
+       for_each_cpu_mask(cpu, tmp) {
+               BUG_ON(cpu_isset(cpu, cpu_present_map));
+               cpu_set(cpu, cpu_present_map);
+               set_hard_smp_processor_id(cpu, *intserv++);
+       }
+       err = 0;
+out_unlock:
+       unlock_cpu_hotplug();
+       return err;
+}
+
+/*
+ * Update the present map for a cpu node which is going away, and set
+ * the hard id in the paca(s) to -1 to be consistent with boot time
+ * convention for non-present cpus.
+ */
+static void pseries_remove_processor(struct device_node *np)
+{
+       unsigned int cpu;
+       int len, nthreads, i;
+       const u32 *intserv;
+
+       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+       if (!intserv)
+               return;
+
+       nthreads = len / sizeof(u32);
+
+       lock_cpu_hotplug();
+       for (i = 0; i < nthreads; i++) {
+               for_each_present_cpu(cpu) {
+                       if (get_hard_smp_processor_id(cpu) != intserv[i])
+                               continue;
+                       BUG_ON(cpu_online(cpu));
+                       cpu_clear(cpu, cpu_present_map);
+                       set_hard_smp_processor_id(cpu, -1);
+                       break;
+               }
+               if (cpu == NR_CPUS)
+                       printk(KERN_WARNING "Could not find cpu to remove "
+                              "with physical id 0x%x\n", intserv[i]);
+       }
+       unlock_cpu_hotplug();
+}
+
+static int pseries_smp_notifier(struct notifier_block *nb,
+                               unsigned long action, void *node)
+{
+       int err = NOTIFY_OK;
+
+       switch (action) {
+       case PSERIES_RECONFIG_ADD:
+               if (pseries_add_processor(node))
+                       err = NOTIFY_BAD;
+               break;
+       case PSERIES_RECONFIG_REMOVE:
+               pseries_remove_processor(node);
+               break;
+       default:
+               err = NOTIFY_DONE;
+               break;
+       }
+       return err;
+}
+
+static struct notifier_block pseries_smp_nb = {
+       .notifier_call = pseries_smp_notifier,
+};
+
+static int __init pseries_cpu_hotplug_init(void)
+{
+       rtas_stop_self_args.token = rtas_token("stop-self");
+       qcss_tok = rtas_token("query-cpu-stopped-state");
+
+       if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+                       qcss_tok == RTAS_UNKNOWN_SERVICE) {
+               printk(KERN_INFO "CPU Hotplug not supported by firmware "
+                               "- disabling.\n");
+               return 0;
+       }
+
+       ppc_md.cpu_die = pseries_mach_cpu_die;
+       smp_ops->cpu_disable = pseries_cpu_disable;
+       smp_ops->cpu_die = pseries_cpu_die;
+
+       /* Processors can be added/removed only on LPAR */
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               pSeries_reconfig_notifier_register(&pseries_smp_nb);
+
+       return 0;
+}
+arch_initcall(pseries_cpu_hotplug_init);
index 0dc2548ca9bcdd45bebf827db6aa2fe813b20bb0..042ecae107ac89066c5596ab0ccafe58161539d9 100644 (file)
@@ -347,21 +347,6 @@ static int __init pSeries_init_panel(void)
 }
 arch_initcall(pSeries_init_panel);
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void pSeries_mach_cpu_die(void)
-{
-       local_irq_disable();
-       idle_task_exit();
-       xics_teardown_cpu(0);
-       rtas_stop_self();
-       /* Should never get here... */
-       BUG();
-       for(;;);
-}
-#else
-#define pSeries_mach_cpu_die NULL
-#endif
-
 static int pseries_set_dabr(unsigned long dabr)
 {
        return plpar_hcall_norets(H_SET_DABR, dabr);
@@ -437,19 +422,14 @@ static int __init pSeries_probe_hypertas(unsigned long node,
        if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
                powerpc_firmware_features |= FW_FEATURE_LPAR;
 
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               hpte_init_lpar();
-       else
-               hpte_init_native();
-
        return 1;
 }
 
 static int __init pSeries_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
-       char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
-                                         "device_type", NULL);
+       char *dtype = of_get_flat_dt_prop(root, "device_type", NULL);
+
        if (dtype == NULL)
                return 0;
        if (strcmp(dtype, "chrp"))
@@ -467,6 +447,11 @@ static int __init pSeries_probe(void)
        /* Now try to figure out if we are running on LPAR */
        of_scan_flat_dt(pSeries_probe_hypertas, NULL);
 
+       if (firmware_has_feature(FW_FEATURE_LPAR))
+               hpte_init_lpar();
+       else
+               hpte_init_native();
+
        DBG("Machine is%s LPAR !\n",
            (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
 
@@ -561,7 +546,6 @@ define_machine(pseries) {
        .power_off              = rtas_power_off,
        .halt                   = rtas_halt,
        .panic                  = rtas_os_term,
-       .cpu_die                = pSeries_mach_cpu_die,
        .get_boot_time          = rtas_get_boot_time,
        .get_rtc_time           = rtas_get_rtc_time,
        .set_rtc_time           = rtas_set_rtc_time,
index c6624b8a0e774b2aca2e3dab6fc268785f623318..4408518eaebe4afe76d6a1b3f354a4a6cc0a0421 100644 (file)
@@ -64,197 +64,6 @@ static cpumask_t of_spin_map;
 
 extern void generic_secondary_smp_init(unsigned long);
 
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* Get state of physical CPU.
- * Return codes:
- *     0       - The processor is in the RTAS stopped state
- *     1       - stop-self is in progress
- *     2       - The processor is not in the RTAS stopped state
- *     -1      - Hardware Error
- *     -2      - Hardware Busy, Try again later.
- */
-static int query_cpu_stopped(unsigned int pcpu)
-{
-       int cpu_status;
-       int status, qcss_tok;
-
-       qcss_tok = rtas_token("query-cpu-stopped-state");
-       if (qcss_tok == RTAS_UNKNOWN_SERVICE)
-               return -1;
-       status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
-       if (status != 0) {
-               printk(KERN_ERR
-                      "RTAS query-cpu-stopped-state failed: %i\n", status);
-               return status;
-       }
-
-       return cpu_status;
-}
-
-static int pSeries_cpu_disable(void)
-{
-       int cpu = smp_processor_id();
-
-       cpu_clear(cpu, cpu_online_map);
-       vdso_data->processorCount--;
-
-       /*fix boot_cpuid here*/
-       if (cpu == boot_cpuid)
-               boot_cpuid = any_online_cpu(cpu_online_map);
-
-       /* FIXME: abstract this to not be platform specific later on */
-       xics_migrate_irqs_away();
-       return 0;
-}
-
-static void pSeries_cpu_die(unsigned int cpu)
-{
-       int tries;
-       int cpu_status;
-       unsigned int pcpu = get_hard_smp_processor_id(cpu);
-
-       for (tries = 0; tries < 25; tries++) {
-               cpu_status = query_cpu_stopped(pcpu);
-               if (cpu_status == 0 || cpu_status == -1)
-                       break;
-               msleep(200);
-       }
-       if (cpu_status != 0) {
-               printk("Querying DEAD? cpu %i (%i) shows %i\n",
-                      cpu, pcpu, cpu_status);
-       }
-
-       /* Isolation and deallocation are definatly done by
-        * drslot_chrp_cpu.  If they were not they would be
-        * done here.  Change isolate state to Isolate and
-        * change allocation-state to Unusable.
-        */
-       paca[cpu].cpu_start = 0;
-}
-
-/*
- * Update cpu_present_map and paca(s) for a new cpu node.  The wrinkle
- * here is that a cpu device node may represent up to two logical cpus
- * in the SMT case.  We must honor the assumption in other code that
- * the logical ids for sibling SMT threads x and y are adjacent, such
- * that x^1 == y and y^1 == x.
- */
-static int pSeries_add_processor(struct device_node *np)
-{
-       unsigned int cpu;
-       cpumask_t candidate_map, tmp = CPU_MASK_NONE;
-       int err = -ENOSPC, len, nthreads, i;
-       const u32 *intserv;
-
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
-       if (!intserv)
-               return 0;
-
-       nthreads = len / sizeof(u32);
-       for (i = 0; i < nthreads; i++)
-               cpu_set(i, tmp);
-
-       lock_cpu_hotplug();
-
-       BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map));
-
-       /* Get a bitmap of unoccupied slots. */
-       cpus_xor(candidate_map, cpu_possible_map, cpu_present_map);
-       if (cpus_empty(candidate_map)) {
-               /* If we get here, it most likely means that NR_CPUS is
-                * less than the partition's max processors setting.
-                */
-               printk(KERN_ERR "Cannot add cpu %s; this system configuration"
-                      " supports %d logical cpus.\n", np->full_name,
-                      cpus_weight(cpu_possible_map));
-               goto out_unlock;
-       }
-
-       while (!cpus_empty(tmp))
-               if (cpus_subset(tmp, candidate_map))
-                       /* Found a range where we can insert the new cpu(s) */
-                       break;
-               else
-                       cpus_shift_left(tmp, tmp, nthreads);
-
-       if (cpus_empty(tmp)) {
-               printk(KERN_ERR "Unable to find space in cpu_present_map for"
-                      " processor %s with %d thread(s)\n", np->name,
-                      nthreads);
-               goto out_unlock;
-       }
-
-       for_each_cpu_mask(cpu, tmp) {
-               BUG_ON(cpu_isset(cpu, cpu_present_map));
-               cpu_set(cpu, cpu_present_map);
-               set_hard_smp_processor_id(cpu, *intserv++);
-       }
-       err = 0;
-out_unlock:
-       unlock_cpu_hotplug();
-       return err;
-}
-
-/*
- * Update the present map for a cpu node which is going away, and set
- * the hard id in the paca(s) to -1 to be consistent with boot time
- * convention for non-present cpus.
- */
-static void pSeries_remove_processor(struct device_node *np)
-{
-       unsigned int cpu;
-       int len, nthreads, i;
-       const u32 *intserv;
-
-       intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
-       if (!intserv)
-               return;
-
-       nthreads = len / sizeof(u32);
-
-       lock_cpu_hotplug();
-       for (i = 0; i < nthreads; i++) {
-               for_each_present_cpu(cpu) {
-                       if (get_hard_smp_processor_id(cpu) != intserv[i])
-                               continue;
-                       BUG_ON(cpu_online(cpu));
-                       cpu_clear(cpu, cpu_present_map);
-                       set_hard_smp_processor_id(cpu, -1);
-                       break;
-               }
-               if (cpu == NR_CPUS)
-                       printk(KERN_WARNING "Could not find cpu to remove "
-                              "with physical id 0x%x\n", intserv[i]);
-       }
-       unlock_cpu_hotplug();
-}
-
-static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
-       int err = NOTIFY_OK;
-
-       switch (action) {
-       case PSERIES_RECONFIG_ADD:
-               if (pSeries_add_processor(node))
-                       err = NOTIFY_BAD;
-               break;
-       case PSERIES_RECONFIG_REMOVE:
-               pSeries_remove_processor(node);
-               break;
-       default:
-               err = NOTIFY_DONE;
-               break;
-       }
-       return err;
-}
-
-static struct notifier_block pSeries_smp_nb = {
-       .notifier_call = pSeries_smp_notifier,
-};
-
-#endif /* CONFIG_HOTPLUG_CPU */
-
 /**
  * smp_startup_cpu() - start the given cpu
  *
@@ -422,15 +231,6 @@ static void __init smp_init_pseries(void)
 
        DBG(" -> smp_init_pSeries()\n");
 
-#ifdef CONFIG_HOTPLUG_CPU
-       smp_ops->cpu_disable = pSeries_cpu_disable;
-       smp_ops->cpu_die = pSeries_cpu_die;
-
-       /* Processors can be added/removed only on LPAR */
-       if (firmware_has_feature(FW_FEATURE_LPAR))
-               pSeries_reconfig_notifier_register(&pSeries_smp_nb);
-#endif
-
        /* Mark threads which are still spinning in hold loops. */
        if (cpu_has_feature(CPU_FTR_SMT)) {
                for_each_present_cpu(i) { 
index 6cc34597a620202e901927359bf9207664ffb0a8..04d4917eb3035c4140d184e1c740b6fc9eb535cd 100644 (file)
@@ -5,7 +5,8 @@ endif
 obj-$(CONFIG_MPIC)             += mpic.o
 obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)       += grackle.o
-obj-$(CONFIG_PPC_DCR)          += dcr.o dcr-low.o
+obj-$(CONFIG_PPC_DCR)          += dcr.o
+obj-$(CONFIG_PPC_DCR_NATIVE)   += dcr-low.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
diff --git a/arch/powerpc/sysdev/dcr.S b/arch/powerpc/sysdev/dcr.S
deleted file mode 100644 (file)
index 2078f39..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * "Indirect" DCR access
- *
- * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <asm/ppc_asm.h>
-#include <asm/processor.h>
-
-#define DCR_ACCESS_PROLOG(table) \
-       rlwinm  r3,r3,4,18,27;   \
-       lis     r5,table@h;      \
-       ori     r5,r5,table@l;   \
-       add     r3,r3,r5;        \
-       mtctr   r3;              \
-       bctr
-
-_GLOBAL(__mfdcr)
-       DCR_ACCESS_PROLOG(__mfdcr_table)
-
-_GLOBAL(__mtdcr)
-       DCR_ACCESS_PROLOG(__mtdcr_table)
-
-__mfdcr_table:
-       mfdcr  r3,0; blr
-__mtdcr_table:
-       mtdcr  0,r4; blr
-
-dcr     = 1
-        .rept   1023
-       mfdcr   r3,dcr; blr
-       mtdcr   dcr,r4; blr
-       dcr     = dcr + 1
-       .endr
index 6995f51b94882bdcf55815572c305d42516e4771..74e48d94f27ced66c0ed03fad91644a5cdb26222 100644 (file)
@@ -223,23 +223,15 @@ static void qe_ic_mask_irq(unsigned int virq)
        qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
                    temp & ~qe_ic_info[src].mask);
 
-       spin_unlock_irqrestore(&qe_ic_lock, flags);
-}
-
-static void qe_ic_mask_irq_and_ack(unsigned int virq)
-{
-       struct qe_ic *qe_ic = qe_ic_from_irq(virq);
-       unsigned int src = virq_to_hw(virq);
-       unsigned long flags;
-       u32 temp;
-
-       spin_lock_irqsave(&qe_ic_lock, flags);
-
-       temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
-       qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
-                   temp & ~qe_ic_info[src].mask);
-
-       /* There is nothing to do for ack here, ack is handled in ISR */
+       /* Flush the above write before enabling interrupts; otherwise,
+        * spurious interrupts will sometimes happen.  To be 100% sure
+        * that the write has reached the device before interrupts are
+        * enabled, the mask register would have to be read back; however,
+        * this is not required for correctness, only to avoid wasting
+        * time on a large number of spurious interrupts.  In testing,
+        * a sync reduced the observed spurious interrupts to zero.
+        */
+       mb();
 
        spin_unlock_irqrestore(&qe_ic_lock, flags);
 }
@@ -248,7 +240,7 @@ static struct irq_chip qe_ic_irq_chip = {
        .typename = " QEIC  ",
        .unmask = qe_ic_unmask_irq,
        .mask = qe_ic_mask_irq,
-       .mask_ack = qe_ic_mask_irq_and_ack,
+       .mask_ack = qe_ic_mask_irq,
 };
 
 static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
@@ -331,34 +323,22 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
        return irq_linear_revmap(qe_ic->irqhost, irq);
 }
 
-/* FIXME: We mask all the QE Low interrupts while handling.  We should
- * let other interrupt come in, but BAD interrupts are generated */
 void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
 {
        struct qe_ic *qe_ic = desc->handler_data;
-       struct irq_chip *chip = irq_desc[irq].chip;
-
        unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
 
-       chip->mask_ack(irq);
        if (cascade_irq != NO_IRQ)
                generic_handle_irq(cascade_irq);
-       chip->unmask(irq);
 }
 
-/* FIXME: We mask all the QE High interrupts while handling.  We should
- * let other interrupt come in, but BAD interrupts are generated */
 void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
 {
        struct qe_ic *qe_ic = desc->handler_data;
-       struct irq_chip *chip = irq_desc[irq].chip;
-
        unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
 
-       chip->mask_ack(irq);
        if (cascade_irq != NO_IRQ)
                generic_handle_irq(cascade_irq);
-       chip->unmask(irq);
 }
 
 void __init qe_ic_init(struct device_node *node, unsigned int flags)
index bf5b3f10e6c600099011cab1ab9f0ccbd221a635..c855a3b298a3f253af247c949db8813622b47ba9 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 static int __init powerpc_flash_init(void)
 {
index a34ed49e0356c418a81fa5cfc85e0f47c0cd84a3..77540a2f77040734396570889e6127230d965404 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/bug.h>
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
@@ -35,7 +36,6 @@
 #include <asm/cputable.h>
 #include <asm/rtas.h>
 #include <asm/sstep.h>
-#include <asm/bug.h>
 #include <asm/irq_regs.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
@@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp)
 
 static void print_bug_trap(struct pt_regs *regs)
 {
-       struct bug_entry *bug;
+       const struct bug_entry *bug;
        unsigned long addr;
 
        if (regs->msr & MSR_PR)
@@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs)
        bug = find_bug(regs->nip);
        if (bug == NULL)
                return;
-       if (bug->line & BUG_WARNING_TRAP)
+       if (is_warning_bug(bug))
                return;
 
-       printf("kernel BUG in %s at %s:%d!\n",
-              bug->function, bug->file, (unsigned int)bug->line);
+       printf("kernel BUG at %s:%u!\n",
+              bug->file, bug->line);
 }
 
 void excprint(struct pt_regs *fp)
index 63808e01cb0b7cc51ea75c20885c630d8ef63ea4..5e723c4c2571b0a3dc886032a92681a9927b9d7c 100644 (file)
@@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
 
 
 static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
-                                              unsigned long *offset,
+                                              resource_size_t *offset,
                                               enum pci_mmap_state mmap_state)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
@@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
 
        /* If memory, add on the PCI bridge address offset */
        if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
                *offset += hose->pci_mem_offset;
+#endif
                res_bit = IORESOURCE_MEM;
        } else {
                io_offset = hose->io_base_virt - ___IO_BASE;
@@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state,
                        int write_combine)
 {
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
        struct resource *rp;
        int ret;
 
@@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          resource_size_t *start, resource_size_t *end)
 {
        struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-       unsigned long offset = 0;
+       resource_size_t offset = 0;
 
        if (hose == NULL)
                return;
 
        if (rsrc->flags & IORESOURCE_IO)
-               offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+       /* We pass a fully fixed up address to userland for MMIO instead of
+        * a BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem !
+        *
+        * That means that we'll have potentially 64 bits values where some
+        * userland apps only expect 32 (like X itself since it thinks only
+        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+        * 32 bits CHRPs :-(
+        *
+        * Hopefully, the sysfs insterface is immune to that gunk. Once X
+        * has been fixed (and the fix spread enough), we can re-enable the
+        * 2 lines below and pass down a BAR value to userland. In that case
+        * we'll also have to re-enable the matching code in
+        * __pci_mmap_make_offset().
+        *
+        * BenH.
+        */
+#if 0
+       else if (rsrc->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+#endif
 
-       *start = rsrc->start + offset;
-       *end = rsrc->end + offset;
+       *start = rsrc->start - offset;
+       *end = rsrc->end - offset;
 }
 
-void __init
-pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
-                 int flags, char *name)
+void __init pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name)
 {
        res->start = start;
        res->end = end;
index b52d547b7a78e38fac23e036170e9444224090f0..8433eb7562cb2c9ceb77e365564e12de90bae8d9 100644 (file)
@@ -1 +1,2 @@
 obj-y += system-bus.o
+obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
new file mode 100644 (file)
index 0000000..6974f65
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ *  PS3 virtual uart
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 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 <asm/ps3.h>
+
+#include <asm/lv1call.h>
+#include <asm/bitops.h>
+
+#include "vuart.h"
+
+MODULE_AUTHOR("Sony Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ps3 vuart");
+
+/**
+ * vuart - An inter-partition data link service.
+ *  port 0: PS3 AV Settings.
+ *  port 2: PS3 System Manager.
+ *
+ * The vuart provides a bi-directional byte stream data link between logical
+ * partitions.  Its primary role is as a communications link between the guest
+ * OS and the system policy module.  The current HV does not support any
+ * connections other than those listed.
+ */
+
+enum {PORT_COUNT = 3,};
+
+enum vuart_param {
+       PARAM_TX_TRIGGER = 0,
+       PARAM_RX_TRIGGER = 1,
+       PARAM_INTERRUPT_MASK = 2,
+       PARAM_RX_BUF_SIZE = 3, /* read only */
+       PARAM_RX_BYTES = 4, /* read only */
+       PARAM_TX_BUF_SIZE = 5, /* read only */
+       PARAM_TX_BYTES = 6, /* read only */
+       PARAM_INTERRUPT_STATUS = 7, /* read only */
+};
+
+enum vuart_interrupt_bit {
+       INTERRUPT_BIT_TX = 0,
+       INTERRUPT_BIT_RX = 1,
+       INTERRUPT_BIT_DISCONNECT = 2,
+};
+
+enum vuart_interrupt_mask {
+       INTERRUPT_MASK_TX = 1,
+       INTERRUPT_MASK_RX = 2,
+       INTERRUPT_MASK_DISCONNECT = 4,
+};
+
+/**
+ * struct ports_bmp - bitmap indicating ports needing service.
+ *
+ * A 256 bit read only bitmap indicating ports needing service.  Do not write
+ * to these bits.  Must not cross a page boundary.
+ */
+
+struct ports_bmp {
+       u64 status;
+       u64 unused[3];
+} __attribute__ ((aligned (32)));
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_ports_bmp(
+       const struct ports_bmp* bmp, const char* func, int line)
+{
+       pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
+}
+
+static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
+       unsigned int *port_number)
+{
+       switch(match_id) {
+       case PS3_MATCH_ID_AV_SETTINGS:
+               *port_number = 0;
+               return 0;
+       case PS3_MATCH_ID_SYSTEM_MANAGER:
+               *port_number = 2;
+               return 0;
+       default:
+               WARN_ON(1);
+               *port_number = UINT_MAX;
+               return -EINVAL;
+       };
+}
+
+#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
+static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
+       const char* func, int line)
+{
+#if defined(DEBUG)
+       static const char *strings[] = {
+               "tx_trigger      ",
+               "rx_trigger      ",
+               "interrupt_mask  ",
+               "rx_buf_size     ",
+               "rx_bytes        ",
+               "tx_buf_size     ",
+               "tx_bytes        ",
+               "interrupt_status",
+       };
+       int result;
+       unsigned int i;
+       u64 value;
+
+       for (i = 0; i < ARRAY_SIZE(strings); i++) {
+               result = lv1_get_virtual_uart_param(port_number, i, &value);
+
+               if (result) {
+                       pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
+                               port_number, strings[i], ps3_result(result));
+                       continue;
+               }
+               pr_debug("%s:%d: port_%u: %s = %lxh\n",
+                       func, line, port_number, strings[i], value);
+       }
+#endif
+}
+
+struct vuart_triggers {
+       unsigned long rx;
+       unsigned long tx;
+};
+
+int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
+       struct vuart_triggers *trig)
+{
+       int result;
+       unsigned long size;
+       unsigned long val;
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_TX_TRIGGER, &trig->tx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BUF_SIZE, &size);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_TRIGGER, &val);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       trig->rx = size - val;
+
+       dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
+               trig->tx, trig->rx);
+
+       return result;
+}
+
+int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
+       unsigned int rx)
+{
+       int result;
+       unsigned long size;
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_TX_TRIGGER, tx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BUF_SIZE, &size);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_RX_TRIGGER, size - rx);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
+               tx, rx);
+
+       return result;
+}
+
+static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
+       unsigned long *bytes_waiting)
+{
+       int result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_RX_BYTES, bytes_waiting);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
+               *bytes_waiting);
+       return result;
+}
+
+static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
+       unsigned long mask)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
+
+       dev->interrupt_mask = mask;
+
+       result = lv1_set_virtual_uart_param(dev->port_number,
+               PARAM_INTERRUPT_MASK, dev->interrupt_mask);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       return result;
+}
+
+static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
+       unsigned long *status)
+{
+       int result = lv1_get_virtual_uart_param(dev->port_number,
+               PARAM_INTERRUPT_STATUS, status);
+
+       if (result)
+               dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
+               __func__, __LINE__, dev->interrupt_mask, *status,
+               dev->interrupt_mask & *status);
+
+       return result;
+}
+
+int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_TX);
+}
+
+int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_RX);
+}
+
+int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
+               : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               | INTERRUPT_MASK_DISCONNECT);
+}
+
+int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_TX)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_TX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_RX)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_RX) : 0;
+}
+
+int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+{
+       return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
+               ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+               & ~INTERRUPT_MASK_DISCONNECT) : 0;
+}
+
+/**
+ * ps3_vuart_raw_write - Low level write helper.
+ *
+ * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
+ */
+
+static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
+       const void* buf, unsigned int bytes, unsigned long *bytes_written)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+       result = lv1_write_virtual_uart(dev->port_number,
+               ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
+                       "%s\n", __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev->stats.bytes_written += *bytes_written;
+
+       dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
+               __LINE__, *bytes_written, bytes, dev->stats.bytes_written);
+
+       return result;
+}
+
+/**
+ * ps3_vuart_raw_read - Low level read helper.
+ *
+ * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
+ */
+
+static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes, unsigned long *bytes_read)
+{
+       int result;
+
+       dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
+
+       result = lv1_read_virtual_uart(dev->port_number,
+               ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       dev->stats.bytes_read += *bytes_read;
+
+       dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
+               *bytes_read, bytes, dev->stats.bytes_read);
+
+       return result;
+}
+
+/**
+ * struct list_buffer - An element for a port device fifo buffer list.
+ */
+
+struct list_buffer {
+       struct list_head link;
+       const unsigned char *head;
+       const unsigned char *tail;
+       unsigned long dbg_number;
+       unsigned char data[];
+};
+
+/**
+ * ps3_vuart_write - the entry point for writing data to a port
+ *
+ * If the port is idle on entry as much of the incoming data is written to
+ * the port as the port will accept.  Otherwise a list buffer is created
+ * and any remaning incoming data is copied to that buffer.  The buffer is
+ * then enqueued for transmision via the transmit interrupt.
+ */
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+       unsigned int bytes)
+{
+       static unsigned long dbg_number;
+       int result;
+       unsigned long flags;
+       struct list_buffer *lb;
+
+       dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+               bytes, bytes);
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+       if (list_empty(&dev->tx_list.head)) {
+               unsigned long bytes_written;
+
+               result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
+
+               spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_vuart_raw_write failed\n",
+                               __func__, __LINE__);
+                       return result;
+               }
+
+               if (bytes_written == bytes) {
+                       dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
+                               __func__, __LINE__, bytes);
+                       return 0;
+               }
+
+               bytes -= bytes_written;
+               buf += bytes_written;
+       } else
+               spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+       lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
+
+       if (!lb) {
+               return -ENOMEM;
+       }
+
+       memcpy(lb->data, buf, bytes);
+       lb->head = lb->data;
+       lb->tail = lb->data + bytes;
+       lb->dbg_number = ++dbg_number;
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+       list_add_tail(&lb->link, &dev->tx_list.head);
+       ps3_vuart_enable_interrupt_tx(dev);
+       spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+/**
+ * ps3_vuart_read - the entry point for reading data from a port
+ *
+ * If enough bytes to satisfy the request are held in the buffer list those
+ * bytes are dequeued and copied to the caller's buffer.  Emptied list buffers
+ * are retiered.  If the request cannot be statified by bytes held in the list
+ * buffers -EAGAIN is returned.
+ */
+
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes)
+{
+       unsigned long flags;
+       struct list_buffer *lb, *n;
+       unsigned long bytes_read;
+
+       dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
+               bytes, bytes);
+
+       spin_lock_irqsave(&dev->rx_list.lock, flags);
+
+       if (dev->rx_list.bytes_held < bytes) {
+               spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+               dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
+                       __func__, __LINE__, bytes - dev->rx_list.bytes_held);
+               return -EAGAIN;
+       }
+
+       list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
+               bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
+
+               memcpy(buf, lb->head, bytes_read);
+               buf += bytes_read;
+               bytes -= bytes_read;
+               dev->rx_list.bytes_held -= bytes_read;
+
+               if (bytes_read < lb->tail - lb->head) {
+                       lb->head += bytes_read;
+                       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+                       dev_dbg(&dev->core,
+                               "%s:%d: dequeued buf_%lu, %lxh bytes\n",
+                               __func__, __LINE__, lb->dbg_number, bytes_read);
+                       return 0;
+               }
+
+               dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+                       lb->dbg_number);
+
+               list_del(&lb->link);
+               kfree(lb);
+       }
+       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
+ *
+ * Services the transmit interrupt for the port.  Writes as much data from the
+ * buffer list as the port will accept.  Retires any emptied list buffers and
+ * adjusts the final list buffer state for a partial write.
+ */
+
+static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
+{
+       int result = 0;
+       unsigned long flags;
+       struct list_buffer *lb, *n;
+       unsigned long bytes_total = 0;
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       spin_lock_irqsave(&dev->tx_list.lock, flags);
+
+       list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
+
+               unsigned long bytes_written;
+
+               result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
+                       &bytes_written);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_vuart_raw_write failed\n",
+                               __func__, __LINE__);
+                       break;
+               }
+
+               bytes_total += bytes_written;
+
+               if (bytes_written < lb->tail - lb->head) {
+                       lb->head += bytes_written;
+                       dev_dbg(&dev->core,
+                               "%s:%d cleared buf_%lu, %lxh bytes\n",
+                               __func__, __LINE__, lb->dbg_number,
+                               bytes_written);
+                       goto port_full;
+               }
+
+               dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
+                       lb->dbg_number);
+
+               list_del(&lb->link);
+               kfree(lb);
+       }
+
+       ps3_vuart_disable_interrupt_tx(dev);
+port_full:
+       spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+       dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
+               __func__, __LINE__, bytes_total);
+       return result;
+}
+
+/**
+ * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
+ *
+ * Services the receive interrupt for the port.  Creates a list buffer and
+ * copies all waiting port data to that buffer and enqueues the buffer in the
+ * buffer list.  Buffer list data is dequeued via ps3_vuart_read.
+ */
+
+static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
+{
+       static unsigned long dbg_number;
+       int result = 0;
+       unsigned long flags;
+       struct list_buffer *lb;
+       unsigned long bytes;
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
+
+       if (result)
+               return -EIO;
+
+       BUG_ON(!bytes);
+
+       /* add some extra space for recently arrived data */
+
+       bytes += 128;
+
+       lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
+
+       if (!lb)
+               return -ENOMEM;
+
+       ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
+
+       lb->head = lb->data;
+       lb->tail = lb->data + bytes;
+       lb->dbg_number = ++dbg_number;
+
+       spin_lock_irqsave(&dev->rx_list.lock, flags);
+       list_add_tail(&lb->link, &dev->rx_list.head);
+       dev->rx_list.bytes_held += bytes;
+       spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
+               __func__, __LINE__, lb->dbg_number, bytes);
+
+       return 0;
+}
+
+static int ps3_vuart_handle_interrupt_disconnect(
+       struct ps3_vuart_port_device *dev)
+{
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+       BUG_ON("no support");
+       return -1;
+}
+
+/**
+ * ps3_vuart_handle_port_interrupt - second stage interrupt handler
+ *
+ * Services any pending interrupt types for the port.  Passes control to the
+ * third stage type specific interrupt handler.  Returns control to the first
+ * stage handler after one iteration.
+ */
+
+static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
+{
+       int result;
+       unsigned long status;
+
+       result = ps3_vuart_get_interrupt_mask(dev, &status);
+
+       if (result)
+               return result;
+
+       dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
+               status);
+
+       if (status & INTERRUPT_MASK_DISCONNECT) {
+               dev->stats.disconnect_interrupts++;
+               result = ps3_vuart_handle_interrupt_disconnect(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_disconnect(dev);
+       }
+
+       if (status & INTERRUPT_MASK_TX) {
+               dev->stats.tx_interrupts++;
+               result = ps3_vuart_handle_interrupt_tx(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_tx(dev);
+       }
+
+       if (status & INTERRUPT_MASK_RX) {
+               dev->stats.rx_interrupts++;
+               result = ps3_vuart_handle_interrupt_rx(dev);
+               if (result)
+                       ps3_vuart_disable_interrupt_rx(dev);
+       }
+
+       return 0;
+}
+
+struct vuart_private {
+       unsigned int in_use;
+       unsigned int virq;
+       struct ps3_vuart_port_device *devices[PORT_COUNT];
+       const struct ports_bmp bmp;
+};
+
+/**
+ * ps3_vuart_irq_handler - first stage interrupt handler
+ *
+ * Loops finding any interrupting port and its associated instance data.
+ * Passes control to the second stage port specific interrupt handler.  Loops
+ * until all outstanding interrupts are serviced.
+ */
+
+static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
+{
+       struct vuart_private *private;
+
+       BUG_ON(!_private);
+       private = (struct vuart_private *)_private;
+
+       while (1) {
+               unsigned int port;
+
+               dump_ports_bmp(&private->bmp);
+
+               port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
+
+               if (port == BITS_PER_LONG)
+                       break;
+
+               BUG_ON(port >= PORT_COUNT);
+               BUG_ON(!private->devices[port]);
+
+               ps3_vuart_handle_port_interrupt(private->devices[port]);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
+{
+       int result;
+       struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+
+       result = dev->match_id == drv->match_id;
+
+       dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
+               __LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
+               drv->core.name, (result ? "match" : "miss"));
+
+       return result;
+}
+
+static struct vuart_private vuart_private;
+
+static int ps3_vuart_probe(struct device *_dev)
+{
+       int result;
+       unsigned long tmp;
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+       struct ps3_vuart_port_driver *drv =
+               to_ps3_vuart_port_driver(_dev->driver);
+
+       dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+       BUG_ON(!drv);
+
+       result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
+                       __func__, __LINE__, dev->match_id);
+               result = -EINVAL;
+               goto fail_match;
+       }
+
+       if (vuart_private.devices[dev->port_number]) {
+               dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
+                       __LINE__, dev->port_number);
+               result = -EBUSY;
+               goto fail_match;
+       }
+
+       vuart_private.devices[dev->port_number] = dev;
+
+       INIT_LIST_HEAD(&dev->tx_list.head);
+       spin_lock_init(&dev->tx_list.lock);
+       INIT_LIST_HEAD(&dev->rx_list.head);
+       spin_lock_init(&dev->rx_list.lock);
+
+       vuart_private.in_use++;
+       if (vuart_private.in_use == 1) {
+               result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
+                       &vuart_private.virq);
+
+               if (result) {
+                       dev_dbg(&dev->core,
+                               "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+                               __func__, __LINE__, result);
+                       result = -EPERM;
+                       goto fail_alloc_irq;
+               }
+
+               result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
+                       IRQF_DISABLED, "vuart", &vuart_private);
+
+               if (result) {
+                       dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
+                               __func__, __LINE__, result);
+                       goto fail_request_irq;
+               }
+       }
+
+       ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
+
+       /* clear stale pending interrupts */
+       ps3_vuart_get_interrupt_mask(dev, &tmp);
+
+       ps3_vuart_set_triggers(dev, 1, 1);
+
+       if (drv->probe)
+               result = drv->probe(dev);
+       else {
+               result = 0;
+               dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
+                       __LINE__);
+       }
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
+                       __func__, __LINE__);
+               goto fail_probe;
+       }
+
+       return result;
+
+fail_probe:
+fail_request_irq:
+       vuart_private.in_use--;
+       if (!vuart_private.in_use) {
+               ps3_free_vuart_irq(vuart_private.virq);
+               vuart_private.virq = NO_IRQ;
+       }
+fail_alloc_irq:
+fail_match:
+       dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
+       return result;
+}
+
+static int ps3_vuart_remove(struct device *_dev)
+{
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+       struct ps3_vuart_port_driver *drv =
+               to_ps3_vuart_port_driver(_dev->driver);
+
+       dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
+               dev->core.bus_id);
+
+       BUG_ON(vuart_private.in_use < 1);
+
+       if (drv->remove)
+               drv->remove(dev);
+       else
+               dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
+                       __LINE__, dev->core.bus_id);
+
+       vuart_private.in_use--;
+
+       if (!vuart_private.in_use) {
+               free_irq(vuart_private.virq, &vuart_private);
+               ps3_free_vuart_irq(vuart_private.virq);
+               vuart_private.virq = NO_IRQ;
+       }
+       return 0;
+}
+
+/**
+ * ps3_vuart - The vuart instance.
+ *
+ * The vuart is managed as a bus that port devices connect to.
+ */
+
+struct bus_type ps3_vuart = {
+        .name = "ps3_vuart",
+       .match = ps3_vuart_match,
+       .probe = ps3_vuart_probe,
+       .remove = ps3_vuart_remove,
+};
+
+int __init ps3_vuart_init(void)
+{
+       int result;
+
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       result = bus_register(&ps3_vuart);
+       BUG_ON(result);
+       return result;
+}
+
+void __exit ps3_vuart_exit(void)
+{
+       pr_debug("%s:%d:\n", __func__, __LINE__);
+       bus_unregister(&ps3_vuart);
+}
+
+core_initcall(ps3_vuart_init);
+module_exit(ps3_vuart_exit);
+
+/**
+ * ps3_vuart_port_release_device - Remove a vuart port device.
+ */
+
+static void ps3_vuart_port_release_device(struct device *_dev)
+{
+       struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+#if defined(DEBUG)
+       memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
+#endif
+       kfree(dev);
+}
+
+/**
+ * ps3_vuart_port_device_register - Add a vuart port device.
+ */
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
+{
+       int result;
+       static unsigned int dev_count = 1;
+
+       dev->core.parent = NULL;
+       dev->core.bus = &ps3_vuart;
+       dev->core.release = ps3_vuart_port_release_device;
+
+       snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
+               dev_count++);
+
+       dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
+
+       result = device_register(&dev->core);
+
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
+
+/**
+ * ps3_vuart_port_driver_register - Add a vuart port device driver.
+ */
+
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
+{
+       int result;
+
+       pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
+       drv->core.bus = &ps3_vuart;
+       result = driver_register(&drv->core);
+       return result;
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
+
+/**
+ * ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
+ */
+
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
+{
+       driver_unregister(&drv->core);
+}
+
+EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
new file mode 100644 (file)
index 0000000..28fd89f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  PS3 virtual uart
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 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
+ */
+
+#if !defined(_PS3_VUART_H)
+#define _PS3_VUART_H
+
+struct ps3_vuart_stats {
+       unsigned long bytes_written;
+       unsigned long bytes_read;
+       unsigned long tx_interrupts;
+       unsigned long rx_interrupts;
+       unsigned long disconnect_interrupts;
+};
+
+/**
+ * struct ps3_vuart_port_device - a device on a vuart port
+ */
+
+struct ps3_vuart_port_device {
+       enum ps3_match_id match_id;
+       struct device core;
+
+       /* private driver variables */
+       unsigned int port_number;
+       unsigned long interrupt_mask;
+       struct {
+               spinlock_t lock;
+               struct list_head head;
+       } tx_list;
+       struct {
+               unsigned long bytes_held;
+               spinlock_t lock;
+               struct list_head head;
+       } rx_list;
+       struct ps3_vuart_stats stats;
+};
+
+/**
+ * struct ps3_vuart_port_driver - a driver for a device on a vuart port
+ */
+
+struct ps3_vuart_port_driver {
+       enum ps3_match_id match_id;
+       struct device_driver core;
+       int (*probe)(struct ps3_vuart_port_device *);
+       int (*remove)(struct ps3_vuart_port_device *);
+       int (*tx_event)(struct ps3_vuart_port_device *dev);
+       int (*rx_event)(struct ps3_vuart_port_device *dev);
+       int (*disconnect_event)(struct ps3_vuart_port_device *dev);
+       /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
+       /* int (*resume)(struct ps3_vuart_port_device *); */
+};
+
+int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
+int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
+void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
+int ps3_vuart_write(struct ps3_vuart_port_device *dev,
+       const void* buf, unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes);
+static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
+       struct device_driver *_drv)
+{
+       return container_of(_drv, struct ps3_vuart_port_driver, core);
+}
+static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
+       struct device *_dev)
+{
+       return container_of(_dev, struct ps3_vuart_port_device, core);
+}
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+       unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+       unsigned int bytes);
+
+#endif
index 1e637381c118db47c3694253bf6bfbdb75fe9a92..703970fb0ec0d5d7bdf6b715c2becb7bbf7bd5f3 100644 (file)
@@ -17,7 +17,6 @@ header-y += ipc.h
 header-y += poll.h
 header-y += shmparam.h
 header-y += sockios.h
-header-y += spu_info.h
 header-y += ucontext.h
 header-y += ioctl.h
 header-y += linkage.h
@@ -37,6 +36,7 @@ unifdef-y += posix_types.h
 unifdef-y += ptrace.h
 unifdef-y += seccomp.h
 unifdef-y += signal.h
+unifdef-y += spu_info.h
 unifdef-y += termios.h
 unifdef-y += types.h
 unifdef-y += unistd.h
index 978b2c7e84eaf25f9d32a7ffb06c8744ed65fdf4..709568879f731e2367009c778465b639c997775a 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-struct bug_entry {
-       unsigned long   bug_addr;
-       long            line;
-       const char      *file;
-       const char      *function;
-};
-
-struct bug_entry *find_bug(unsigned long bugaddr);
-
-/*
- * If this bit is set in the line number it means that the trap
- * is for WARN_ON rather than BUG or BUG_ON.
- */
-#define BUG_WARNING_TRAP       0x1000000
-
 #ifdef CONFIG_BUG
 
+/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
+   sizeof(struct bug_entry), respectively */
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY                                \
+       ".section __bug_table,\"a\"\n"          \
+       "2:\t" PPC_LONG "1b, %0\n"              \
+       "\t.short %1, %2\n"                     \
+       ".org 2b+%3\n"                          \
+       ".previous\n"
+#else
+#define _EMIT_BUG_ENTRY                                \
+       ".section __bug_table,\"a\"\n"          \
+       "2:\t" PPC_LONG "1b\n"                  \
+       "\t.short %2\n"                         \
+       ".org 2b+%3\n"                          \
+       ".previous\n"
+#endif
+
 /*
  * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
  * optimisations. However depending on the complexity of the condition
  * some compiler versions may not produce optimal results.
  */
 
-#define BUG() do {                                                      \
-       __asm__ __volatile__(                                            \
-               "1:     twi 31,0,0\n"                                    \
-               ".section __bug_table,\"a\"\n"                           \
-               "\t"PPC_LONG"   1b,%0,%1,%2\n"                           \
-               ".previous"                                              \
-               : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
+#define BUG() do {                                             \
+       __asm__ __volatile__(                                   \
+               "1:     twi 31,0,0\n"                           \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                   "i" (0), "i"  (sizeof(struct bug_entry)));  \
+       for(;;) ;                                               \
 } while (0)
 
 #define BUG_ON(x) do {                                         \
@@ -51,23 +54,21 @@ struct bug_entry *find_bug(unsigned long bugaddr);
                        BUG();                                  \
        } else {                                                \
                __asm__ __volatile__(                           \
-               "1:     "PPC_TLNEI"     %0,0\n"                 \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%1,%2,%3\n"                  \
-               ".previous"                                     \
-               : : "r" ((long)(x)), "i" (__LINE__),            \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               "1:     "PPC_TLNEI"     %4,0\n"                 \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__), "i" (0),    \
+                 "i" (sizeof(struct bug_entry)),               \
+                 "r" ((long)(x)));                             \
        }                                                       \
 } while (0)
 
 #define __WARN() do {                                          \
        __asm__ __volatile__(                                   \
                "1:     twi 31,0,0\n"                           \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%0,%1,%2\n"                  \
-               ".previous"                                     \
-               : : "i" (__LINE__ + BUG_WARNING_TRAP),          \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (sizeof(struct bug_entry)));              \
 } while (0)
 
 #define WARN_ON(x) ({                                          \
@@ -77,13 +78,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
                        __WARN();                               \
        } else {                                                \
                __asm__ __volatile__(                           \
-               "1:     "PPC_TLNEI"     %0,0\n"                 \
-               ".section __bug_table,\"a\"\n"                  \
-               "\t"PPC_LONG"   1b,%1,%2,%3\n"                  \
-               ".previous"                                     \
-               : : "r" (__ret_warn_on),                        \
-                   "i" (__LINE__ + BUG_WARNING_TRAP),          \
-                   "i" (__FILE__), "i" (__FUNCTION__));        \
+               "1:     "PPC_TLNEI"     %4,0\n"                 \
+               _EMIT_BUG_ENTRY                                 \
+               : : "i" (__FILE__), "i" (__LINE__),             \
+                 "i" (BUGFLAG_WARNING),                        \
+                 "i" (sizeof(struct bug_entry)),               \
+                 "r" (__ret_warn_on));                         \
        }                                                       \
        unlikely(__ret_warn_on);                                \
 })
index 6fe5c9d4ca3b946e2ad5f348070851b6e039d086..7384b8086b75411e2bc001f60184e344e42b31cf 100644 (file)
@@ -126,6 +126,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTR_NODSISRALIGN           ASM_CONST(0x0000000000100000)
 #define CPU_FTR_PPC_LE                 ASM_CONST(0x0000000000200000)
 #define CPU_FTR_REAL_LE                        ASM_CONST(0x0000000000400000)
+#define CPU_FTR_FPU_UNAVAILABLE                ASM_CONST(0x0000000000800000)
 
 /*
  * Add the 64-bit processor unique features in the top half of the word;
@@ -152,6 +153,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTR_PURR                   LONG_ASM_CONST(0x0000400000000000)
 #define CPU_FTR_CELL_TB_BUG            LONG_ASM_CONST(0x0000800000000000)
 #define CPU_FTR_SPURR                  LONG_ASM_CONST(0x0001000000000000)
+#define CPU_FTR_DSCR                   LONG_ASM_CONST(0x0002000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -295,6 +297,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 #define CPU_FTRS_E300  (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
            CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
            CPU_FTR_COMMON)
+#define CPU_FTRS_E300C2        (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+           CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
+           CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
 #define CPU_FTRS_CLASSIC32     (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
            CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
 #define CPU_FTRS_8XX   (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
@@ -330,13 +335,14 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
-           CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE)
+           CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
+           CPU_FTR_DSCR)
 #define CPU_FTRS_POWER6X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
            CPU_FTR_PURR | CPU_FTR_CI_LARGE_PAGE | \
-           CPU_FTR_SPURR | CPU_FTR_REAL_LE)
+           CPU_FTR_SPURR | CPU_FTR_REAL_LE | CPU_FTR_DSCR)
 #define CPU_FTRS_CELL  (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -364,7 +370,8 @@ enum {
            CPU_FTRS_7450_21 | CPU_FTRS_7450_23 | CPU_FTRS_7455_1 |
            CPU_FTRS_7455_20 | CPU_FTRS_7455 | CPU_FTRS_7447_10 |
            CPU_FTRS_7447 | CPU_FTRS_7447A | CPU_FTRS_82XX |
-           CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_CLASSIC32 |
+           CPU_FTRS_G2_LE | CPU_FTRS_E300 | CPU_FTRS_E300C2 |
+           CPU_FTRS_CLASSIC32 |
 #else
            CPU_FTRS_GENERIC_32 |
 #endif
@@ -403,7 +410,8 @@ enum {
            CPU_FTRS_7450_21 & CPU_FTRS_7450_23 & CPU_FTRS_7455_1 &
            CPU_FTRS_7455_20 & CPU_FTRS_7455 & CPU_FTRS_7447_10 &
            CPU_FTRS_7447 & CPU_FTRS_7447A & CPU_FTRS_82XX &
-           CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_CLASSIC32 &
+           CPU_FTRS_G2_LE & CPU_FTRS_E300 & CPU_FTRS_E300C2 &
+           CPU_FTRS_CLASSIC32 &
 #else
            CPU_FTRS_GENERIC_32 &
 #endif
index fd4a5f5e33d16588ef4c92e7bdbde279901d5e5b..d7a1bc1551c603086c97a2ee1c85f9ad53803172 100644 (file)
@@ -20,8 +20,7 @@
 #ifndef _ASM_POWERPC_DCR_NATIVE_H
 #define _ASM_POWERPC_DCR_NATIVE_H
 #ifdef __KERNEL__
-
-#include <asm/reg.h>
+#ifndef __ASSEMBLY__
 
 typedef struct {} dcr_host_t;
 
@@ -32,7 +31,41 @@ typedef struct {} dcr_host_t;
 #define dcr_read(host, dcr_n)          mfdcr(dcr_n)
 #define dcr_write(host, dcr_n, value)  mtdcr(dcr_n, value)
 
+/* Device Control Registers */
+void __mtdcr(int reg, unsigned int val);
+unsigned int __mfdcr(int reg);
+#define mfdcr(rn)                                              \
+       ({unsigned int rval;                                    \
+       if (__builtin_constant_p(rn))                           \
+               asm volatile("mfdcr %0," __stringify(rn)        \
+                             : "=r" (rval));                   \
+       else                                                    \
+               rval = __mfdcr(rn);                             \
+       rval;})
+
+#define mtdcr(rn, v)                                           \
+do {                                                           \
+       if (__builtin_constant_p(rn))                           \
+               asm volatile("mtdcr " __stringify(rn) ",%0"     \
+                             : : "r" (v));                     \
+       else                                                    \
+               __mtdcr(rn, v);                                 \
+} while (0)
+
+/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
+#define mfdcri(base, reg)                      \
+({                                             \
+       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
+       mfdcr(base ## _CFGDATA);                        \
+})
+
+#define mtdcri(base, reg, data)                        \
+do {                                           \
+       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
+       mtdcr(base ## _CFGDATA, data);          \
+} while (0)
 
+#endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DCR_NATIVE_H */
 
index 473f2c7fd89250c3603cd594f3a4754f9741793a..b66c5e6941f01cabfc128a7b0f4082ac71555fae 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef _ASM_POWERPC_DCR_H
 #define _ASM_POWERPC_DCR_H
 #ifdef __KERNEL__
+#ifdef CONFIG_PPC_DCR
 
 #ifdef CONFIG_PPC_DCR_NATIVE
 #include <asm/dcr-native.h>
@@ -38,5 +39,6 @@ extern unsigned int dcr_resource_len(struct device_node *np,
                                     unsigned int index);
 #endif /* CONFIG_PPC_MERGE */
 
+#endif /* CONFIG_PPC_DCR */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DCR_H */
index d604863d72fb08b9b69a757fe20f117edb8e3cae..9e4dd98eb220ca65a409ffe475bc59a762f84f55 100644 (file)
@@ -107,25 +107,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 
 #endif /* CONFIG_PPC64 */
 
-#define mask_irq(irq)                                          \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->disable)  \
-                       desc->chip->disable(irq);               \
-       })
-#define unmask_irq(irq)                                                \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->enable)   \
-                       desc->chip->enable(irq);                \
-       })
-#define ack_irq(irq)                                           \
-       ({                                                      \
-               irq_desc_t *desc = get_irq_desc(irq);           \
-               if (desc->chip && desc->chip->ack)      \
-                       desc->chip->ack(irq);           \
-       })
-
 /*
  * interrupt-retrigger: should we handle this via lost interrupts and IPIs
  * or should we not care like we do now ? --BenH.
index 584fabfb4f08aa9eccfb688727e109da3d021530..e5f14b13ccf0ff2c11ef8392b6697750608ca919 100644 (file)
@@ -46,8 +46,6 @@ struct mod_arch_specific {
        unsigned int num_bugs;
 };
 
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
 /*
  * Select ELF headers.
  * Make empty section for module_frob_arch_sections to expand.
index 7bb7f90098066f81d3ec216141c21294c26ea2ea..cb02c9d1ef938f0c0d8bcdc9169d22236012c543 100644 (file)
@@ -31,12 +31,12 @@ struct pci_controller {
        int last_busno;
 
        void __iomem *io_base_virt;
-       unsigned long io_base_phys;
+       resource_size_t io_base_phys;
 
        /* Some machines have a non 1:1 mapping of
         * the PCI memory space in the CPU bus space
         */
-       unsigned long pci_mem_offset;
+       resource_size_t pci_mem_offset;
        unsigned long pci_io_size;
 
        struct pci_ops *ops;
index 16f13319c7693fbb55cea896bab704885ebd4357..ac656ee6bb193215db3cc9a9c6353726f3963a0e 100644 (file)
@@ -143,8 +143,13 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP  1
 
-#ifdef CONFIG_PPC64
-/* pci_unmap_{single,page} is not a nop, thus... */
+#if defined(CONFIG_PPC64) || defined(CONFIG_NOT_COHERENT_CACHE)
+/*
+ * For 64-bit kernels, pci_unmap_{single,page} is not a nop.
+ * For 32-bit non-coherent kernels, pci_dma_sync_single_for_cpu() and
+ * so on are not nops.
+ * and thus...
+ */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
        dma_addr_t ADDR_NAME;
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
@@ -158,6 +163,20 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
        (((PTR)->LEN_NAME) = (VAL))
 
+#else /* 32-bit && coherent */
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)           (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+
+#endif /* CONFIG_PPC64 || CONFIG_NOT_COHERENT_CACHE */
+
+#ifdef CONFIG_PPC64
+
 /* The PCI address space does not equal the physical memory address
  * space (we have an IOMMU).  The IDE and SCSI device layers use
  * this boolean for bounce buffer decisions.
@@ -172,16 +191,8 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
-/* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
-
 #endif /* CONFIG_PPC64 */
-       
+
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
                        struct pci_bus_region *region,
                        struct resource *res);
index 6faae7b14d5540f0e5cdcd13b3a31c195d7d980b..a3631b15754ca39bfd49984d631635e56b8f8cf2 100644 (file)
 
 /* Special Purpose Registers (SPRNs)*/
 #define SPRN_CTR       0x009   /* Count Register */
+#define SPRN_DSCR      0x11
 #define SPRN_CTRLF     0x088
 #define SPRN_CTRLT     0x098
 #define   CTRL_CT      0xc0000000      /* current thread */
 #define SPRN_TBRU      0x10D   /* Time Base Read Upper Register (user, R/O) */
 #define SPRN_TBWL      0x11C   /* Time Base Lower Register (super, R/W) */
 #define SPRN_TBWU      0x11D   /* Time Base Upper Register (super, R/W) */
+#define SPRN_SPURR     0x134   /* Scaled PURR */
 #define SPRN_HIOR      0x137   /* 970 Hypervisor interrupt offset */
 #define SPRN_DBAT0L    0x219   /* Data BAT 0 Lower Register */
 #define SPRN_DBAT0U    0x218   /* Data BAT 0 Upper Register */
index 5a0c136c04168f94e8d235a6308702c4cf712c5e..8eaa7b28d9d07d59ad6d2f0a6cb83187380ec8b3 100644 (file)
@@ -159,6 +159,7 @@ extern struct rtas_t rtas;
 
 extern void enter_rtas(unsigned long);
 extern int rtas_token(const char *service);
+extern int rtas_service_present(const char *service);
 extern int rtas_call(int token, int, int, int *, ...);
 extern void rtas_restart(char *cmd);
 extern void rtas_power_off(void);
@@ -221,8 +222,6 @@ extern int rtas_get_error_log_max(void);
 extern spinlock_t rtas_data_buf_lock;
 extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
 
-extern void rtas_stop_self(void);
-
 /* RMO buffer reserved for user-space RTAS use */
 extern unsigned long rtas_rmo_buf;
 
index 6c955d0c1ef0d217199f30ea358dd1f03cf45e31..4d35b844bc58e8fd7e110bc3e620b65e691bf631 100644 (file)
@@ -20,8 +20,8 @@ extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
 extern struct pci_controller* pcibios_alloc_controller(void);
 
 /* Helper function for setting up resources */
-extern void pci_init_resource(struct resource *res, unsigned long start,
-                             unsigned long end, int flags, char *name);
+extern void pci_init_resource(struct resource *res, resource_size_t start,
+                             resource_size_t end, int flags, char *name);
 
 /* Get the PCI host controller for a bus */
 extern struct pci_controller* pci_bus_to_hose(int bus);
@@ -50,12 +50,12 @@ struct pci_controller {
        int bus_offset;
 
        void __iomem *io_base_virt;
-       unsigned long io_base_phys;
+       resource_size_t io_base_phys;
 
        /* Some machines (PReP) have a non 1:1 mapping of
         * the PCI memory space in the CPU bus space
         */
-       unsigned long pci_mem_offset;
+       resource_size_t pci_mem_offset;
 
        struct pci_ops *ops;
        volatile unsigned int __iomem *cfg_addr;
index 11ffaaa5da165abe9adec4d586eba35864fa71dc..9d162028dab92809d4d6b49bc9fce254ccc3932b 100644 (file)
@@ -61,6 +61,27 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
+#ifdef CONFIG_NOT_COHERENT_CACHE
+/*
+ * pci_unmap_{page,single} are NOPs but pci_dma_sync_single_for_cpu()
+ * and so on are not, so...
+ */
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      \
+       dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                \
+       __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)                 \
+       ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)                \
+       (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)                   \
+       ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)          \
+       (((PTR)->LEN_NAME) = (VAL))
+
+#else /* coherent */
+
 /* pci_unmap_{page,single} is a nop so... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
@@ -69,6 +90,8 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
 #define pci_unmap_len(PTR, LEN_NAME)           (0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
 
+#endif /* CONFIG_NOT_COHERENT_CACHE */
+
 #ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
                                        enum pci_dma_burst_strategy *strat,
index 602fbadeaf480cff1769496e9e37e3796356e7fa..a263fc1e65c41c6990cfc3f0a3ff93629c557778 100644 (file)
@@ -9,41 +9,9 @@
 #ifndef __ASM_PPC_REG_BOOKE_H__
 #define __ASM_PPC_REG_BOOKE_H__
 
-#ifndef __ASSEMBLY__
-/* Device Control Registers */
-void __mtdcr(int reg, unsigned int val);
-unsigned int __mfdcr(int reg);
-#define mfdcr(rn)                                              \
-       ({unsigned int rval;                                    \
-       if (__builtin_constant_p(rn))                           \
-               asm volatile("mfdcr %0," __stringify(rn)        \
-                             : "=r" (rval));                   \
-       else                                                    \
-               rval = __mfdcr(rn);                             \
-       rval;})
-
-#define mtdcr(rn, v)                                           \
-do {                                                           \
-       if (__builtin_constant_p(rn))                           \
-               asm volatile("mtdcr " __stringify(rn) ",%0"     \
-                             : : "r" (v));                     \
-       else                                                    \
-               __mtdcr(rn, v);                                 \
-} while (0)
-
-/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
-#define mfdcri(base, reg)                      \
-({                                             \
-       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
-       mfdcr(base ## _CFGDATA);                        \
-})
-
-#define mtdcri(base, reg, data)                        \
-do {                                           \
-       mtdcr(base ## _CFGADDR, base ## _ ## reg);      \
-       mtdcr(base ## _CFGDATA, data);          \
-} while (0)
+#include <asm/dcr.h>
 
+#ifndef __ASSEMBLY__
 /* Performance Monitor Registers */
 #define mfpmr(rn)      ({unsigned int rval; \
                        asm volatile("mfpmr %0," __stringify(rn) \
index 3da29e2d524a57a8bc5fe80cc9942da561c1f32b..abb64c437f6fd92b447deb18768549d7cbb45ddc 100644 (file)
@@ -19,6 +19,7 @@
 #define _FSL_DEVICE_H_
 
 #include <linux/types.h>
+#include <linux/phy.h>
 
 /*
  * Some conventions on how we handle peripherals on Freescale chips