summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/Makefile4
-rw-r--r--arch/powerpc/kernel/asm-offsets.c1
-rw-r--r--arch/powerpc/kernel/cputable.c12
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/head_64.S2
-rw-r--r--arch/powerpc/kernel/ibmebus.c283
-rw-r--r--arch/powerpc/kernel/iommu.c10
-rw-r--r--arch/powerpc/kernel/misc_32.S4
-rw-r--r--arch/powerpc/kernel/pci_64.c14
-rw-r--r--arch/powerpc/kernel/process.c50
-rw-r--r--arch/powerpc/kernel/prom.c26
-rw-r--r--arch/powerpc/kernel/rtas_pci.c4
-rw-r--r--arch/powerpc/kernel/setup-common.c22
-rw-r--r--arch/powerpc/kernel/setup_32.c3
-rw-r--r--arch/powerpc/kernel/traps.c76
15 files changed, 342 insertions, 170 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8120d428ebfd..e0fa80eca366 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
-rtaspci-$(CONFIG_PPC64) := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y)
+rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o
+obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y)
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 030d300cd71c..9735e828b52d 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -77,7 +77,6 @@ int main(void)
DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
#else /* CONFIG_PPC64 */
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
- DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
DEFINE(PT_PTRACED, PT_PTRACED);
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index e4006dc087ca..6b59e40214d2 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -558,6 +558,18 @@ static struct cpu_spec cpu_specs[] = {
.cpu_setup = __setup_cpu_750cx,
.platform = "ppc750",
},
+ { /* 750CL */
+ .pvr_mask = 0xfffff0f0,
+ .pvr_value = 0x00087010,
+ .cpu_name = "750CL",
+ .cpu_features = CPU_FTRS_750,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750cx,
+ .platform = "ppc750",
+ },
{ /* 745/755 */
.pvr_mask = 0xfffff000,
.pvr_value = 0x00083000,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c03e829fee3c..c29d1652a421 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -191,7 +191,6 @@ stack_ovf:
0:
_GLOBAL(DoSyscall)
- stw r0,THREAD+LAST_SYSCALL(r2)
stw r3,ORIG_GPR3(r1)
li r12,0
stw r12,RESULT(r1)
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 97cedcd6c9b4..5a53cebd17e6 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -1555,7 +1555,6 @@ _GLOBAL(generic_secondary_smp_init)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
@@ -1851,7 +1850,6 @@ __secondary_start_pmac_0:
_GLOBAL(pmac_secondary_start)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_ppc970
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 82bd2f10770f..8ed1163c0bd4 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -2,36 +2,37 @@
* IBM PowerPC IBM eBus Infrastructure Support.
*
* Copyright (c) 2005 IBM Corporation
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
- *
+ *
* All rights reserved.
*
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB
- * BSD.
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
*
* OpenIB BSD License
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
*
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
* and/or other materials
- * provided with the distribution.
+ * provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
@@ -43,19 +44,21 @@
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
-static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
- .name = ibmebus_bus_device.ofdev.dev.bus_id,
- .ofdev.dev.bus_id = "ibmebus",
- .ofdev.dev.bus = &ibmebus_bus_type,
+#define MAX_LOC_CODE_LENGTH 80
+
+static struct device ibmebus_bus_device = { /* fake "parent" device */
+ .bus_id = "ibmebus",
};
+struct bus_type ibmebus_bus_type;
+
static void *ibmebus_alloc_coherent(struct device *dev,
size_t size,
dma_addr_t *dma_handle,
gfp_t flag)
{
void *mem;
-
+
mem = kmalloc(size, flag);
*dma_handle = (dma_addr_t)mem;
@@ -63,7 +66,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
}
static void ibmebus_free_coherent(struct device *dev,
- size_t size, void *vaddr,
+ size_t size, void *vaddr,
dma_addr_t dma_handle)
{
kfree(vaddr);
@@ -79,7 +82,7 @@ static dma_addr_t ibmebus_map_single(struct device *dev,
static void ibmebus_unmap_single(struct device *dev,
dma_addr_t dma_addr,
- size_t size,
+ size_t size,
enum dma_data_direction direction)
{
return;
@@ -90,13 +93,13 @@ static int ibmebus_map_sg(struct device *dev,
int nents, enum dma_data_direction direction)
{
int i;
-
+
for (i = 0; i < nents; i++) {
- sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].offset;
sg[i].dma_length = sg[i].length;
}
-
+
return nents;
}
@@ -128,15 +131,15 @@ static int ibmebus_bus_probe(struct device *dev)
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
const struct of_device_id *id;
int error = -ENODEV;
-
+
if (!ibmebusdrv->probe)
return error;
-
+
id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
if (id) {
error = ibmebusdrv->probe(ibmebusdev, id);
}
-
+
return error;
}
@@ -144,11 +147,11 @@ static int ibmebus_bus_remove(struct device *dev)
{
struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev);
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
-
+
if (ibmebusdrv->remove) {
return ibmebusdrv->remove(ibmebusdev);
}
-
+
return 0;
}
@@ -158,21 +161,12 @@ static void __devinit ibmebus_dev_release(struct device *dev)
kfree(to_ibmebus_dev(dev));
}
-static ssize_t ibmebusdev_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
-}
-static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
- NULL);
-
-static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+static int __devinit ibmebus_register_device_common(
struct ibmebus_dev *dev, const char *name)
{
int err = 0;
- dev->name = name;
- dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev;
+ dev->ofdev.dev.parent = &ibmebus_bus_device;
dev->ofdev.dev.bus = &ibmebus_bus_type;
dev->ofdev.dev.release = ibmebus_dev_release;
@@ -181,17 +175,15 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node);
/* An ibmebusdev is based on a of_device. We have to change the
- * bus type to use our own DMA mapping operations.
- */
+ * bus type to use our own DMA mapping operations.
+ */
if ((err = of_device_register(&dev->ofdev)) != 0) {
printk(KERN_ERR "%s: failed to register device (%d).\n",
__FUNCTION__, err);
- return NULL;
+ return -ENODEV;
}
-
- device_create_file(&dev->ofdev.dev, &dev_attr_name);
-
- return dev;
+
+ return 0;
}
static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -205,31 +197,31 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
if (!loc_code) {
printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
__FUNCTION__, dn->name ? dn->name : "<unknown>");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
-
+
if (strlen(loc_code) == 0) {
printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
__FUNCTION__);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
if (!dev) {
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
dev->ofdev.node = of_node_get(dn);
-
+
length = strlen(loc_code);
- memcpy(dev->ofdev.dev.bus_id, loc_code
- + (length - min(length, BUS_ID_SIZE - 1)),
+ memcpy(dev->ofdev.dev.bus_id, loc_code
+ + (length - min(length, BUS_ID_SIZE - 1)),
min(length, BUS_ID_SIZE - 1));
/* Register with generic device framework. */
- if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+ if (ibmebus_register_device_common(dev, dn->name) != 0) {
kfree(dev);
- return NULL;
+ return ERR_PTR(-ENODEV);
}
return dev;
@@ -238,17 +230,16 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
static void ibmebus_probe_of_nodes(char* name)
{
struct device_node *dn = NULL;
-
+
while ((dn = of_find_node_by_name(dn, name))) {
- if (ibmebus_register_device_node(dn) == NULL) {
+ if (IS_ERR(ibmebus_register_device_node(dn))) {
of_node_put(dn);
-
return;
}
}
-
+
of_node_put(dn);
-
+
return;
}
@@ -262,17 +253,22 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt)
return;
}
-static int ibmebus_match_helper(struct device *dev, void *data)
+static int ibmebus_match_helper_name(struct device *dev, void *data)
{
- if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ char *name;
+
+ name = (char*)get_property(
+ ebus_dev->ofdev.node, "name", NULL);
+
+ if (name && (strcmp((char*)data, name) == 0))
return 1;
-
+
return 0;
}
static int ibmebus_unregister_device(struct device *dev)
{
- device_remove_file(dev, &dev_attr_name);
of_device_unregister(to_of_device(dev));
return 0;
@@ -281,17 +277,16 @@ static int ibmebus_unregister_device(struct device *dev)
static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
{
struct device *dev;
-
+
while (strlen(idt->name) > 0) {
- while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
+ while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
(void*)idt->name,
- ibmebus_match_helper))) {
+ ibmebus_match_helper_name))) {
ibmebus_unregister_device(dev);
}
idt++;
-
}
-
+
return;
}
@@ -307,30 +302,33 @@ int ibmebus_register_driver(struct ibmebus_driver *drv)
if ((err = driver_register(&drv->driver) != 0))
return err;
+ /* remove all supported devices first, in case someone
+ * probed them manually before registering the driver */
+ ibmebus_remove_devices_by_id(drv->id_table);
ibmebus_add_devices_by_id(drv->id_table);
-
+
return 0;
}
EXPORT_SYMBOL(ibmebus_register_driver);
void ibmebus_unregister_driver(struct ibmebus_driver *drv)
-{
+{
driver_unregister(&drv->driver);
ibmebus_remove_devices_by_id(drv->id_table);
}
EXPORT_SYMBOL(ibmebus_unregister_driver);
int ibmebus_request_irq(struct ibmebus_dev *dev,
- u32 ist,
+ u32 ist,
irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id)
{
unsigned int irq = irq_create_mapping(NULL, ist);
-
+
if (irq == NO_IRQ)
return -EINVAL;
-
+
return request_irq(irq, handler,
irq_flags, devname, dev_id);
}
@@ -339,56 +337,157 @@ EXPORT_SYMBOL(ibmebus_request_irq);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
{
unsigned int irq = irq_find_mapping(NULL, ist);
-
+
free_irq(irq, dev_id);
}
EXPORT_SYMBOL(ibmebus_free_irq);
static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
-{
+{
const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv);
const struct of_device_id *ids = ebus_drv->id_table;
const struct of_device_id *found_id;
-
+
if (!ids)
return 0;
-
+
found_id = of_match_device(ids, &ebus_dev->ofdev);
if (found_id)
return 1;
-
+
return 0;
}
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ char *name = (char*)get_property(ebus_dev->ofdev.node, "name", NULL);
+ return sprintf(buf, "%s\n", name);
+}
+
+static struct device_attribute ibmebus_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_NULL
+};
+
+static int ibmebus_match_helper_loc_code(struct device *dev, void *data)
+{
+ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ char *loc_code;
+
+ loc_code = (char*)get_property(
+ ebus_dev->ofdev.node, "ibm,loc-code", NULL);
+
+ if (loc_code && (strcmp((char*)data, loc_code) == 0))
+ return 1;
+
+ return 0;
+}
+
+static ssize_t ibmebus_store_probe(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device_node *dn = NULL;
+ struct ibmebus_dev *dev;
+ char *loc_code;
+ char parm[MAX_LOC_CODE_LENGTH];
+
+ if (count >= MAX_LOC_CODE_LENGTH)
+ return -EINVAL;
+ memcpy(parm, buf, count);
+ parm[count] = '\0';
+ if (parm[count-1] == '\n')
+ parm[count-1] = '\0';
+
+ if (bus_find_device(&ibmebus_bus_type, NULL, parm,
+ ibmebus_match_helper_loc_code)) {
+ printk(KERN_WARNING "%s: loc_code %s has already been probed\n",
+ __FUNCTION__, parm);
+ return -EINVAL;
+ }
+
+ while ((dn = of_find_all_nodes(dn))) {
+ loc_code = (char *)get_property(dn, "ibm,loc-code", NULL);
+ if (loc_code && (strncmp(loc_code, parm, count) == 0)) {
+ dev = ibmebus_register_device_node(dn);
+ if (IS_ERR(dev)) {
+ of_node_put(dn);
+ return PTR_ERR(dev);
+ } else
+ return count; /* success */
+ }
+ }
+
+ /* if we drop out of the loop, the loc code was invalid */
+ printk(KERN_WARNING "%s: no device with loc_code %s found\n",
+ __FUNCTION__, parm);
+ return -ENODEV;
+}
+
+static ssize_t ibmebus_store_remove(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device *dev;
+ char parm[MAX_LOC_CODE_LENGTH];
+
+ if (count >= MAX_LOC_CODE_LENGTH)
+ return -EINVAL;
+ memcpy(parm, buf, count);
+ parm[count] = '\0';
+ if (parm[count-1] == '\n')
+ parm[count-1] = '\0';
+
+ /* The location code is unique, so we will find one device at most */
+ if ((dev = bus_find_device(&ibmebus_bus_type, NULL, parm,
+ ibmebus_match_helper_loc_code))) {
+ ibmebus_unregister_device(dev);
+ } else {
+ printk(KERN_WARNING "%s: loc_code %s not on the bus\n",
+ __FUNCTION__, parm);
+ return -ENODEV;
+ }
+
+ return count;
+}
+
+static struct bus_attribute ibmebus_bus_attrs[] = {
+ __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
+ __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
+ __ATTR_NULL
+};
+
struct bus_type ibmebus_bus_type = {
- .name = "ibmebus",
- .match = ibmebus_bus_match,
+ .name = "ibmebus",
+ .match = ibmebus_bus_match,
+ .dev_attrs = ibmebus_dev_attrs,
+ .bus_attrs = ibmebus_bus_attrs
};
EXPORT_SYMBOL(ibmebus_bus_type);
static int __init ibmebus_bus_init(void)
{
int err;
-
+
printk(KERN_INFO "IBM eBus Device Driver\n");
-
+
err = bus_register(&ibmebus_bus_type);
if (err) {
printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
__FUNCTION__);
return err;
}
-
- err = device_register(&ibmebus_bus_device.ofdev.dev);
+
+ err = device_register(&ibmebus_bus_device);
if (err) {
- printk(KERN_WARNING "%s: device_register returned %i\n",
+ printk(KERN_WARNING "%s: device_register returned %i\n",
__FUNCTION__, err);
bus_unregister(&ibmebus_bus_type);
return err;
}
-
+
return 0;
}
__initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 95edad4faf26..c50d7072f305 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -76,6 +76,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
unsigned int align_order)
{
unsigned long n, end, i, start;
+ unsigned long start_addr, end_addr;
unsigned long limit;
int largealloc = npages > 15;
int pass = 0;
@@ -146,6 +147,15 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
}
}
+ /* DMA cannot cross 4 GB boundary */
+ start_addr = (n + tbl->it_offset) << PAGE_SHIFT;
+ end_addr = (end + tbl->it_offset) << PAGE_SHIFT;
+ if ((start_addr >> 32) != (end_addr >> 32)) {
+ end_addr &= 0xffffffff00000000l;
+ start = (end_addr >> PAGE_SHIFT) - tbl->it_offset;
+ goto again;
+ }
+
for (i = n; i < end; i++)
if (test_bit(i, tbl->it_map)) {
start = i+1;
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 412bea3cf813..98decf8ebff4 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -734,10 +734,6 @@ _GLOBAL(abs)
sub r3,r3,r4
blr
-_GLOBAL(_get_SP)
- mr r3,r1 /* Close enough */
- blr
-
/*
* Create a kernel thread
* kernel_thread(fn, arg, flags)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 7e97d71a5f8f..db1d40ef7d60 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -61,8 +61,7 @@ void iSeries_pcibios_init(void);
LIST_HEAD(hose_list);
-struct dma_mapping_ops *pci_dma_ops;
-EXPORT_SYMBOL(pci_dma_ops);
+static struct dma_mapping_ops *pci_dma_ops;
int global_phb_number; /* Global phb counter */
@@ -70,6 +69,17 @@ int global_phb_number; /* Global phb counter */
struct pci_dev *ppc64_isabridge_dev = NULL;
EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+ pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+ return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
static void fixup_broken_pcnet32(struct pci_dev* dev)
{
if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e53b2988d1bf..949092dccf44 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -402,11 +402,11 @@ static void printbits(unsigned long val, struct regbit *bits)
}
#ifdef CONFIG_PPC64
-#define REG "%016lX"
+#define REG "%016lx"
#define REGS_PER_LINE 4
#define LAST_VOLATILE 13
#else
-#define REG "%08lX"
+#define REG "%08lx"
#define REGS_PER_LINE 8
#define LAST_VOLATILE 12
#endif
@@ -421,7 +421,7 @@ void show_regs(struct pt_regs * regs)
regs, regs->trap, print_tainted(), init_utsname()->release);
printk("MSR: "REG" ", regs->msr);
printbits(regs->msr, msr_bits);
- printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer);
+ printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer);
trap = TRAP(regs);
if (trap == 0x300 || trap == 0x600)
printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -572,7 +572,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
kregs->nip = *((unsigned long *)ret_from_fork);
#else
kregs->nip = (unsigned long)ret_from_fork;
- p->thread.last_syscall = -1;
#endif
return 0;
@@ -823,6 +822,35 @@ out:
return error;
}
+#ifdef CONFIG_IRQSTACKS
+static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
+ unsigned long nbytes)
+{
+ unsigned long stack_page;
+ unsigned long cpu = task_cpu(p);
+
+ /*
+ * Avoid crashing if the stack has overflowed and corrupted
+ * task_cpu(p), which is in the thread_info struct.
+ */
+ if (cpu < NR_CPUS && cpu_possible(cpu)) {
+ stack_page = (unsigned long) hardirq_ctx[cpu];
+ if (sp >= stack_page + sizeof(struct thread_struct)
+ && sp <= stack_page + THREAD_SIZE - nbytes)
+ return 1;
+
+ stack_page = (unsigned long) softirq_ctx[cpu];
+ if (sp >= stack_page + sizeof(struct thread_struct)
+ && sp <= stack_page + THREAD_SIZE - nbytes)
+ return 1;
+ }
+ return 0;
+}
+
+#else
+#define valid_irq_stack(sp, p, nb) 0
+#endif /* CONFIG_IRQSTACKS */
+
int validate_sp(unsigned long sp, struct task_struct *p,
unsigned long nbytes)
{
@@ -832,19 +860,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
&& sp <= stack_page + THREAD_SIZE - nbytes)
return 1;
-#ifdef CONFIG_IRQSTACKS
- stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
- if (sp >= stack_page + sizeof(struct thread_struct)
- && sp <= stack_page + THREAD_SIZE - nbytes)
- return 1;
-
- stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
- if (sp >= stack_page + sizeof(struct thread_struct)
- && sp <= stack_page + THREAD_SIZE - nbytes)
- return 1;
-#endif
-
- return 0;
+ return valid_irq_stack(sp, p, nbytes);
}
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 8d52b23348bd..ef6bfb70b24a 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -719,6 +719,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long *lprop;
+ u32 *prop;
unsigned long l;
char *p;
@@ -760,6 +761,22 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ DBG("Looking for initrd properties... ");
+ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+ if (prop) {
+ initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+ prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+ if (prop) {
+ initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
+ initrd_below_start_ok = 1;
+ } else {
+ initrd_start = 0;
+ }
+ }
+ DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
/* Retreive command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
@@ -926,6 +943,12 @@ static void __init early_reserve_mem(void)
self_size = initial_boot_params->totalsize;
lmb_reserve(self_base, self_size);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* then reserve the initrd, if any */
+ if (initrd_start && (initrd_end > initrd_start))
+ lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
#ifdef CONFIG_PPC32
/*
* Handle the case where we might be booting from an old kexec
@@ -954,9 +977,6 @@ static void __init early_reserve_mem(void)
size = *(reserve_map++);
if (size == 0)
break;
- /* skip if the reservation is for the blob */
- if (base == self_base && size == self_size)
- continue;
DBG("reserving: %llx -> %llx\n", base, size);
lmb_reserve(base, size);
}
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index ace9f4c86e67..1616a44ac608 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_controller *phb)
return 0;
}
-unsigned long __init find_and_init_phbs(void)
+void __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
@@ -319,8 +319,6 @@ unsigned long __init find_and_init_phbs(void)
if (prop)
pci_assign_all_buses = *prop;
}
-
- return 0;
}
/* RPA-specific bits for removing PHBs */
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 89cfaf49d3de..d050d9a61bd4 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -304,26 +304,8 @@ struct seq_operations cpuinfo_op = {
void __init check_for_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
- const unsigned int *prop;
- int len;
-
- DBG(" -> check_for_initrd()\n");
-
- if (of_chosen) {
- prop = get_property(of_chosen, "linux,initrd-start", &len);
- if (prop != NULL) {
- initrd_start = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- prop = get_property(of_chosen,
- "linux,initrd-end", &len);
- if (prop != NULL) {
- initrd_end = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- initrd_below_start_ok = 1;
- } else
- initrd_start = 0;
- }
- }
+ DBG(" -> check_for_initrd() initrd_start=0x%lx initrd_end=0x%lx\n",
+ initrd_start, initrd_end);
/* If we were passed an initrd, set the ROOT_DEV properly if the values
* look sensible. If not, clear initrd reference.
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 44a6a3c47feb..f688548f74cd 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -92,7 +92,8 @@ unsigned long __init early_init(unsigned long dt_ptr)
/* First zero the BSS -- use memset_io, some platforms don't have
* caches on yet */
- memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
+ memset_io((void __iomem *)PTRRELOC(&__bss_start), 0,
+ __bss_stop - __bss_start);
/*
* Identify the CPU type and fix up code sections
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 17724fb2067f..f7862224fe85 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -90,21 +90,11 @@ EXPORT_SYMBOL(unregister_die_notifier);
* Trap & Exception support
*/
-static DEFINE_SPINLOCK(die_lock);
-
-int die(const char *str, struct pt_regs *regs, long err)
-{
- static int die_counter;
-
- if (debugger(regs))
- return 1;
-
- console_verbose();
- spin_lock_irq(&die_lock);
- bust_spinlocks(1);
#ifdef CONFIG_PMAC_BACKLIGHT
+static void pmac_backlight_unblank(void)
+{
mutex_lock(&pmac_backlight_mutex);
- if (machine_is(powermac) && pmac_backlight) {
+ if (pmac_backlight) {
struct backlight_properties *props;
props = &pmac_backlight->props;
@@ -113,26 +103,67 @@ int die(const char *str, struct pt_regs *regs, long err)
backlight_update_status(pmac_backlight);
}
mutex_unlock(&pmac_backlight_mutex);
+}
+#else
+static inline void pmac_backlight_unblank(void) { }
#endif
- printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
+
+int die(const char *str, struct pt_regs *regs, long err)
+{
+ static struct {
+ spinlock_t lock;
+ u32 lock_owner;
+ int lock_owner_depth;
+ } die = {
+ .lock = __SPIN_LOCK_UNLOCKED(die.lock),
+ .lock_owner = -1,
+ .lock_owner_depth = 0
+ };
+ static int die_counter;
+ unsigned long flags;
+
+ if (debugger(regs))
+ return 1;
+
+ oops_enter();
+
+ if (die.lock_owner != raw_smp_processor_id()) {
+ console_verbose();
+ spin_lock_irqsave(&die.lock, flags);
+ die.lock_owner = smp_processor_id();
+ die.lock_owner_depth = 0;
+ bust_spinlocks(1);
+ if (machine_is(powermac))
+ pmac_backlight_unblank();
+ } else {
+ local_save_flags(flags);
+ }
+
+ if (++die.lock_owner_depth < 3) {
+ printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
- printk("PREEMPT ");
+ printk("PREEMPT ");
#endif
#ifdef CONFIG_SMP
- printk("SMP NR_CPUS=%d ", NR_CPUS);
+ printk("SMP NR_CPUS=%d ", NR_CPUS);
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
- printk("DEBUG_PAGEALLOC ");
+ printk("DEBUG_PAGEALLOC ");
#endif
#ifdef CONFIG_NUMA
- printk("NUMA ");
+ printk("NUMA ");
#endif
- printk("%s\n", ppc_md.name ? "" : ppc_md.name);
+ printk("%s\n", ppc_md.name ? ppc_md.name : "");
+
+ print_modules();
+ show_regs(regs);
+ } else {
+ printk("Recursive die() failure, output suppressed\n");
+ }
- print_modules();
- show_regs(regs);
bust_spinlocks(0);
- spin_unlock_irq(&die_lock);
+ die.lock_owner = -1;
+ spin_unlock_irqrestore(&die.lock, flags);
if (kexec_should_crash(current) ||
kexec_sr_activated(smp_processor_id()))
@@ -145,6 +176,7 @@ int die(const char *str, struct pt_regs *regs, long err)
if (panic_on_oops)
panic("Fatal exception");
+ oops_exit();
do_exit(err);
return 0;