summaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel')
-rw-r--r--arch/ppc64/kernel/head.S16
-rw-r--r--arch/ppc64/kernel/iSeries_vio.c21
-rw-r--r--arch/ppc64/kernel/lparcfg.c1
-rw-r--r--arch/ppc64/kernel/of_device.c2
-rw-r--r--arch/ppc64/kernel/pSeries_lpar.c4
-rw-r--r--arch/ppc64/kernel/pSeries_vio.c19
-rw-r--r--arch/ppc64/kernel/pacaData.c1
-rw-r--r--arch/ppc64/kernel/prom_init.c5
-rw-r--r--arch/ppc64/kernel/rtasd.c10
-rw-r--r--arch/ppc64/kernel/rtc.c7
-rw-r--r--arch/ppc64/kernel/scanlog.c17
-rw-r--r--arch/ppc64/kernel/vio.c73
12 files changed, 93 insertions, 83 deletions
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index cccec490264..03695977562 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -1269,7 +1269,21 @@ initial_stab:
.= 0x7000
.globl fwnmi_data_area
fwnmi_data_area:
- .space PAGE_SIZE
+
+ /* iSeries does not use the FWNMI stuff, so it is safe to put
+ * this here, even if we later allow kernels that will boot on
+ * both pSeries and iSeries */
+#ifdef CONFIG_PPC_ISERIES
+ . = LPARMAP_PHYS
+#include "lparmap.s"
+/*
+ * This ".text" is here for old compilers that generate a trailing
+ * .note section when compiling .c files to .s
+ */
+ .text
+#endif /* CONFIG_PPC_ISERIES */
+
+ . = 0x8000
/*
* On pSeries, secondary processors spin in the following code.
diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c
index b4268cc4ba4..6b754b0c834 100644
--- a/arch/ppc64/kernel/iSeries_vio.c
+++ b/arch/ppc64/kernel/iSeries_vio.c
@@ -68,7 +68,7 @@ static void __init iommu_vio_init(void)
}
/**
- * vio_register_device: - Register a new vio device.
+ * vio_register_device_iseries: - Register a new iSeries vio device.
* @voidev: The device to register.
*/
static struct vio_dev *__init vio_register_device_iseries(char *type,
@@ -76,7 +76,7 @@ static struct vio_dev *__init vio_register_device_iseries(char *type,
{
struct vio_dev *viodev;
- /* allocate a vio_dev for this node */
+ /* allocate a vio_dev for this device */
viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
if (!viodev)
return NULL;
@@ -84,8 +84,15 @@ static struct vio_dev *__init vio_register_device_iseries(char *type,
snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
- return vio_register_device_common(viodev, viodev->dev.bus_id, type,
- unit_num, &vio_iommu_table);
+ viodev->name = viodev->dev.bus_id;
+ viodev->type = type;
+ viodev->unit_address = unit_num;
+ viodev->iommu_table = &vio_iommu_table;
+ if (vio_register_device(viodev) == NULL) {
+ kfree(viodev);
+ return NULL;
+ }
+ return viodev;
}
void __init probe_bus_iseries(void)
@@ -124,6 +131,10 @@ static int vio_match_device_iseries(const struct vio_device_id *id,
return strncmp(dev->type, id->type, strlen(id->type)) == 0;
}
+static struct vio_bus_ops vio_bus_ops_iseries = {
+ .match = vio_match_device_iseries,
+};
+
/**
* vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
*/
@@ -131,7 +142,7 @@ static int __init vio_bus_init_iseries(void)
{
int err;
- err = vio_bus_init(vio_match_device_iseries, NULL, NULL);
+ err = vio_bus_init(&vio_bus_ops_iseries);
if (err == 0) {
iommu_vio_init();
vio_bus_device.iommu_table = &vio_iommu_table;
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c
index 9d034ff062b..edad361a8db 100644
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/ppc64/kernel/lparcfg.c
@@ -273,6 +273,7 @@ static void parse_system_parameter_string(struct seq_file *m)
if (!workbuffer) {
printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
__FILE__, __FUNCTION__, __LINE__);
+ kfree(local_buffer);
return;
}
#ifdef LPARCFG_DEBUG
diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c
index b80e81984ba..da580812ddf 100644
--- a/arch/ppc64/kernel/of_device.c
+++ b/arch/ppc64/kernel/of_device.c
@@ -236,7 +236,6 @@ void of_device_unregister(struct of_device *ofdev)
struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id)
{
struct of_device *dev;
- u32 *reg;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -250,7 +249,6 @@ struct of_device* of_platform_device_create(struct device_node *np, const char *
dev->dev.bus = &of_platform_bus_type;
dev->dev.release = of_release_dev;
- reg = (u32 *)get_property(np, "reg", NULL);
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
if (of_device_register(dev) != 0) {
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
index 0a3ddc9227c..a1d5fdfea4a 100644
--- a/arch/ppc64/kernel/pSeries_lpar.c
+++ b/arch/ppc64/kernel/pSeries_lpar.c
@@ -266,6 +266,10 @@ void vpa_init(int cpu)
/* Register the Virtual Processor Area (VPA) */
flags = 1UL << (63 - 18);
+
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ paca[cpu].lppaca.vmxregs_in_use = 1;
+
ret = register_vpa(flags, hwcpu, __pa(vpa));
if (ret)
diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c
index 338f9e1bdc0..e0ae06f58f8 100644
--- a/arch/ppc64/kernel/pSeries_vio.c
+++ b/arch/ppc64/kernel/pSeries_vio.c
@@ -19,6 +19,7 @@
#include <linux/kobject.h>
#include <asm/iommu.h>
#include <asm/dma.h>
+#include <asm/prom.h>
#include <asm/vio.h>
#include <asm/hvcall.h>
@@ -75,6 +76,12 @@ static void vio_unregister_device_pseries(struct vio_dev *viodev)
device_remove_file(&viodev->dev, &dev_attr_devspec);
}
+static struct vio_bus_ops vio_bus_ops_pseries = {
+ .match = vio_match_device_pseries,
+ .unregister_device = vio_unregister_device_pseries,
+ .release_device = vio_release_device_pseries,
+};
+
/**
* vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
*/
@@ -82,9 +89,7 @@ static int __init vio_bus_init_pseries(void)
{
int err;
- err = vio_bus_init(vio_match_device_pseries,
- vio_unregister_device_pseries,
- vio_release_device_pseries);
+ err = vio_bus_init(&vio_bus_ops_pseries);
if (err == 0)
probe_bus_pseries();
return err;
@@ -181,11 +186,13 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
}
snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
+ viodev->name = of_node->name;
+ viodev->type = of_node->type;
+ viodev->unit_address = *unit_address;
+ viodev->iommu_table = vio_build_iommu_table(viodev);
/* register with generic device framework */
- if (vio_register_device_common(viodev, of_node->name, of_node->type,
- *unit_address, vio_build_iommu_table(viodev))
- == NULL) {
+ if (vio_register_device(viodev) == NULL) {
/* XXX free TCE table */
kfree(viodev);
return NULL;
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
index 6182a2cd90a..33a2d8db3f2 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -59,6 +59,7 @@ extern unsigned long __toc_start;
.fpregs_in_use = 1, \
.end_of_quantum = 0xfffffffffffffffful, \
.slb_count = 64, \
+ .vmxregs_in_use = 0, \
}, \
#ifdef CONFIG_PPC_ISERIES
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index adcf972711f..122283a1d39 100644
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -892,7 +892,10 @@ static void __init prom_init_mem(void)
if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
RELOC(alloc_top) = RELOC(rmo_top);
else
- RELOC(alloc_top) = RELOC(rmo_top) = min(0x40000000ul, RELOC(ram_top));
+ /* Some RS64 machines have buggy firmware where claims up at 1GB
+ * fails. Cap at 768MB as a workaround. Still plenty of room.
+ */
+ RELOC(alloc_top) = RELOC(rmo_top) = min(0x30000000ul, RELOC(ram_top));
prom_printf("memory layout at init:\n");
prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
index b0c3b829fe4..e26b0420b6d 100644
--- a/arch/ppc64/kernel/rtasd.c
+++ b/arch/ppc64/kernel/rtasd.c
@@ -19,6 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -412,8 +413,7 @@ static void do_event_scan_all_cpus(long delay)
/* Drop hotplug lock, and sleep for the specified delay */
unlock_cpu_hotplug();
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(delay);
+ msleep_interruptible(delay);
lock_cpu_hotplug();
cpu = next_cpu(cpu, cpu_online_map);
@@ -442,7 +442,7 @@ static int rtasd(void *unused)
printk(KERN_INFO "RTAS daemon started\n");
- DEBUG("will sleep for %d jiffies\n", (HZ*60/rtas_event_scan_rate) / 2);
+ DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate));
/* See if we have any error stored in NVRAM */
memset(logdata, 0, rtas_error_log_max);
@@ -459,7 +459,7 @@ static int rtasd(void *unused)
}
/* First pass. */
- do_event_scan_all_cpus(HZ);
+ do_event_scan_all_cpus(1000);
if (surveillance_timeout != -1) {
DEBUG("enabling surveillance\n");
@@ -471,7 +471,7 @@ static int rtasd(void *unused)
* machines have problems if we call event-scan too
* quickly. */
for (;;)
- do_event_scan_all_cpus((HZ*60/rtas_event_scan_rate) / 2);
+ do_event_scan_all_cpus(30000/rtas_event_scan_rate);
error:
/* Should delete proc entries */
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c
index d729fefa0df..6ff52bc6132 100644
--- a/arch/ppc64/kernel/rtc.c
+++ b/arch/ppc64/kernel/rtc.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -351,8 +352,7 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)
return; /* delay not allowed */
}
wait_time = rtas_extended_busy_delay_time(error);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
error = RTAS_CLOCK_BUSY;
}
} while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
@@ -386,8 +386,7 @@ int rtas_set_rtc_time(struct rtc_time *tm)
if (in_interrupt())
return 1; /* probably decrementer */
wait_time = rtas_extended_busy_delay_time(error);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
error = RTAS_CLOCK_BUSY;
}
} while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c
index 4d70736619c..215bf890030 100644
--- a/arch/ppc64/kernel/scanlog.c
+++ b/arch/ppc64/kernel/scanlog.c
@@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#include <asm/prom.h>
@@ -77,7 +78,7 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
return -EFAULT;
for (;;) {
- wait_time = HZ/2; /* default wait if no data */
+ wait_time = 500; /* default wait if no data */
spin_lock(&rtas_data_buf_lock);
memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
@@ -107,24 +108,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf,
break;
default:
if (status > 9900 && status <= 9905) {
- /* No data. RTAS is hinting at a delay required
- * between 1-100000 milliseconds
- */
- int ms = 1;
- for (; status > 9900; status--)
- ms = ms * 10;
- /* Use microseconds for reasonable accuracy */
- ms *= 1000;
- wait_time = ms / (1000000/HZ); /* round down is fine */
- /* Fall through to sleep */
+ wait_time = rtas_extended_busy_delay_time(status);
} else {
printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status);
return -EIO;
}
}
/* Apparently no data yet. Wait and try again. */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(wait_time);
+ msleep_interruptible(wait_time);
}
/*NOTREACHED*/
}
diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c
index 3b790bafcaa..c90e1dd875c 100644
--- a/arch/ppc64/kernel/vio.c
+++ b/arch/ppc64/kernel/vio.c
@@ -32,14 +32,13 @@ struct vio_dev vio_bus_device = { /* fake "parent" device */
.dev.bus = &vio_bus_type,
};
-static int (*is_match)(const struct vio_device_id *id,
- const struct vio_dev *dev);
-static void (*unregister_device_callback)(struct vio_dev *dev);
-static void (*release_device_callback)(struct device *dev);
+static struct vio_bus_ops vio_bus_ops;
-/* convert from struct device to struct vio_dev and pass to driver.
+/*
+ * Convert from struct device to struct vio_dev and pass to driver.
* dev->driver has already been set by generic code because vio_bus_match
- * succeeded. */
+ * succeeded.
+ */
static int vio_bus_probe(struct device *dev)
{
struct vio_dev *viodev = to_vio_dev(dev);
@@ -51,9 +50,8 @@ static int vio_bus_probe(struct device *dev)
return error;
id = vio_match_device(viodrv->id_table, viodev);
- if (id) {
+ if (id)
error = viodrv->probe(viodev, id);
- }
return error;
}
@@ -64,9 +62,8 @@ static int vio_bus_remove(struct device *dev)
struct vio_dev *viodev = to_vio_dev(dev);
struct vio_driver *viodrv = to_vio_driver(dev->driver);
- if (viodrv->remove) {
+ if (viodrv->remove)
return viodrv->remove(viodev);
- }
/* driver can't remove */
return 1;
@@ -102,19 +99,20 @@ void vio_unregister_driver(struct vio_driver *viodrv)
EXPORT_SYMBOL(vio_unregister_driver);
/**
- * vio_match_device: - Tell if a VIO device has a matching VIO device id structure.
- * @ids: array of VIO device id structures to search in
- * @dev: the VIO device structure to match against
+ * vio_match_device: - Tell if a VIO device has a matching
+ * VIO device id structure.
+ * @ids: array of VIO device id structures to search in
+ * @dev: the VIO device structure to match against
*
* Used by a driver to check whether a VIO device present in the
* system is in its list of supported devices. Returns the matching
* vio_device_id structure or NULL if there is no match.
*/
-static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
- const struct vio_dev *dev)
+static const struct vio_device_id *vio_match_device(
+ const struct vio_device_id *ids, const struct vio_dev *dev)
{
- while (ids->type) {
- if (is_match(ids, dev))
+ while (ids->type[0] != '\0') {
+ if (vio_bus_ops.match(ids, dev))
return ids;
ids++;
}
@@ -124,16 +122,11 @@ static const struct vio_device_id * vio_match_device(const struct vio_device_id
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
-int __init vio_bus_init(int (*match_func)(const struct vio_device_id *id,
- const struct vio_dev *dev),
- void (*unregister_dev)(struct vio_dev *),
- void (*release_dev)(struct device *))
+int __init vio_bus_init(struct vio_bus_ops *ops)
{
int err;
- is_match = match_func;
- unregister_device_callback = unregister_dev;
- release_device_callback = release_dev;
+ vio_bus_ops = *ops;
err = bus_register(&vio_bus_type);
if (err) {
@@ -141,7 +134,8 @@ int __init vio_bus_init(int (*match_func)(const struct vio_device_id *id,
return err;
}
- /* the fake parent of all vio devices, just to give us
+ /*
+ * The fake parent of all vio devices, just to give us
* a nice directory
*/
err = device_register(&vio_bus_device.dev);
@@ -157,25 +151,20 @@ int __init vio_bus_init(int (*match_func)(const struct vio_device_id *id,
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
- if (release_device_callback)
- release_device_callback(dev);
+ if (vio_bus_ops.release_device)
+ vio_bus_ops.release_device(dev);
kfree(to_vio_dev(dev));
}
-static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t viodev_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", to_vio_dev(dev)->name);
}
DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL);
-struct vio_dev * __devinit vio_register_device_common(
- struct vio_dev *viodev, char *name, char *type,
- uint32_t unit_address, struct iommu_table *iommu_table)
+struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev)
{
- viodev->name = name;
- viodev->type = type;
- viodev->unit_address = unit_address;
- viodev->iommu_table = iommu_table;
/* init generic 'struct device' fields: */
viodev->dev.parent = &vio_bus_device.dev;
viodev->dev.bus = &vio_bus_type;
@@ -194,8 +183,8 @@ struct vio_dev * __devinit vio_register_device_common(
void __devinit vio_unregister_device(struct vio_dev *viodev)
{
- if (unregister_device_callback)
- unregister_device_callback(viodev);
+ if (vio_bus_ops.unregister_device)
+ vio_bus_ops.unregister_device(viodev);
device_remove_file(&viodev->dev, &dev_attr_name);
device_unregister(&viodev->dev);
}
@@ -262,16 +251,8 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
const struct vio_dev *vio_dev = to_vio_dev(dev);
struct vio_driver *vio_drv = to_vio_driver(drv);
const struct vio_device_id *ids = vio_drv->id_table;
- const struct vio_device_id *found_id;
-
- if (!ids)
- return 0;
- found_id = vio_match_device(ids, vio_dev);
- if (found_id)
- return 1;
-
- return 0;
+ return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
}
struct bus_type vio_bus_type = {