summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/common/gic.c1
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/entry-common.S4
-rw-r--r--arch/arm/kernel/sys_arm.c10
-rw-r--r--arch/arm/kernel/time.c10
-rw-r--r--arch/arm/mach-ixp4xx/common.c155
-rw-r--r--arch/arm/mach-ixp4xx/coyote-pci.c7
-rw-r--r--arch/arm/mach-ixp4xx/coyote-setup.c9
-rw-r--r--arch/arm/mach-ixp4xx/gtwx5715-pci.c28
-rw-r--r--arch/arm/mach-ixp4xx/gtwx5715-setup.c8
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-pci.c12
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c13
-rw-r--r--arch/arm/mach-ixp4xx/ixdpg425-pci.c4
-rw-r--r--arch/arm/mach-pxa/time.c58
-rw-r--r--arch/arm/mach-s3c2410/clock.c9
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-clock.c6
-rw-r--r--arch/arm/mach-sa1100/time.c68
-rw-r--r--arch/arm/mm/alignment.c70
-rw-r--r--arch/arm/mm/mm-armv.c30
-rw-r--r--arch/i386/pci/common.c1
-rw-r--r--arch/i386/pci/i386.c49
-rw-r--r--arch/ia64/Kconfig6
-rw-r--r--arch/ia64/hp/sim/boot/fw-emu.c11
-rw-r--r--arch/ia64/ia32/ia32_signal.c1
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/cpufreq/Kconfig29
-rw-r--r--arch/ia64/kernel/cpufreq/Makefile1
-rw-r--r--arch/ia64/kernel/cpufreq/acpi-cpufreq.c499
-rw-r--r--arch/ia64/kernel/sys_ia64.c2
-rw-r--r--arch/ia64/kernel/uncached.c4
-rw-r--r--arch/ia64/lib/Makefile2
-rw-r--r--arch/ia64/lib/swiotlb.c5
-rw-r--r--arch/ia64/mm/hugetlbpage.c8
-rw-r--r--arch/ia64/pci/pci.c1
-rw-r--r--arch/ia64/sn/include/tio.h6
-rw-r--r--arch/ia64/sn/include/xtalk/hubdev.h11
-rw-r--r--arch/ia64/sn/kernel/bte.c83
-rw-r--r--arch/ia64/sn/kernel/huberror.c2
-rw-r--r--arch/ia64/sn/kernel/io_init.c35
-rw-r--r--arch/ia64/sn/kernel/irq.c75
-rw-r--r--arch/ia64/sn/kernel/setup.c7
-rw-r--r--arch/ia64/sn/kernel/sn2/ptc_deadlock.S13
-rw-r--r--arch/ia64/sn/kernel/sn2/sn2_smp.c256
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_hwperf.c313
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_proc_fs.c4
-rw-r--r--arch/ia64/sn/kernel/sn2/timer_interrupt.c22
-rw-r--r--arch/ia64/sn/pci/Makefile2
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_dma.c60
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c40
-rw-r--r--arch/ia64/sn/pci/tioca_provider.c7
-rw-r--r--arch/ia64/sn/pci/tioce_provider.c771
-rw-r--r--arch/m68knommu/Kconfig66
-rw-r--r--arch/m68knommu/Makefile5
-rw-r--r--arch/m68knommu/defconfig452
-rw-r--r--arch/m68knommu/kernel/setup.c25
-rw-r--r--arch/m68knommu/kernel/traps.c20
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S23
-rw-r--r--arch/m68knommu/platform/523x/config.c82
-rw-r--r--arch/m68knommu/platform/5307/head.S15
-rw-r--r--arch/m68knommu/platform/68328/entry.S4
-rw-r--r--arch/m68knommu/platform/68360/entry.S2
-rw-r--r--arch/ppc/Makefile11
-rw-r--r--arch/ppc/boot/utils/addRamDisk.c203
-rw-r--r--arch/ppc/kernel/cpu_setup_6xx.S5
-rw-r--r--arch/ppc/kernel/l2cr.S31
-rw-r--r--arch/ppc/syslib/m8xx_setup.c6
-rw-r--r--arch/ppc64/Kconfig74
-rw-r--r--arch/ppc64/Makefile9
-rw-r--r--arch/ppc64/boot/Makefile4
-rw-r--r--arch/ppc64/boot/addnote.c4
-rw-r--r--arch/ppc64/boot/crt0.S2
-rw-r--r--arch/ppc64/boot/div64.S2
-rw-r--r--arch/ppc64/boot/elf.h149
-rw-r--r--arch/ppc64/boot/main.c55
-rw-r--r--arch/ppc64/boot/page.h34
-rw-r--r--arch/ppc64/boot/ppc32-types.h36
-rw-r--r--arch/ppc64/boot/ppc_asm.h62
-rw-r--r--arch/ppc64/boot/prom.c196
-rw-r--r--arch/ppc64/boot/prom.h18
-rw-r--r--arch/ppc64/boot/stdio.h16
-rw-r--r--arch/ppc64/boot/string.S2
-rw-r--r--arch/ppc64/boot/string.h16
-rw-r--r--arch/ppc64/boot/zlib.c2
-rw-r--r--arch/ppc64/configs/g5_defconfig6
-rw-r--r--arch/ppc64/configs/iSeries_defconfig7
-rw-r--r--arch/ppc64/configs/maple_defconfig6
-rw-r--r--arch/ppc64/configs/pSeries_defconfig6
-rw-r--r--arch/ppc64/defconfig6
-rw-r--r--arch/ppc64/kernel/LparData.c37
-rw-r--r--arch/ppc64/kernel/Makefile7
-rw-r--r--arch/ppc64/kernel/asm-offsets.c3
-rw-r--r--arch/ppc64/kernel/cputable.c40
-rw-r--r--arch/ppc64/kernel/firmware.c47
-rw-r--r--arch/ppc64/kernel/head.S523
-rw-r--r--arch/ppc64/kernel/iSeries_htab.c5
-rw-r--r--arch/ppc64/kernel/iSeries_setup.c30
-rw-r--r--arch/ppc64/kernel/iSeries_vio.c155
-rw-r--r--arch/ppc64/kernel/lmb.c151
-rw-r--r--arch/ppc64/kernel/lparcfg.c7
-rw-r--r--arch/ppc64/kernel/misc.S98
-rw-r--r--arch/ppc64/kernel/of_device.c2
-rw-r--r--arch/ppc64/kernel/pSeries_iommu.c3
-rw-r--r--arch/ppc64/kernel/pSeries_lpar.c4
-rw-r--r--arch/ppc64/kernel/pSeries_setup.c39
-rw-r--r--arch/ppc64/kernel/pSeries_smp.c3
-rw-r--r--arch/ppc64/kernel/pSeries_vio.c273
-rw-r--r--arch/ppc64/kernel/pacaData.c4
-rw-r--r--arch/ppc64/kernel/pmac_setup.c2
-rw-r--r--arch/ppc64/kernel/pmc.c21
-rw-r--r--arch/ppc64/kernel/process.c12
-rw-r--r--arch/ppc64/kernel/prom.c184
-rw-r--r--arch/ppc64/kernel/prom_init.c93
-rw-r--r--arch/ppc64/kernel/rtas_pci.c19
-rw-r--r--arch/ppc64/kernel/setup.c28
-rw-r--r--arch/ppc64/kernel/sysfs.c57
-rw-r--r--arch/ppc64/kernel/time.c7
-rw-r--r--arch/ppc64/kernel/vio.c444
-rw-r--r--arch/ppc64/mm/hash_low.S4
-rw-r--r--arch/ppc64/mm/hash_native.c3
-rw-r--r--arch/ppc64/mm/hash_utils.c4
-rw-r--r--arch/ppc64/mm/hugetlbpage.c388
-rw-r--r--arch/ppc64/mm/imalloc.c2
-rw-r--r--arch/ppc64/mm/init.c96
-rw-r--r--arch/ppc64/mm/numa.c2
-rw-r--r--arch/ppc64/mm/slb_low.S35
-rw-r--r--arch/ppc64/mm/tlb.c95
-rw-r--r--arch/ppc64/oprofile/common.c1
-rw-r--r--arch/ppc64/xmon/start.c2
-rw-r--r--arch/ppc64/xmon/xmon.c28
-rw-r--r--arch/sparc/kernel/setup.c1
-rw-r--r--arch/sparc/kernel/tick14.c1
-rw-r--r--arch/sparc/kernel/time.c1
-rw-r--r--arch/sparc/mm/fault.c1
-rw-r--r--arch/sparc/mm/init.c1
-rw-r--r--arch/sparc64/kernel/entry.S293
-rw-r--r--arch/sparc64/kernel/pci_iommu.c2
-rw-r--r--arch/sparc64/kernel/process.c2
-rw-r--r--arch/sparc64/kernel/sbus.c2
-rw-r--r--arch/sparc64/kernel/setup.c1
-rw-r--r--arch/sparc64/kernel/signal32.c22
-rw-r--r--arch/sparc64/kernel/smp.c30
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c32
-rw-r--r--arch/sparc64/kernel/traps.c269
-rw-r--r--arch/sparc64/kernel/ttable.S27
-rw-r--r--arch/sparc64/kernel/unaligned.c18
-rw-r--r--arch/sparc64/kernel/winfixup.S6
-rw-r--r--arch/sparc64/lib/Makefile2
-rw-r--r--arch/sparc64/lib/debuglocks.c56
-rw-r--r--arch/sparc64/lib/mb.S73
-rw-r--r--arch/sparc64/solaris/misc.c6
-rw-r--r--arch/v850/configs/rte-ma1-cb_defconfig108
-rw-r--r--arch/v850/configs/rte-me2-cb_defconfig21
-rw-r--r--arch/v850/configs/sim_defconfig21
-rw-r--r--arch/v850/kernel/setup.c44
155 files changed, 5541 insertions, 2954 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4bf0e8737e1..68dfdba71d7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -365,8 +365,8 @@ config NO_IDLE_HZ
Please note that dynamic tick may affect the accuracy of
timekeeping on some platforms depending on the implementation.
- Currently at least OMAP platform is known to have accurate
- timekeeping with dynamic tick.
+ Currently at least OMAP, PXA2xx and SA11x0 platforms are known
+ to have accurate timekeeping with dynamic tick.
config ARCH_DISCONTIGMEM_ENABLE
bool
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 51dbf5489b6..d7499071755 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/smp.h>
+#include <linux/cpumask.h>
#include <asm/irq.h>
#include <asm/io.h>
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 2b6b4c786e6..db07ce42b3b 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -284,7 +284,7 @@ __syscall_start:
.long sys_fstatfs64
.long sys_tgkill
.long sys_utimes
-/* 270 */ .long sys_fadvise64_64
+/* 270 */ .long sys_arm_fadvise64_64_wrapper
.long sys_pciconfig_iobase
.long sys_pciconfig_read
.long sys_pciconfig_write
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 3f8d0e3aefa..6281d488ac9 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -265,6 +265,10 @@ sys_futex_wrapper:
str r5, [sp, #4] @ push sixth arg
b sys_futex
+sys_arm_fadvise64_64_wrapper:
+ str r5, [sp, #4] @ push r5 to stack
+ b sys_arm_fadvise64_64
+
/*
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
* offset, we return EINVAL.
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index f897ce2ccf0..42629ff84f5 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -311,3 +311,13 @@ long execve(const char *filename, char **argv, char **envp)
return ret;
}
EXPORT_SYMBOL(execve);
+
+/*
+ * Since loff_t is a 64 bit type we avoid a lot of ABI hastle
+ * with a different argument ordering.
+ */
+asmlinkage long sys_arm_fadvise64_64(int fd, int advice,
+ loff_t offset, loff_t len)
+{
+ return sys_fadvise64_64(fd, offset, len, advice);
+}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 1b7fcd50c3e..8880482dcbf 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -433,10 +433,12 @@ void timer_dyn_reprogram(void)
{
struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
- write_seqlock(&xtime_lock);
- if (dyn_tick->state & DYN_TICK_ENABLED)
- dyn_tick->reprogram(next_timer_interrupt() - jiffies);
- write_sequnlock(&xtime_lock);
+ if (dyn_tick) {
+ write_seqlock(&xtime_lock);
+ if (dyn_tick->state & DYN_TICK_ENABLED)
+ dyn_tick->reprogram(next_timer_interrupt() - jiffies);
+ write_sequnlock(&xtime_lock);
+ }
}
static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 04490a9f8f6..0422e906cc9 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -38,90 +38,6 @@
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-enum ixp4xx_irq_type {
- IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
-};
-static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
-
-/*************************************************************************
- * GPIO acces functions
- *************************************************************************/
-
-/*
- * Configure GPIO line for input, interrupt, or output operation
- *
- * TODO: Enable/disable the irq_desc based on interrupt or output mode.
- * TODO: Should these be named ixp4xx_gpio_?
- */
-void gpio_line_config(u8 line, u32 style)
-{
- static const int gpio2irq[] = {
- 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
- };
- u32 enable;
- volatile u32 *int_reg;
- u32 int_style;
- enum ixp4xx_irq_type irq_type;
-
- enable = *IXP4XX_GPIO_GPOER;
-
- if (style & IXP4XX_GPIO_OUT) {
- enable &= ~((1) << line);
- } else if (style & IXP4XX_GPIO_IN) {
- enable |= ((1) << line);
-
- switch (style & IXP4XX_GPIO_INTSTYLE_MASK)
- {
- case (IXP4XX_GPIO_ACTIVE_HIGH):
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- case (IXP4XX_GPIO_ACTIVE_LOW):
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- case (IXP4XX_GPIO_RISING_EDGE):
- int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- case (IXP4XX_GPIO_FALLING_EDGE):
- int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- case (IXP4XX_GPIO_TRANSITIONAL):
- int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
- irq_type = IXP4XX_IRQ_EDGE;
- break;
- default:
- int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
- irq_type = IXP4XX_IRQ_LEVEL;
- break;
- }
-
- if (style & IXP4XX_GPIO_INTSTYLE_MASK)
- ixp4xx_config_irq(gpio2irq[line], irq_type);
-
- if (line >= 8) { /* pins 8-15 */
- line -= 8;
- int_reg = IXP4XX_GPIO_GPIT2R;
- }
- else { /* pins 0-7 */
- int_reg = IXP4XX_GPIO_GPIT1R;
- }
-
- /* Clear the style for the appropriate pin */
- *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
- (line * IXP4XX_GPIO_STYLE_SIZE));
-
- /* Set the new style */
- *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
- }
-
- *IXP4XX_GPIO_GPOER = enable;
-}
-
-EXPORT_SYMBOL(gpio_line_config);
-
/*************************************************************************
* IXP4xx chipset I/O mapping
*************************************************************************/
@@ -165,6 +81,69 @@ void __init ixp4xx_map_io(void)
* (be it PCI or something else) configures that GPIO line
* as an IRQ.
**************************************************************************/
+enum ixp4xx_irq_type {
+ IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
+};
+
+static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type);
+
+/*
+ * IRQ -> GPIO mapping table
+ */
+static int irq2gpio[32] = {
+ -1, -1, -1, -1, -1, -1, 0, 1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, -1, -1,
+};
+
+static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+ int line = irq2gpio[irq];
+ u32 int_style;
+ enum ixp4xx_irq_type irq_type;
+ volatile u32 *int_reg;
+
+ /*
+ * Only for GPIO IRQs
+ */
+ if (line < 0)
+ return -EINVAL;
+
+ if (type & IRQT_BOTHEDGE) {
+ int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_RISING) {
+ int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_FALLING) {
+ int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
+ irq_type = IXP4XX_IRQ_EDGE;
+ } else if (type & IRQT_HIGH) {
+ int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
+ irq_type = IXP4XX_IRQ_LEVEL;
+ } else if (type & IRQT_LOW) {
+ int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
+ irq_type = IXP4XX_IRQ_LEVEL;
+ }
+
+ ixp4xx_config_irq(irq, irq_type);
+
+ if (line >= 8) { /* pins 8-15 */
+ line -= 8;
+ int_reg = IXP4XX_GPIO_GPIT2R;
+ } else { /* pins 0-7 */
+ int_reg = IXP4XX_GPIO_GPIT1R;
+ }
+
+ /* Clear the style for the appropriate pin */
+ *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR <<
+ (line * IXP4XX_GPIO_STYLE_SIZE));
+
+ /* Set the new style */
+ *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
+}
+
static void ixp4xx_irq_mask(unsigned int irq)
{
if (cpu_is_ixp46x() && irq >= 32)
@@ -183,12 +162,6 @@ static void ixp4xx_irq_unmask(unsigned int irq)
static void ixp4xx_irq_ack(unsigned int irq)
{
- static int irq2gpio[32] = {
- -1, -1, -1, -1, -1, -1, 0, 1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, -1, -1,
- };
int line = (irq < 32) ? irq2gpio[irq] : -1;
if (line >= 0)
@@ -209,12 +182,14 @@ static struct irqchip ixp4xx_irq_level_chip = {
.ack = ixp4xx_irq_mask,
.mask = ixp4xx_irq_mask,
.unmask = ixp4xx_irq_level_unmask,
+ .type = ixp4xx_set_irq_type
};
static struct irqchip ixp4xx_irq_edge_chip = {
.ack = ixp4xx_irq_ack,
.mask = ixp4xx_irq_mask,
.unmask = ixp4xx_irq_unmask,
+ .type = ixp4xx_set_irq_type
};
static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c
index afafb42ae12..60de8a94cff 100644
--- a/arch/arm/mach-ixp4xx/coyote-pci.c
+++ b/arch/arm/mach-ixp4xx/coyote-pci.c
@@ -30,11 +30,8 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
void __init coyote_pci_preinit(void)
{
- gpio_line_config(COYOTE_PCI_SLOT0_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
-
- gpio_line_config(COYOTE_PCI_SLOT1_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW);
+ set_irq_type(IRQ_COYOTE_PCI_SLOT1, IRQT_LOW);
gpio_line_isr_clear(COYOTE_PCI_SLOT0_PIN);
gpio_line_isr_clear(COYOTE_PCI_SLOT1_PIN);
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 411ea999619..8b2f2532245 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -24,11 +24,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-void __init coyote_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data coyote_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -107,7 +102,7 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = coyote_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -125,7 +120,7 @@ MACHINE_START(IXDPG425, "Intel IXDPG425")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = coyote_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-pci.c b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
index b18035824e3..a66484b63d3 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-pci.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
@@ -35,26 +35,20 @@ extern void ixp4xx_pci_preinit(void);
extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
- /*
- * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
- * Slot 0 isn't actually populated with a card connector but
- * we initialize it anyway in case a future version has the
- * slot populated or someone with good soldering skills has
- * some free time.
- */
-
-
-static void gtwx5715_init_gpio(u8 pin, u32 style)
-{
- gpio_line_config(pin, style | IXP4XX_GPIO_ACTIVE_LOW);
-
- if (style & IXP4XX_GPIO_IN) gpio_line_isr_clear(pin);
-}
+/*
+ * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
+ * Slot 0 isn't actually populated with a card connector but
+ * we initialize it anyway in case a future version has the
+ * slot populated or someone with good soldering skills has
+ * some free time.
+ */
void __init gtwx5715_pci_preinit(void)
{
- gtwx5715_init_gpio(GTWX5715_PCI_SLOT0_INTA_GPIO, IXP4XX_GPIO_IN);
- gtwx5715_init_gpio(GTWX5715_PCI_SLOT1_INTA_GPIO, IXP4XX_GPIO_IN);
+ set_irq_type(GTWX5715_PCI_SLOT0_INTA_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT0_INTB_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT1_INTA_IRQ, IRQT_LOW);
+ set_irq_type(GTWX5715_PCI_SLOT1_INTB_IRQ, IRQT_LOW);
ixp4xx_pci_preinit();
}
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index 333459d6aa4..3fd92c5cbaa 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -101,12 +101,6 @@ static struct platform_device gtwx5715_uart_device = {
.resource = gtwx5715_uart_resources,
};
-
-void __init gtwx5715_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data gtwx5715_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -144,7 +138,7 @@ MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_UART2_BASE_PHYS,
.io_pg_offst = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = gtwx5715_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c
index c2ab9ebb598..f9a1d3e7d69 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
@@ -27,14 +27,10 @@
void __init ixdp425_pci_preinit(void)
{
- gpio_line_config(IXDP425_PCI_INTA_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTB_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTC_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(IXDP425_PCI_INTD_PIN,
- IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTA, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTB, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTC, IRQT_LOW);
+ set_irq_type(IRQ_IXDP425_PCI_INTD, IRQT_LOW);
gpio_line_isr_clear(IXDP425_PCI_INTA_PIN);
gpio_line_isr_clear(IXDP425_PCI_INTB_PIN);
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index fa0646c8693..6c14ff3c23a 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -24,11 +24,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
-void __init ixdp425_map_io(void)
-{
- ixp4xx_map_io();
-}
-
static struct flash_platform_data ixdp425_flash_data = {
.map_name = "cfi_probe",
.width = 2,
@@ -133,7 +128,7 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -145,7 +140,7 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -157,7 +152,7 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
@@ -176,7 +171,7 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform")
.phys_ram = PHYS_OFFSET,
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
- .map_io = ixdp425_map_io,
+ .map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
.boot_params = 0x0100,
diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
index ce4563f0067..fe5e7660de1 100644
--- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
@@ -29,8 +29,8 @@ extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
void __init ixdpg425_pci_preinit(void)
{
- gpio_line_config(6, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
- gpio_line_config(7, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO7, IRQT_LOW);
gpio_line_isr_clear(6);
gpio_line_isr_clear(7);
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 6e5202154f9..7dad3f1465e 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -70,6 +70,11 @@ static unsigned long pxa_gettimeoffset (void)
return usec;
}
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
static irqreturn_t
pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -77,11 +82,19 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_seqlock(&xtime_lock);
+#ifdef CONFIG_NO_IDLE_HZ
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ }
+#endif
+
/* Loop until we get ahead of the free running timer.
* This ensures an exact clock tick count and time accuracy.
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
+ * Since IRQs are disabled at this point, coherence between
+ * lost_ticks(updated in do_timer()) and the match reg value is
+ * ensured, hence we can use do_gettimeofday() from interrupt
+ * handlers.
*
* HACK ALERT: it seems that the PXA timer regs aren't updated right
* away in all cases when a write occurs. We therefore compare with
@@ -126,6 +139,42 @@ static void __init pxa_timer_init(void)
OSCR = 0; /* initialize free-running timer, force first match */
}
+#ifdef CONFIG_NO_IDLE_HZ
+static int pxa_dyn_tick_enable_disable(void)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static void pxa_dyn_tick_reprogram(unsigned long ticks)
+{
+ if (ticks > 1) {
+ initial_match = OSMR0;
+ OSMR0 = initial_match + ticks * LATCH;
+ match_posponed = 1;
+ }
+}
+
+static irqreturn_t
+pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ( (signed long)(initial_match - OSCR) <= 8 )
+ return pxa_timer_interrupt(irq, dev_id, regs);
+ }
+ return IRQ_NONE;
+}
+
+static struct dyn_tick_timer pxa_dyn_tick = {
+ .enable = pxa_dyn_tick_enable_disable,
+ .disable = pxa_dyn_tick_enable_disable,
+ .reprogram = pxa_dyn_tick_reprogram,
+ .handler = pxa_dyn_tick_handler,
+};
+#endif
+
#ifdef CONFIG_PM
static unsigned long osmr[4], oier;
@@ -161,4 +210,7 @@ struct sys_timer pxa_timer = {
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
.offset = pxa_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+ .dyn_tick = &pxa_dyn_tick,
+#endif
};
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 9a66050e887..f5960826875 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -388,6 +388,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
unsigned long hclk,
unsigned long pclk)
{
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
struct clk *clkp = init_clocks;
int ptr;
int ret;
@@ -446,5 +447,13 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
}
}
+ /* show the clock-slow value */
+
+ printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+ print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+ (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+ (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+ (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
+
return 0;
}
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c
index b018a1f680c..c67e0979aec 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2440-clock.c
@@ -68,6 +68,7 @@ static struct clk s3c2440_clk_ac97 = {
static int s3c2440_clk_add(struct sys_device *sysdev)
{
unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+ unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
struct clk *clk_h;
struct clk *clk_p;
struct clk *clk_xtal;
@@ -80,8 +81,9 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal->rate);
- printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
- print_mhz(s3c2440_clk_upll.rate));
+ printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz, DVS %s\n",
+ print_mhz(s3c2440_clk_upll.rate),
+ (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
clk_p = clk_get(NULL, "pclk");
clk_h = clk_get(NULL, "hclk");
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 0eeb3616ffe..47e0420623f 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -70,15 +70,11 @@ static unsigned long sa1100_gettimeoffset (void)
return usec;
}
-/*
- * We will be entered with IRQs enabled.
- *
- * Loop until we get ahead of the free running timer.
- * This ensures an exact clock tick count and time accuracy.
- * IRQs are disabled inside the loop to ensure coherence between
- * lost_ticks (updated in do_timer()) and the match reg value, so we
- * can use do_gettimeofday() from interrupt handlers.
- */
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
static irqreturn_t
sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -86,6 +82,21 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_seqlock(&xtime_lock);
+#ifdef CONFIG_NO_IDLE_HZ
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ }
+#endif
+
+ /*
+ * Loop until we get ahead of the free running timer.
+ * This ensures an exact clock tick count and time accuracy.
+ * Since IRQs are disabled at this point, coherence between
+ * lost_ticks(updated in do_timer()) and the match reg value is
+ * ensured, hence we can use do_gettimeofday() from interrupt
+ * handlers.
+ */
do {
timer_tick(regs);
OSSR = OSSR_M0; /* Clear match on timer 0 */
@@ -120,6 +131,42 @@ static void __init sa1100_timer_init(void)
OSCR = 0; /* initialize free-running timer, force first match */
}
+#ifdef CONFIG_NO_IDLE_HZ
+static int sa1100_dyn_tick_enable_disable(void)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static void sa1100_dyn_tick_reprogram(unsigned long ticks)
+{
+ if (ticks > 1) {
+ initial_match = OSMR0;
+ OSMR0 = initial_match + ticks * LATCH;
+ match_posponed = 1;
+ }
+}
+
+static irqreturn_t
+sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (match_posponed) {
+ match_posponed = 0;
+ OSMR0 = initial_match;
+ if ((signed long)(initial_match - OSCR) <= 0)
+ return sa1100_timer_interrupt(irq, dev_id, regs);
+ }
+ return IRQ_NONE;
+}
+
+static struct dyn_tick_timer sa1100_dyn_tick = {
+ .enable = sa1100_dyn_tick_enable_disable,
+ .disable = sa1100_dyn_tick_enable_disable,
+ .reprogram = sa1100_dyn_tick_reprogram,
+ .handler = sa1100_dyn_tick_handler,
+};
+#endif
+
#ifdef CONFIG_PM
unsigned long osmr[4], oier;
@@ -156,4 +203,7 @@ struct sys_timer sa1100_timer = {
.suspend = sa1100_timer_suspend,
.resume = sa1100_timer_resume,
.offset = sa1100_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+ .dyn_tick = &sa1100_dyn_tick,
+#endif
};
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 81f4a8a2d34..4b39d867ac1 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -45,7 +45,7 @@
#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
-#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
+#define LDSTHD_I_BIT(i) (i & (1 << 22)) /* double/half-word immed */
#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
#define RN_BITS(i) ((i >> 16) & 15) /* Rn */
@@ -68,6 +68,7 @@ static unsigned long ai_sys;
static unsigned long ai_skipped;
static unsigned long ai_half;
static unsigned long ai_word;
+static unsigned long ai_dword;
static unsigned long ai_multi;
static int ai_usermode;
@@ -93,6 +94,8 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
p += sprintf(p, "Half:\t\t%lu\n", ai_half);
p += sprintf(p, "Word:\t\t%lu\n", ai_word);
+ if (cpu_architecture() >= CPU_ARCH_ARMv5TE)
+ p += sprintf(p, "DWord:\t\t%lu\n", ai_dword);
p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
usermode_action[ai_usermode]);
@@ -283,12 +286,6 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
{
unsigned int rd = RD_BITS(instr);
- if ((instr & 0x01f00ff0) == 0x01000090)
- goto swp;
-
- if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
- goto bad;
-
ai_half += 1;
if (user_mode(regs))
@@ -323,10 +320,47 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
return TYPE_LDST;
- swp:
- printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
- bad:
- return TYPE_ERROR;
+ fault:
+ return TYPE_FAULT;
+}
+
+static int
+do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
+ struct pt_regs *regs)
+{
+ unsigned int rd = RD_BITS(instr);
+
+ ai_dword += 1;
+
+ if (user_mode(regs))
+ goto user;
+
+ if ((instr & 0xf0) == 0xd0) {
+ unsigned long val;
+ get32_unaligned_check(val, addr);
+ regs->uregs[rd] = val;
+ get32_unaligned_check(val, addr+4);
+ regs->uregs[rd+1] = val;
+ } else {
+ put32_unaligned_check(regs->uregs[rd], addr);
+ put32_unaligned_check(regs->uregs[rd+1], addr+4);
+ }
+
+ return TYPE_LDST;
+
+ user:
+ if ((instr & 0xf0) == 0xd0) {
+ unsigned long val;
+ get32t_unaligned_check(val, addr);
+ regs->uregs[rd] = val;
+ get32t_unaligned_check(val, addr+4);
+ regs->uregs[rd+1] = val;
+ } else {
+ put32t_unaligned_check(regs->uregs[rd], addr);
+ put32t_unaligned_check(regs->uregs[rd+1], addr+4);
+ }
+
+ return TYPE_LDST;
fault:
return TYPE_FAULT;
@@ -617,12 +651,20 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
switch (CODING_BITS(instr)) {
- case 0x00000000: /* ldrh or strh */
- if (LDSTH_I_BIT(instr))
+ case 0x00000000: /* 3.13.4 load/store instruction extensions */
+ if (LDSTHD_I_BIT(instr))
offset.un = (instr & 0xf00) >> 4 | (instr & 15);
else
offset.un = regs->uregs[RM_BITS(instr)];
- handler = do_alignment_ldrhstrh;
+
+ if ((instr & 0x000000f0) == 0x000000b0 || /* LDRH, STRH */
+ (instr & 0x001000f0) == 0x001000f0) /* LDRSH */
+ handler = do_alignment_ldrhstrh;
+ else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */
+ (instr & 0x001000f0) == 0x000000f0) /* STRD */
+ handler = do_alignment_ldrdstrd;
+ else
+ goto bad;
break;
case 0x04000000: /* ldr or str immediate */
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 3c655c54e23..d125a3dc061 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -275,11 +275,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
int i;
for (i = 0; i < 16; i += 1) {
- alloc_init_section(virt, phys & SUPERSECTION_MASK,
- prot | PMD_SECT_SUPER);
+ alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
virt += (PGDIR_SIZE / 2);
- phys += (PGDIR_SIZE / 2);
}
}
@@ -297,14 +295,10 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
pte_t *ptep;
if (pmd_none(*pmdp)) {
- unsigned long pmdval;
ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
sizeof(pte_t));
- pmdval = __pa(ptep) | prot_l1;
- pmdp[0] = __pmd(pmdval);
- pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
- flush_pmd_entry(pmdp);
+ __pmd_populate(pmdp, __pa(ptep) | prot_l1);
}
ptep = pte_offset_kernel(pmdp, virt);
@@ -459,7 +453,7 @@ static void __init build_mem_type_table(void)
for (i = 0; i < 16; i++) {
unsigned long v = pgprot_val(protection_map[i]);
- v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
+ v = (v & ~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot;
protection_map[i] = __pgprot(v);
}
@@ -583,23 +577,23 @@ static void __init create_mapping(struct map_desc *md)
*/
void setup_mm_for_reboot(char mode)
{
- unsigned long pmdval;
+ unsigned long base_pmdval;
pgd_t *pgd;
- pmd_t *pmd;
int i;
- int cpu_arch = cpu_architecture();
if (current->mm && current->mm->pgd)
pgd = current->mm->pgd;
else
pgd = init_mm.pgd;
- for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
- pmdval = (i << PGDIR_SHIFT) |
- PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
- PMD_TYPE_SECT;
- if (cpu_arch <= CPU_ARCH_ARMv5TEJ)
- pmdval |= PMD_BIT4;
+ base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
+ if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ)
+ base_pmdval |= PMD_BIT4;
+
+ for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
+ unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
+ pmd_t *pmd;
+
pmd = pmd_off(pgd, i << PGDIR_SHIFT);
pmd[0] = __pmd(pmdval);
pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index ade5bc57c34..c96bea14b98 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -165,7 +165,6 @@ static int __init pcibios_init(void)
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
#endif
- pci_assign_unassigned_resources();
return 0;
}
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index 93a364c8215..3cc480998a4 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -170,43 +170,26 @@ static void __init pcibios_allocate_resources(int pass)
static int __init pcibios_assign_resources(void)
{
struct pci_dev *dev = NULL;
- int idx;
- struct resource *r;
-
- for_each_pci_dev(dev) {
- int class = dev->class >> 8;
-
- /* Don't touch classless devices and host bridges */
- if (!class || class == PCI_CLASS_BRIDGE_HOST)
- continue;
-
- for(idx=0; idx<6; idx++) {
- r = &dev->resource[idx];
-
- /*
- * Don't touch IDE controllers and I/O ports of video cards!
- */
- if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
- (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
- continue;
-
- /*
- * We shall assign a new address to this resource, either because
- * the BIOS forgot to do so or because we have decided the old
- * address was unusable for some reason.
- */
- if (!r->start && r->end)
- pci_assign_resource(dev, idx);
- }
+ struct resource *r, *pr;
- if (pci_probe & PCI_ASSIGN_ROMS) {
+ if (!(pci_probe & PCI_ASSIGN_ROMS)) {
+ /* Try to use BIOS settings for ROMs, otherwise let
+ pci_assign_unassigned_resources() allocate the new
+ addresses. */
+ for_each_pci_dev(dev) {
r = &dev->resource[PCI_ROM_RESOURCE];
- r->end -= r->start;
- r->start = 0;
- if (r->end)
- pci_assign_resource(dev, PCI_ROM_RESOURCE);
+ if (!r->flags || !r->start)
+ continue;
+ pr = pci_find_parent_resource(dev, r);
+ if (!pr || request_resource(pr, r) < 0) {
+ r->end -= r->start;
+ r->start = 0;
+ }
}
}
+
+ pci_assign_unassigned_resources();
+
return 0;
}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index addf07393ef..e1c9ea03f31 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -357,6 +357,12 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"
+if PM
+
+source "arch/ia64/kernel/cpufreq/Kconfig"
+
+endif
+
endmenu
if !IA64_HP_SIM
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 5c46928e3dc..30fdfb1d0a5 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -237,17 +237,6 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
return ((struct sal_ret_values) {status, r9, r10, r11});
}
-
-/*
- * This is here to work around a bug in egcs-1.1.1b that causes the
- * compiler to crash (seems like a bug in the new alias analysis code.
- */
-void *
-id (long addr)
-{
- return (void *) addr;
-}
-
struct ia64_boot_param *
sys_fw_init (const char *args, int arglen)
{
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index ebb89be2aa2..aa891c9bc9b 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -29,7 +29,6 @@
#include <asm/uaccess.h>
#include <asm/rse.h>
#include <asm/sigcontext.h>
-#include <asm/segment.h>
#include "ia32priv.h"
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index e1fb68ddec2..b242594be55 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o domain.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
diff --git a/arch/ia64/kernel/cpufreq/Kconfig b/arch/ia64/kernel/cpufreq/Kconfig
new file mode 100644
index 00000000000..2d9d5279b98
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/Kconfig
@@ -0,0 +1,29 @@
+
+#
+# CPU Frequency scaling
+#
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+if CPU_FREQ
+
+comment "CPUFreq processor drivers"
+
+config IA64_ACPI_CPUFREQ
+ tristate "ACPI Processor P-States driver"
+ select CPU_FREQ_TABLE
+ depends on ACPI_PROCESSOR
+ help
+ This driver adds a CPUFreq driver which utilizes the ACPI
+ Processor Performance States.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+endif # CPU_FREQ
+
+endmenu
+
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile
new file mode 100644
index 00000000000..f748d34c02f
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
new file mode 100644
index 00000000000..da4d5cf80a4
--- /dev/null
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -0,0 +1,499 @@
+/*
+ * arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+ * This file provides the ACPI based P-state support. This
+ * module works with generic cpufreq infrastructure. Most of
+ * the code is based on i386 version
+ * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
+ *
+ * Copyright (C) 2005 Intel Corp
+ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pal.h>
+
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
+
+MODULE_AUTHOR("Venkatesh Pallipadi");
+MODULE_DESCRIPTION("ACPI Processor P-States Driver");
+MODULE_LICENSE("GPL");
+
+
+struct cpufreq_acpi_io {
+ struct acpi_processor_performance acpi_data;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int resume;
+};
+
+static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
+
+static struct cpufreq_driver acpi_cpufreq_driver;
+
+
+static int
+processor_set_pstate (
+ u32 value)
+{
+ s64 retval;
+
+ dprintk("processor_set_pstate\n");
+
+ retval = ia64_pal_set_pstate((u64)value);
+
+ if (retval) {
+ dprintk("Failed to set freq to 0x%x, with error 0x%x\n",
+ value, retval);
+ return -ENODEV;
+ }
+ return (int)retval;
+}
+
+
+static int
+processor_get_pstate (
+ u32 *value)
+{
+ u64 pstate_index = 0;
+ s64 retval;
+
+ dprintk("processor_get_pstate\n");
+
+ retval = ia64_pal_get_pstate(&pstate_index);
+ *value = (u32) pstate_index;
+
+ if (retval)
+ dprintk("Failed to get current freq with "
+ "error 0x%x, idx 0x%x\n", retval, *value);
+
+ return (int)retval;
+}
+
+
+/* To be used only after data->acpi_data is initialized */
+static unsigned
+extract_clock (
+ struct cpufreq_acpi_io *data,
+ unsigned value,
+ unsigned int cpu)
+{
+ unsigned long i;
+
+ dprintk("extract_clock\n");
+
+ for (i = 0; i < data->acpi_data.state_count; i++) {
+ if (value >= data->acpi_data.states[i].control)
+ return data->acpi_data.states[i].core_frequency;
+ }
+ return data->acpi_data.states[i-1].core_frequency;
+}
+
+
+static unsigned int
+processor_get_freq (
+ struct cpufreq_acpi_io *data,
+ unsigned int cpu)
+{
+ int ret = 0;
+ u32 value = 0;
+ cpumask_t saved_mask;
+ unsigned long clock_freq;
+
+ dprintk("processor_get_freq\n");
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (smp_processor_id() != cpu) {
+ ret = -EAGAIN;
+ goto migrate_end;
+ }
+
+ /*
+ * processor_get_pstate gets the average frequency since the
+ * last get. So, do two PAL_get_freq()...
+ */
+ ret = processor_get_pstate(&value);
+ ret = processor_get_pstate(&value);
+
+ if (ret) {
+ set_cpus_allowed(current, saved_mask);
+ printk(KERN_WARNING "get performance failed with error %d\n",
+ ret);
+ ret = -EAGAIN;
+ goto migrate_end;
+ }
+ clock_freq = extract_clock(data, value, cpu);
+ ret = (clock_freq*1000);
+
+migrate_end:
+ set_cpus_allowed(current, saved_mask);
+ return ret;
+}
+
+
+static int
+processor_set_freq (
+ struct cpufreq_acpi_io *data,
+ unsigned int cpu,
+ int state)
+{
+ int ret = 0;
+ u32 value = 0;
+ struct cpufreq_freqs cpufreq_freqs;
+ cpumask_t saved_mask;
+ int retval;
+
+ dprintk("processor_set_freq\n");
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (smp_processor_id() != cpu) {
+ retval = -EAGAIN;
+ goto migrate_end;
+ }
+
+ if (state == data->acpi_data.state) {
+ if (unlikely(data->resume)) {
+ dprintk("Called after resume, resetting to P%d\n", state);
+ data->resume = 0;
+ } else {
+ dprintk("Already at target state (P%d)\n", state);
+ retval = 0;
+ goto migrate_end;
+ }
+ }
+
+ dprintk("Transitioning from P%d to P%d\n",
+ data->acpi_data.state, state);
+
+ /* cpufreq frequency struct */
+ cpufreq_freqs.cpu = cpu;
+ cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
+ cpufreq_freqs.new = data->freq_table[state].frequency;
+
+ /* notify cpufreq */
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+
+ /*
+ * First we write the target state's 'control' value to the
+ * control_register.
+ */
+
+ value = (u32) data->acpi_data.states[state].control;
+
+ dprintk("Transitioning to state: 0x%08x\n", value);
+
+ ret = processor_set_pstate(value);
+ if (ret) {
+ unsigned int tmp = cpufreq_freqs.new;
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_freqs.new = cpufreq_freqs.old;
+ cpufreq_freqs.old = tmp;
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ printk(KERN_WARNING "Transition failed with error %d\n", ret);
+ retval = -ENODEV;
+ goto migrate_end;
+ }
+
+ cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+
+ data->acpi_data.state = state;
+
+ retval = 0;
+
+migrate_end:
+ set_cpus_allowed(current, saved_mask);
+ return (retval);
+}
+
+
+static unsigned int
+acpi_cpufreq_get (
+ unsigned int cpu)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[cpu];
+
+ dprintk("acpi_cpufreq_get\n");
+
+ return processor_get_freq(data, cpu);
+}
+
+
+static int
+acpi_cpufreq_target (
+ struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+ unsigned int next_state = 0;
+ unsigned int result = 0;
+
+ dprintk("acpi_cpufreq_setpolicy\n");
+
+ result = cpufreq_frequency_table_target(policy,
+ data->freq_table, target_freq, relation, &next_state);
+ if (result)
+ return (result);
+
+ result = processor_set_freq(data, policy->cpu, next_state);
+
+ return (result);
+}
+
+
+static int
+acpi_cpufreq_verify (
+ struct cpufreq_policy *policy)
+{
+ unsigned int result = 0;
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+ dprintk("acpi_cpufreq_verify\n");
+
+ result = cpufreq_frequency_table_verify(policy,
+ data->freq_table);
+
+ return (result);
+}
+
+
+/*
+ * processor_init_pdc - let BIOS know about the SMP capabilities
+ * of this driver
+ * @perf: processor-specific acpi_io_data struct
+ * @cpu: CPU being initialized
+ *
+ * To avoid issues with legacy OSes, some BIOSes require to be informed of
+ * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC
+ * accordingly. Actual call to _PDC is done in driver/acpi/processor.c
+ */
+static void
+processor_init_pdc (
+ struct acpi_processor_performance *perf,
+ unsigned int cpu,
+ struct acpi_object_list *obj_list
+ )
+{
+ union acpi_object *obj;
+ u32 *buf;
+
+ dprintk("processor_init_pdc\n");
+
+ perf->pdc = NULL;
+ /* Initialize pdc. It will be used later. */
+ if (!obj_list)
+ return;
+
+ if (!(obj_list->count && obj_list->pointer))
+ return;
+
+ obj = obj_list->pointer;
+ if ((obj->buffer.length == 12) && obj->buffer.pointer) {
+ buf = (u32 *)obj->buffer.pointer;
+ buf[0] = ACPI_PDC_REVISION_ID;
+ buf[1] = 1;
+ buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
+ perf->pdc = obj_list;
+ }
+ return;
+}
+
+
+static int
+acpi_cpufreq_cpu_init (
+ struct cpufreq_policy *policy)
+{
+ unsigned int i;
+ unsigned int cpu = policy->cpu;
+ struct cpufreq_acpi_io *data;
+ unsigned int result = 0;
+
+ union acpi_object arg0 = {ACPI_TYPE_BUFFER};
+ u32 arg0_buf[3];
+ struct acpi_object_list arg_list = {1, &arg0};
+
+ dprintk("acpi_cpufreq_cpu_init\n");
+ /* setup arg_list for _PDC settings */
+ arg0.buffer.length = 12;
+ arg0.buffer.pointer = (u8 *) arg0_buf;
+
+ data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+ if (!data)
+ return (-ENOMEM);
+
+ memset(data, 0, sizeof(struct cpufreq_acpi_io));
+
+ acpi_io_data[cpu] = data;
+
+ processor_init_pdc(&data->acpi_data, cpu, &arg_list);
+ result = acpi_processor_register_performance(&data->acpi_data, cpu);
+ data->acpi_data.pdc = NULL;
+
+ if (result)
+ goto err_free;
+
+ /* capability check */
+ if (data->acpi_data.state_count <= 1) {
+ dprintk("No P-States\n");
+ result = -ENODEV;
+ goto err_unreg;
+ }
+
+ if ((data->acpi_data.control_register.space_id !=
+ ACPI_ADR_SPACE_FIXED_HARDWARE) ||
+ (data->acpi_data.status_register.space_id !=
+ ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+ dprintk("Unsupported address space [%d, %d]\n",
+ (u32) (data->acpi_data.control_register.space_id),
+ (u32) (data->acpi_data.status_register.space_id));
+ result = -ENODEV;
+ goto err_unreg;
+ }
+
+ /* alloc freq_table */
+ data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+ (data->acpi_data.state_count + 1),
+ GFP_KERNEL);
+ if (!data->freq_table) {
+ result = -ENOMEM;
+ goto err_unreg;
+ }
+
+ /* detect transition latency */
+ policy->cpuinfo.transition_latency = 0;
+ for (i=0; i<data->acpi_data.state_count; i++) {
+ if ((data->acpi_data.states[i].transition_latency * 1000) >
+ policy->cpuinfo.transition_latency) {
+ policy->cpuinfo.transition_latency =
+ data->acpi_data.states[i].transition_latency * 1000;
+ }
+ }
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cur = processor_get_freq(data, policy->cpu);
+
+ /* table init */
+ for (i = 0; i <= data->acpi_data.state_count; i++)
+ {
+ data->freq_table[i].index = i;
+ if (i < data->acpi_data.state_count) {
+ data->freq_table[i].frequency =
+ data->acpi_data.states[i].core_frequency * 1000;
+ } else {
+ data->freq_table[i].frequency = CPUFREQ_TABLE_END;
+ }
+ }
+
+ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+ if (result) {
+ goto err_freqfree;
+ }
+
+ /* notify BIOS that we exist */
+ acpi_processor_notify_smm(THIS_MODULE);
+
+ printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management "
+ "activated.\n", cpu);
+
+ for (i = 0; i < data->acpi_data.state_count; i++)
+ dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
+ (i == data->acpi_data.state?'*':' '), i,
+ (u32) data->acpi_data.states[i].core_frequency,
+ (u32) data->acpi_data.states[i].power,
+ (u32) data->acpi_data.states[i].transition_latency,
+ (u32) data->acpi_data.states[i].bus_master_latency,
+ (u32) data->acpi_data.states[i].status,
+ (u32) data->acpi_data.states[i].control);
+
+ cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
+
+ /* the first call to ->target() should result in us actually
+ * writing something to the appropriate registers. */
+ data->resume = 1;
+
+ return (result);
+
+ err_freqfree:
+ kfree(data->freq_table);
+ err_unreg:
+ acpi_processor_unregister_performance(&data->acpi_data, cpu);
+ err_free:
+ kfree(data);
+ acpi_io_data[cpu] = NULL;
+
+ return (result);
+}
+
+
+static int
+acpi_cpufreq_cpu_exit (
+ struct cpufreq_policy *policy)
+{
+ struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+ dprintk("acpi_cpufreq_cpu_exit\n");
+
+ if (data) {
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ acpi_io_data[policy->cpu] = NULL;
+ acpi_processor_unregister_performance(&data->acpi_data,
+ policy->cpu);
+ kfree(data);
+ }
+
+ return (0);
+}
+
+
+static struct freq_attr* acpi_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+
+static struct cpufreq_driver acpi_cpufreq_driver = {
+ .verify = acpi_cpufreq_verify,
+ .target = acpi_cpufreq_target,
+ .get = acpi_cpufreq_get,
+ .init = acpi_cpufreq_cpu_init,
+ .exit = acpi_cpufreq_cpu_exit,
+ .name = "acpi-cpufreq",
+ .owner = THIS_MODULE,
+ .attr = acpi_cpufreq_attr,
+};
+
+
+static int __init
+acpi_cpufreq_init (void)
+{
+ dprintk("acpi_cpufreq_init\n");
+
+ return cpufreq_register_driver(&acpi_cpufreq_driver);
+}
+
+
+static void __exit
+acpi_cpufreq_exit (void)
+{
+ dprintk("acpi_cpufreq_exit\n");
+
+ cpufreq_unregister_driver(&acpi_cpufreq_driver);
+ return;
+}
+
+
+late_initcall(acpi_cpufreq_init);
+module_exit(acpi_cpufreq_exit);
+
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 770fab37928..f2dbcd1db0d 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -35,7 +35,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
return -ENOMEM;
#ifdef CONFIG_HUGETLB_PAGE
- if (REGION_NUMBER(addr) == REGION_HPAGE)
+ if (REGION_NUMBER(addr) == RGN_HPAGE)
addr = 0;
#endif
if (!addr)
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index 490dfc9ab47..4e9d06c48a8 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -184,7 +184,7 @@ uncached_free_page(unsigned long maddr)
{
int node;
- node = nasid_to_cnodeid(NASID_GET(maddr));
+ node = paddr_to_nid(maddr - __IA64_UNCACHED_OFFSET);
dprintk(KERN_DEBUG "uncached_free_page(%lx) on node %i\n", maddr, node);
@@ -217,7 +217,7 @@ uncached_build_memmap(unsigned long start, unsigned long end, void *arg)
memset((char *)vstart, 0, length);
- node = nasid_to_cnodeid(NASID_GET(start));
+ node = paddr_to_nid(start);
for (; vstart < vend ; vstart += PAGE_SIZE) {
dprintk(KERN_INFO "sticking %lx into the pool!\n", vstart);
diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
index 1902c3c2ef9..799407e7726 100644
--- a/arch/ia64/lib/Makefile
+++ b/arch/ia64/lib/Makefile
@@ -6,7 +6,7 @@ obj-y := io.o
lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \
- bitop.o checksum.o clear_page.o csum_partial_copy.o copy_page.o \
+ bitop.o checksum.o clear_page.o csum_partial_copy.o \
clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \
flush.o ip_fast_csum.o do_csum.o \
memset.o strlen.o swiotlb.o
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
index ab7b3ad99a7..dbc0b3e449c 100644
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -93,8 +93,7 @@ static int __init
setup_io_tlb_npages(char *str)
{
if (isdigit(*str)) {
- io_tlb_nslabs = simple_strtoul(str, &str, 0) <<
- (PAGE_SHIFT - IO_TLB_SHIFT);
+ io_tlb_nslabs = simple_strtoul(str, &str, 0);
/* avoid tail segment of size < IO_TLB_SEGSIZE */
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
@@ -117,7 +116,7 @@ swiotlb_init_with_default_size (size_t default_size)
unsigned long i;
if (!io_tlb_nslabs) {
- io_tlb_nslabs = (default_size >> PAGE_SHIFT);
+ io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
}
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index e0a776a3044..2d13889d0a9 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -76,7 +76,7 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
return -EINVAL;
if (addr & ~HPAGE_MASK)
return -EINVAL;
- if (REGION_NUMBER(addr) != REGION_HPAGE)
+ if (REGION_NUMBER(addr) != RGN_HPAGE)
return -EINVAL;
return 0;
@@ -87,7 +87,7 @@ struct page *follow_huge_addr(struct mm_struct *mm, unsigned long addr, int writ
struct page *page;
pte_t *ptep;
- if (REGION_NUMBER(addr) != REGION_HPAGE)
+ if (REGION_NUMBER(addr) != RGN_HPAGE)
return ERR_PTR(-EINVAL);
ptep = huge_pte_offset(mm, addr);
@@ -142,8 +142,8 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u
return -ENOMEM;
if (len & ~HPAGE_MASK)
return -EINVAL;
- /* This code assumes that REGION_HPAGE != 0. */
- if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE - 1)))
+ /* This code assumes that RGN_HPAGE != 0. */
+ if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
addr = HPAGE_REGION_BASE;
else
addr = ALIGN(addr, HPAGE_SIZE);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index f9472c50ab4..9977c122e9f 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -24,7 +24,6 @@
#include <asm/machvec.h>
#include <asm/page.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/sal.h>
diff --git a/arch/ia64/sn/include/tio.h b/arch/ia64/sn/include/tio.h
index 0139124dd54..6b2e7b75eb1 100644
--- a/arch/ia64/sn/include/tio.h
+++ b/arch/ia64/sn/include/tio.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_TIO_H
@@ -26,6 +26,10 @@
#define TIO_ITTE_VALID_MASK 0x1
#define TIO_ITTE_VALID_SHIFT 16
+#define TIO_ITTE_WIDGET(itte) \
+ (((itte) >> TIO_ITTE_WIDGET_SHIFT) & TIO_ITTE_WIDGET_MASK)
+#define TIO_ITTE_VALID(itte) \
+ (((itte) >> TIO_ITTE_VALID_SHIFT) & TIO_ITTE_VALID_MASK)
#define TIO_ITTE_PUT(nasid, bigwin, widget, addr, valid) \
REMOTE_HUB_S((nasid), TIO_ITTE(bigwin), \
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
index 580a1c0403a..71c2b271b4c 100644
--- a/arch/ia64/sn/include/xtalk/hubdev.h
+++ b/arch/ia64/sn/include/xtalk/hubdev.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
#define _ASM_IA64_SN_XTALK_HUBDEV_H
@@ -16,6 +16,9 @@
#define IIO_ITTE_WIDGET_MASK ((1<<IIO_ITTE_WIDGET_BITS)-1)
#define IIO_ITTE_WIDGET_SHIFT 8
+#define IIO_ITTE_WIDGET(itte) \
+ (((itte) >> IIO_ITTE_WIDGET_SHIFT) & IIO_ITTE_WIDGET_MASK)
+
/*
* Use the top big window as a surrogate for the first small window
*/
@@ -34,7 +37,8 @@ struct sn_flush_device_list {
unsigned long sfdl_force_int_addr;
unsigned long sfdl_flush_value;
volatile unsigned long *sfdl_flush_addr;
- uint64_t sfdl_persistent_busnum;
+ uint32_t sfdl_persistent_busnum;
+ uint32_t sfdl_persistent_segment;
struct pcibus_info *sfdl_pcibus_info;
spinlock_t sfdl_flush_lock;
};
@@ -58,7 +62,8 @@ struct hubdev_info {
void *hdi_nodepda;
void *hdi_node_vertex;
- void *hdi_xtalk_vertex;
+ uint32_t max_segment_number;
+ uint32_t max_pcibus_number;
};
extern void hubdev_init_node(nodepda_t *, cnodeid_t);
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
index 647deae9bfc..45854c637e9 100644
--- a/arch/ia64/sn/kernel/bte.c
+++ b/arch/ia64/sn/kernel/bte.c
@@ -29,16 +29,30 @@
/* two interfaces on two btes */
#define MAX_INTERFACES_TO_TRY 4
+#define MAX_NODES_TO_TRY 2
static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface)
{
nodepda_t *tmp_nodepda;
+ if (nasid_to_cnodeid(nasid) == -1)
+ return (struct bteinfo_s *)NULL;;
+
tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid));
return &tmp_nodepda->bte_if[interface];
}
+static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode)
+{
+ if (is_shub2()) {
+ BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24)));
+ } else {
+ BTE_LNSTAT_STORE(bte, len);
+ BTE_CTRL_STORE(bte, mode);
+ }
+}
+
/************************************************************************
* Block Transfer Engine copy related functions.
*
@@ -67,13 +81,15 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
{
u64 transfer_size;
u64 transfer_stat;
+ u64 notif_phys_addr;
struct bteinfo_s *bte;
bte_result_t bte_status;
unsigned long irq_flags;
unsigned long itc_end = 0;
- struct bteinfo_s *btes_to_try[MAX_INTERFACES_TO_TRY];
- int bte_if_index;
- int bte_pri, bte_sec;
+ int nasid_to_try[MAX_NODES_TO_TRY];
+ int my_nasid = get_nasid();
+ int bte_if_index, nasid_index;
+ int bte_first, btes_per_node = BTES_PER_NODE;
BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n",
src, dest, len, mode, notification));
@@ -86,36 +102,26 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
(src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
- /* CPU 0 (per node) tries bte0 first, CPU 1 try bte1 first */
- if (cpuid_to_subnode(smp_processor_id()) == 0) {
- bte_pri = 0;
- bte_sec = 1;
- } else {
- bte_pri = 1;
- bte_sec = 0;
- }
+ /*
+ * Start with interface corresponding to cpu number
+ */
+ bte_first = raw_smp_processor_id() % btes_per_node;
if (mode & BTE_USE_DEST) {
/* try remote then local */
- btes_to_try[0] = bte_if_on_node(NASID_GET(dest), bte_pri);
- btes_to_try[1] = bte_if_on_node(NASID_GET(dest), bte_sec);
+ nasid_to_try[0] = NASID_GET(dest);
if (mode & BTE_USE_ANY) {
- btes_to_try[2] = bte_if_on_node(get_nasid(), bte_pri);
- btes_to_try[3] = bte_if_on_node(get_nasid(), bte_sec);
+ nasid_to_try[1] = my_nasid;
} else {
- btes_to_try[2] = NULL;
- btes_to_try[3] = NULL;
+ nasid_to_try[1] = (int)NULL;
}
} else {
/* try local then remote */
- btes_to_try[0] = bte_if_on_node(get_nasid(), bte_pri);
- btes_to_try[1] = bte_if_on_node(get_nasid(), bte_sec);
+ nasid_to_try[0] = my_nasid;
if (mode & BTE_USE_ANY) {
- btes_to_try[2] = bte_if_on_node(NASID_GET(dest), bte_pri);
- btes_to_try[3] = bte_if_on_node(NASID_GET(dest), bte_sec);
+ nasid_to_try[1] = NASID_GET(dest);
} else {
- btes_to_try[2] = NULL;
- btes_to_try[3] = NULL;
+ nasid_to_try[1] = (int)NULL;
}
}
@@ -123,11 +129,12 @@ retry_bteop:
do {
local_irq_save(irq_flags);
- bte_if_index = 0;
+ bte_if_index = bte_first;
+ nasid_index = 0;
/* Attempt to lock one of the BTE interfaces. */
- while (bte_if_index < MAX_INTERFACES_TO_TRY) {
- bte = btes_to_try[bte_if_index++];
+ while (nasid_index < MAX_NODES_TO_TRY) {
+ bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index);
if (bte == NULL) {
continue;
@@ -143,6 +150,15 @@ retry_bteop:
break;
}
}
+
+ bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */
+ if (bte_if_index == bte_first) {
+ /*
+ * We've tried all interfaces on this node
+ */
+ nasid_index++;
+ }
+
bte = NULL;
}
@@ -169,7 +185,13 @@ retry_bteop:
/* Initialize the notification to a known value. */
*bte->most_rcnt_na = BTE_WORD_BUSY;
+ notif_phys_addr = TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na));
+ if (is_shub2()) {
+ src = SH2_TIO_PHYS_TO_DMA(src);
+ dest = SH2_TIO_PHYS_TO_DMA(dest);
+ notif_phys_addr = SH2_TIO_PHYS_TO_DMA(notif_phys_addr);
+ }
/* Set the source and destination registers */
BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src))));
BTE_SRC_STORE(bte, TO_PHYS(src));
@@ -177,14 +199,12 @@ retry_bteop:
BTE_DEST_STORE(bte, TO_PHYS(dest));
/* Set the notification register */
- BTE_PRINTKV(("IBNA = 0x%lx)\n",
- TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))));
- BTE_NOTIF_STORE(bte,
- TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)));
+ BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr));
+ BTE_NOTIF_STORE(bte, notif_phys_addr);
/* Initiate the transfer */
BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode)));
- BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode));
+ bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode));
itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec);
@@ -195,6 +215,7 @@ retry_bteop:
}
while ((transfer_stat = *bte->most_rcnt_na) == BTE_WORD_BUSY) {
+ cpu_relax();
if (ia64_get_itc() > itc_end) {
BTE_PRINTK(("BTE timeout nasid 0x%x bte%d IBLS = 0x%lx na 0x%lx\n",
NASID_GET(bte->bte_base_addr), bte->bte_num,
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index 5c39b43ba3c..5c5eb01c50f 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -76,7 +76,7 @@ void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
*/
REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
- udelay(1);
+ cpu_relax();
}
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 414cdf2e3c9..4564ed0b5ff 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -18,6 +18,7 @@
#include <asm/sn/simulator.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/tioca_provider.h>
+#include <asm/sn/tioce_provider.h>
#include "xtalk/hubdev.h"
#include "xtalk/xwidgetdev.h"
@@ -44,6 +45,9 @@ int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */
struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */
+static int max_segment_number = 0; /* Default highest segment number */
+static int max_pcibus_number = 255; /* Default highest pci bus number */
+
/*
* Hooks and struct for unsupported pci providers
*/
@@ -157,13 +161,28 @@ static void sn_fixup_ionodes(void)
uint64_t nasid;
int i, widget;
+ /*
+ * Get SGI Specific HUB chipset information.
+ * Inform Prom that this kernel can support domain bus numbering.
+ */
for (i = 0; i < numionodes; i++) {
hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
nasid = cnodeid_to_nasid(i);
+ hubdev->max_segment_number = 0xffffffff;
+ hubdev->max_pcibus_number = 0xff;
status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
if (status)
continue;
+ /* Save the largest Domain and pcibus numbers found. */
+ if (hubdev->max_segment_number) {
+ /*
+ * Dealing with a Prom that supports segments.
+ */
+ max_segment_number = hubdev->max_segment_number;
+ max_pcibus_number = hubdev->max_pcibus_number;
+ }
+
/* Attach the error interrupt handlers */
if (nasid & 1)
ice_error_init(hubdev);
@@ -230,7 +249,7 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
void sn_pci_fixup_slot(struct pci_dev *dev)
{
int idx;
- int segment = 0;
+ int segment = pci_domain_nr(dev->bus);
int status = 0;
struct pcibus_bussoft *bs;
struct pci_bus *host_pci_bus;
@@ -283,9 +302,9 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
* PCI host_pci_dev struct and set up host bus linkages
*/
- bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+ bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
- host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+ host_pci_bus = pci_find_bus(segment, bus_no);
host_pci_dev = pci_get_slot(host_pci_bus, devfn);
SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
@@ -333,6 +352,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
prom_bussoft_ptr = __va(prom_bussoft_ptr);
controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+ controller->segment = segment;
if (!controller)
BUG();
@@ -390,7 +410,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
if (controller->node >= num_online_nodes()) {
struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);
- printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%lu"
+ printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
"L_IO=%lx L_MEM=%lx BASE=%lx\n",
b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
@@ -445,6 +465,7 @@ sn_sysdata_free_start:
static int __init sn_pci_init(void)
{
int i = 0;
+ int j = 0;
struct pci_dev *pci_dev = NULL;
extern void sn_init_cpei_timer(void);
#ifdef CONFIG_PROC_FS
@@ -464,6 +485,7 @@ static int __init sn_pci_init(void)
pcibr_init_provider();
tioca_init_provider();
+ tioce_init_provider();
/*
* This is needed to avoid bounce limit checks in the blk layer
@@ -479,8 +501,9 @@ static int __init sn_pci_init(void)
#endif
/* busses are not known yet ... */
- for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
- sn_pci_controller_fixup(0, i, NULL);
+ for (i = 0; i <= max_segment_number; i++)
+ for (j = 0; j <= max_pcibus_number; j++)
+ sn_pci_controller_fixup(i, j, NULL);
/*
* Generic Linux PCI Layer has created the pci_bus and pci_dev
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 392bf8a072b..01d18b7b5bb 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*/
#include <linux/irq.h>
@@ -76,16 +76,14 @@ static void sn_enable_irq(unsigned int irq)
static void sn_ack_irq(unsigned int irq)
{
- uint64_t event_occurred, mask = 0;
- int nasid;
+ u64 event_occurred, mask = 0;
irq = irq & 0xff;
- nasid = get_nasid();
event_occurred =
- HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED));
+ HUB_L((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED));
mask = event_occurred & SH_ALL_INT_MASK;
- HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS),
- mask);
+ HUB_S((u64*)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
+ mask);
__set_bit(irq, (volatile void *)pda->sn_in_service_ivecs);
move_irq(irq);
@@ -93,15 +91,12 @@ static void sn_ack_irq(unsigned int irq)
static void sn_end_irq(unsigned int irq)
{
- int nasid;
int ivec;
- uint64_t event_occurred;
+ u64 event_occurred;
ivec = irq & 0xff;
if (ivec == SGI_UART_VECTOR) {
- nasid = get_nasid();
- event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
- (nasid, SH_EVENT_OCCURRED));
+ event_occurred = HUB_L((u64*)LOCAL_MMR_ADDR (SH_EVENT_OCCURRED));
/* If the UART bit is set here, we may have received an
* interrupt from the UART that the driver missed. To
* make sure, we IPI ourselves to force us to look again.
@@ -132,6 +127,7 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
int local_widget, status;
nasid_t local_nasid;
struct sn_irq_info *new_irq_info;
+ struct sn_pcibus_provider *pci_provider;
new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
if (new_irq_info == NULL)
@@ -171,8 +167,9 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
new_irq_info->irq_cpuid = cpuid;
register_intr_pda(new_irq_info);
- if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type))
- pcibr_change_devices_irq(new_irq_info);
+ pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+ if (pci_provider && pci_provider->target_interrupt)
+ (pci_provider->target_interrupt)(new_irq_info);
spin_lock(&sn_irq_info_lock);
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
@@ -317,6 +314,16 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
pci_dev_put(pci_dev);
}
+static inline void
+sn_call_force_intr_provider(struct sn_irq_info *sn_irq_info)
+{
+ struct sn_pcibus_provider *pci_provider;
+
+ pci_provider = sn_pci_provider[sn_irq_info->irq_bridge_type];
+ if (pci_provider && pci_provider->force_interrupt)
+ (*pci_provider->force_interrupt)(sn_irq_info);
+}
+
static void force_interrupt(int irq)
{
struct sn_irq_info *sn_irq_info;
@@ -325,11 +332,9 @@ static void force_interrupt(int irq)
return;
rcu_read_lock();
- list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) {
- if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL))
- pcibr_force_interrupt(sn_irq_info);
- }
+ list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list)
+ sn_call_force_intr_provider(sn_irq_info);
+
rcu_read_unlock();
}
@@ -351,6 +356,14 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
struct pcidev_info *pcidev_info;
struct pcibus_info *pcibus_info;
+ /*
+ * Bridge types attached to TIO (anything but PIC) do not need this WAR
+ * since they do not target Shub II interrupt registers. If that
+ * ever changes, this check needs to accomodate.
+ */
+ if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_PIC)
+ return;
+
pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
if (!pcidev_info)
return;
@@ -377,16 +390,12 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
break;
}
if (!test_bit(irr_bit, &irr_reg)) {
- if (!test_bit(irq, pda->sn_soft_irr)) {
- if (!test_bit(irq, pda->sn_in_service_ivecs)) {
- regval &= 0xff;
- if (sn_irq_info->irq_int_bit & regval &
- sn_irq_info->irq_last_intr) {
- regval &=
- ~(sn_irq_info->
- irq_int_bit & regval);
- pcibr_force_interrupt(sn_irq_info);
- }
+ if (!test_bit(irq, pda->sn_in_service_ivecs)) {
+ regval &= 0xff;
+ if (sn_irq_info->irq_int_bit & regval &
+ sn_irq_info->irq_last_intr) {
+ regval &= ~(sn_irq_info->irq_int_bit & regval);
+ sn_call_force_intr_provider(sn_irq_info);
}
}
}
@@ -404,13 +413,7 @@ void sn_lb_int_war_check(void)
rcu_read_lock();
for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
- /*
- * Only call for PCI bridges that are fully
- * initialized.
- */
- if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL))
- sn_check_intr(i, sn_irq_info);
+ sn_check_intr(i, sn_irq_info);
}
}
rcu_read_unlock();
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 7c7fe441d62..a594aca959e 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -80,8 +80,6 @@ EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
EXPORT_PER_CPU_SYMBOL(__sn_nodepda);
-partid_t sn_partid = -1;
-EXPORT_SYMBOL(sn_partid);
char sn_system_serial_number_string[128];
EXPORT_SYMBOL(sn_system_serial_number_string);
u64 sn_partition_serial_number;
@@ -403,6 +401,7 @@ static void __init sn_init_pdas(char **cmdline_p)
memset(nodepdaindr[cnode], 0, sizeof(nodepda_t));
memset(nodepdaindr[cnode]->phys_cpuid, -1,
sizeof(nodepdaindr[cnode]->phys_cpuid));
+ spin_lock_init(&nodepdaindr[cnode]->ptc_lock);
}
/*
@@ -532,8 +531,8 @@ void __init sn_cpu_init(void)
*/
{
u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
- u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
- SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3};
+ u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_2,
+ SH2_PIO_WRITE_STATUS_1, SH2_PIO_WRITE_STATUS_3};
u64 *pio;
pio = is_shub1() ? pio1 : pio2;
pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]);
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
index 96cb71d1568..3fa95065a44 100644
--- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
+++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <asm/types.h>
@@ -11,7 +11,7 @@
#define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
#define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK
-#define ALIAS_OFFSET (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0)
+#define ALIAS_OFFSET 8
.global sn2_ptc_deadlock_recovery_core
@@ -36,13 +36,15 @@ sn2_ptc_deadlock_recovery_core:
extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address
dep piowcphy=-1,piowcphy,63,1
movl mask=WRITECOUNTMASK
+ mov r8=r0
1:
add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register
- mov scr1=7;; // Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
- st8.rel [scr2]=scr1;;
+ ;;
+ ld8.acq scr1=[scr2];;
5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b
@@ -57,6 +59,7 @@ sn2_ptc_deadlock_recovery_core:
st8.rel [ptc0]=data0 // Write PTC0 & wait for completion.
5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b;;
@@ -67,6 +70,7 @@ sn2_ptc_deadlock_recovery_core:
(p7) st8.rel [ptc1]=data1;; // Now write PTC1.
5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete.
+ hint @pause
and scr2=scr1,mask;; // mask of writecount bits
cmp.ne p6,p0=zeroval,scr2
(p6) br.cond.sptk 5b
@@ -77,6 +81,7 @@ sn2_ptc_deadlock_recovery_core:
srlz.i;;
////////////// END PHYSICAL MODE ////////////////////
+(p8) add r8=1,r8
(p8) br.cond.spnt 1b;; // Repeat if DEADLOCK occurred.
br.ret.sptk rp
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index 7af05a7ac74..0a4ee50c302 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/init.h>
@@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/nodemask.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/processor.h>
#include <asm/irq.h>
@@ -39,12 +41,120 @@
#include <asm/sn/nodepda.h>
#include <asm/sn/rw_mmr.h>
-void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0,
- volatile unsigned long *, unsigned long data1);
+DEFINE_PER_CPU(struct ptc_stats, ptcstats);
+DECLARE_PER_CPU(struct ptc_stats, ptcstats);
static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
-static unsigned long sn2_ptc_deadlock_count;
+void sn2_ptc_deadlock_recovery(short *, short, int, volatile unsigned long *, unsigned long data0,
+ volatile unsigned long *, unsigned long data1);
+
+#ifdef DEBUG_PTC
+/*
+ * ptctest:
+ *
+ * xyz - 3 digit hex number:
+ * x - Force PTC purges to use shub:
+ * 0 - no force
+ * 1 - force
+ * y - interupt enable
+ * 0 - disable interrupts
+ * 1 - leave interuupts enabled
+ * z - type of lock:
+ * 0 - global lock
+ * 1 - node local lock
+ * 2 - no lock
+ *
+ * Note: on shub1, only ptctest == 0 is supported. Don't try other values!
+ */
+
+static unsigned int sn2_ptctest = 0;
+
+static int __init ptc_test(char *str)
+{
+ get_option(&str, &sn2_ptctest);
+ return 1;
+}
+__setup("ptctest=", ptc_test);
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+ unsigned long opt = sn2_ptctest & 255;
+
+ switch (opt) {
+ case 0x00:
+ spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+ break;
+ case 0x01:
+ spin_lock_irqsave(&sn_nodepda->ptc_lock, *flagp);
+ break;
+ case 0x02:
+ local_irq_save(*flagp);
+ break;
+ case 0x10:
+ spin_lock(&sn2_global_ptc_lock);
+ break;
+ case 0x11:
+ spin_lock(&sn_nodepda->ptc_lock);
+ break;
+ case 0x12:
+ break;
+ default:
+ BUG();
+ }
+ return opt;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+ switch (opt) {
+ case 0x00:
+ spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+ break;
+ case 0x01:
+ spin_unlock_irqrestore(&sn_nodepda->ptc_lock, flags);
+ break;
+ case 0x02:
+ local_irq_restore(flags);
+ break;
+ case 0x10:
+ spin_unlock(&sn2_global_ptc_lock);
+ break;
+ case 0x11:
+ spin_unlock(&sn_nodepda->ptc_lock);
+ break;
+ case 0x12:
+ break;
+ default:
+ BUG();
+ }
+}
+#else
+
+#define sn2_ptctest 0
+
+static inline int ptc_lock(unsigned long *flagp)
+{
+ spin_lock_irqsave(&sn2_global_ptc_lock, *flagp);
+ return 0;
+}
+
+static inline void ptc_unlock(unsigned long flags, int opt)
+{
+ spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+}
+#endif
+
+struct ptc_stats {
+ unsigned long ptc_l;
+ unsigned long change_rid;
+ unsigned long shub_ptc_flushes;
+ unsigned long nodes_flushed;
+ unsigned long deadlocks;
+ unsigned long lock_itc_clocks;
+ unsigned long shub_itc_clocks;
+ unsigned long shub_itc_clocks_max;
+};
static inline unsigned long wait_piowc(void)
{
@@ -89,9 +199,9 @@ void
sn2_global_tlb_purge(unsigned long start, unsigned long end,
unsigned long nbits)
{
- int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
+ int i, opt, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0;
volatile unsigned long *ptc0, *ptc1;
- unsigned long flags = 0, data0 = 0, data1 = 0;
+ unsigned long itc, itc2, flags, data0 = 0, data1 = 0;
struct mm_struct *mm = current->active_mm;
short nasids[MAX_NUMNODES], nix;
nodemask_t nodes_flushed;
@@ -114,16 +224,19 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
start += (1UL << nbits);
} while (start < end);
ia64_srlz_i();
+ __get_cpu_var(ptcstats).ptc_l++;
preempt_enable();
return;
}
if (atomic_read(&mm->mm_users) == 1) {
flush_tlb_mm(mm);
+ __get_cpu_var(ptcstats).change_rid++;
preempt_enable();
return;
}
+ itc = ia64_get_itc();
nix = 0;
for_each_node_mask(cnode, nodes_flushed)
nasids[nix++] = cnodeid_to_nasid(cnode);
@@ -148,7 +261,12 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
mynasid = get_nasid();
- spin_lock_irqsave(&sn2_global_ptc_lock, flags);
+ itc = ia64_get_itc();
+ opt = ptc_lock(&flags);
+ itc2 = ia64_get_itc();
+ __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc;
+ __get_cpu_var(ptcstats).shub_ptc_flushes++;
+ __get_cpu_var(ptcstats).nodes_flushed += nix;
do {
if (shub1)
@@ -157,7 +275,7 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK);
for (i = 0; i < nix; i++) {
nasid = nasids[i];
- if (unlikely(nasid == mynasid)) {
+ if ((!(sn2_ptctest & 3)) && unlikely(nasid == mynasid)) {
ia64_ptcga(start, nbits << 2);
ia64_srlz_i();
} else {
@@ -169,18 +287,22 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
flushed = 1;
}
}
-
if (flushed
&& (wait_piowc() &
- SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) {
- sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1);
+ (SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK))) {
+ sn2_ptc_deadlock_recovery(nasids, nix, mynasid, ptc0, data0, ptc1, data1);
}
start += (1UL << nbits);
} while (start < end);
- spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+ itc2 = ia64_get_itc() - itc2;
+ __get_cpu_var(ptcstats).shub_itc_clocks += itc2;
+ if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
+ __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2;
+
+ ptc_unlock(flags, opt);
preempt_enable();
}
@@ -192,31 +314,29 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end,
* TLB flush transaction. The recovery sequence is somewhat tricky & is
* coded in assembly language.
*/
-void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0,
+void sn2_ptc_deadlock_recovery(short *nasids, short nix, int mynasid, volatile unsigned long *ptc0, unsigned long data0,
volatile unsigned long *ptc1, unsigned long data1)
{
extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long);
- int cnode, mycnode, nasid;
- volatile unsigned long *piows;
- volatile unsigned long zeroval;
+ short nasid, i;
+ unsigned long *piows, zeroval;
- sn2_ptc_deadlock_count++;
+ __get_cpu_var(ptcstats).deadlocks++;
- piows = pda->pio_write_status_addr;
+ piows = (unsigned long *) pda->pio_write_status_addr;
zeroval = pda->pio_write_status_val;
- mycnode = numa_node_id();
-
- for_each_online_node(cnode) {
- if (is_headless_node(cnode) || cnode == mycnode)
+ for (i=0; i < nix; i++) {
+ nasid = nasids[i];
+ if (!(sn2_ptctest & 3) && nasid == mynasid)
continue;
- nasid = cnodeid_to_nasid(cnode);
ptc0 = CHANGE_NASID(nasid, ptc0);
if (ptc1)
ptc1 = CHANGE_NASID(nasid, ptc1);
sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval);
}
+
}
/**
@@ -293,3 +413,93 @@ void sn2_send_IPI(int cpuid, int vector, int delivery_mode, int redirect)
sn_send_IPI_phys(nasid, physid, vector, delivery_mode);
}
+
+#ifdef CONFIG_PROC_FS
+
+#define PTC_BASENAME "sgi_sn/ptc_statistics"
+
+static void *sn2_ptc_seq_start(struct seq_file *file, loff_t * offset)
+{
+ if (*offset < NR_CPUS)
+ return offset;
+ return NULL;
+}
+
+static void *sn2_ptc_seq_next(struct seq_file *file, void *data, loff_t * offset)
+{
+ (*offset)++;
+ if (*offset < NR_CPUS)
+ return offset;
+ return NULL;
+}
+
+static void sn2_ptc_seq_stop(struct seq_file *file, void *data)
+{
+}
+
+static int sn2_ptc_seq_show(struct seq_file *file, void *data)
+{
+ struct ptc_stats *stat;
+ int cpu;
+
+ cpu = *(loff_t *) data;
+
+ if (!cpu) {
+ seq_printf(file, "# ptc_l change_rid shub_ptc_flushes shub_nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max\n");
+ seq_printf(file, "# ptctest %d\n", sn2_ptctest);
+ }
+
+ if (cpu < NR_CPUS && cpu_online(cpu)) {
+ stat = &per_cpu(ptcstats, cpu);
+ seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
+ stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
+ stat->deadlocks,
+ 1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+ 1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
+ 1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec);
+ }
+
+ return 0;
+}
+
+static struct seq_operations sn2_ptc_seq_ops = {
+ .start = sn2_ptc_seq_start,
+ .next = sn2_ptc_seq_next,
+ .stop = sn2_ptc_seq_stop,
+ .show = sn2_ptc_seq_show
+};
+
+int sn2_ptc_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &sn2_ptc_seq_ops);
+}
+
+static struct file_operations proc_sn2_ptc_operations = {
+ .open = sn2_ptc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static struct proc_dir_entry *proc_sn2_ptc;
+
+static int __init sn2_ptc_init(void)
+{
+ if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) {
+ printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);
+ return -EINVAL;
+ }
+ proc_sn2_ptc->proc_fops = &proc_sn2_ptc_operations;
+ spin_lock_init(&sn2_global_ptc_lock);
+ return 0;
+}
+
+static void __exit sn2_ptc_exit(void)
+{
+ remove_proc_entry(PTC_BASENAME, NULL);
+}
+
+module_init(sn2_ptc_init);
+module_exit(sn2_ptc_exit);
+#endif /* CONFIG_PROC_FS */
+
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 833e700fdac..0513aacac8c 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -36,7 +36,6 @@
#include <asm/topology.h>
#include <asm/smp.h>
#include <asm/semaphore.h>
-#include <asm/segment.h>
#include <asm/uaccess.h>
#include <asm/sal.h>
#include <asm/sn/io.h>
@@ -59,7 +58,7 @@ static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret)
struct sn_hwperf_object_info *objbuf = NULL;
if ((e = sn_hwperf_init()) < 0) {
- printk("sn_hwperf_init failed: err %d\n", e);
+ printk(KERN_ERR "sn_hwperf_init failed: err %d\n", e);
goto out;
}
@@ -111,7 +110,7 @@ static int sn_hwperf_geoid_to_cnode(char *location)
if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))
return -1;
- for (cnode = 0; cnode < numionodes; cnode++) {
+ for_each_node(cnode) {
geoid = cnodeid_get_geoid(cnode);
module_id = geo_module(geoid);
this_rack = MODULE_GET_RACK(module_id);
@@ -124,11 +123,13 @@ static int sn_hwperf_geoid_to_cnode(char *location)
}
}
- return cnode < numionodes ? cnode : -1;
+ return node_possible(cnode) ? cnode : -1;
}
static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
{
+ if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
+ BUG();
if (!obj->sn_hwp_this_part)
return -1;
return sn_hwperf_geoid_to_cnode(obj->location);
@@ -174,31 +175,199 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj,
return slabname;
}
-static void print_pci_topology(struct seq_file *s,
- struct sn_hwperf_object_info *obj, int *ordinal,
- u64 rack, u64 bay, u64 slot, u64 slab)
+static void print_pci_topology(struct seq_file *s)
+{
+ char *p;
+ size_t sz;
+ int e;
+
+ for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
+ if (!(p = (char *)kmalloc(sz, GFP_KERNEL)))
+ break;
+ e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);
+ if (e == SALRET_OK)
+ seq_puts(s, p);
+ kfree(p);
+ if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED)
+ break;
+ }
+}
+
+static inline int sn_hwperf_has_cpus(cnodeid_t node)
+{
+ return node_online(node) && nr_cpus_node(node);
+}
+
+static inline int sn_hwperf_has_mem(cnodeid_t node)
+{
+ return node_online(node) && NODE_DATA(node)->node_present_pages;
+}
+
+static struct sn_hwperf_object_info *
+sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf,
+ int nobj, int id)
{
- char *p1;
- char *p2;
- char *pg;
-
- if (!(pg = (char *)get_zeroed_page(GFP_KERNEL)))
- return; /* ignore */
- if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab,
- __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) {
- for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) {
- if (!(p2 = strchr(p1, '\n')))
+ int i;
+ struct sn_hwperf_object_info *p = objbuf;
+
+ for (i=0; i < nobj; i++, p++) {
+ if (p->id == id)
+ return p;
+ }
+
+ return NULL;
+
+}
+
+static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf,
+ int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+ int e;
+ struct sn_hwperf_object_info *nodeobj = NULL;
+ struct sn_hwperf_object_info *op;
+ struct sn_hwperf_object_info *dest;
+ struct sn_hwperf_object_info *router;
+ struct sn_hwperf_port_info ptdata[16];
+ int sz, i, j;
+ cnodeid_t c;
+ int found_mem = 0;
+ int found_cpu = 0;
+
+ if (!node_possible(node))
+ return -EINVAL;
+
+ if (sn_hwperf_has_cpus(node)) {
+ if (near_cpu_node)
+ *near_cpu_node = node;
+ found_cpu++;
+ }
+
+ if (sn_hwperf_has_mem(node)) {
+ if (near_mem_node)
+ *near_mem_node = node;
+ found_mem++;
+ }
+
+ if (found_cpu && found_mem)
+ return 0; /* trivially successful */
+
+ /* find the argument node object */
+ for (i=0, op=objbuf; i < nobj; i++, op++) {
+ if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op))
+ continue;
+ if (node == sn_hwperf_obj_to_cnode(op)) {
+ nodeobj = op;
+ break;
+ }
+ }
+ if (!nodeobj) {
+ e = -ENOENT;
+ goto err;
+ }
+
+ /* get it's interconnect topology */
+ sz = op->ports * sizeof(struct sn_hwperf_port_info);
+ if (sz > sizeof(ptdata))
+ BUG();
+ e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+ SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,
+ (u64)&ptdata, 0, 0, NULL);
+ if (e != SN_HWPERF_OP_OK) {
+ e = -EINVAL;
+ goto err;
+ }
+
+ /* find nearest node with cpus and nearest memory */
+ for (router=NULL, j=0; j < op->ports; j++) {
+ dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id);
+ if (!dest || SN_HWPERF_FOREIGN(dest) ||
+ !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(dest);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (SN_HWPERF_IS_ROUTER(dest))
+ router = dest;
+ }
+
+ if (router && (!found_cpu || !found_mem)) {
+ /* search for a node connected to the same router */
+ sz = router->ports * sizeof(struct sn_hwperf_port_info);
+ if (sz > sizeof(ptdata))
+ BUG();
+ e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+ SN_HWPERF_ENUM_PORTS, router->id, sz,
+ (u64)&ptdata, 0, 0, NULL);
+ if (e != SN_HWPERF_OP_OK) {
+ e = -EINVAL;
+ goto err;
+ }
+ for (j=0; j < router->ports; j++) {
+ dest = sn_hwperf_findobj_id(objbuf, nobj,
+ ptdata[j].conn_id);
+ if (!dest || dest->id == node ||
+ SN_HWPERF_FOREIGN(dest) ||
+ !SN_HWPERF_IS_NODE(dest) ||
+ SN_HWPERF_IS_IONODE(dest)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(dest);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (found_cpu && found_mem)
+ break;
+ }
+ }
+
+ if (!found_cpu || !found_mem) {
+ /* resort to _any_ node with CPUs and memory */
+ for (i=0, op=objbuf; i < nobj; i++, op++) {
+ if (SN_HWPERF_FOREIGN(op) ||
+ SN_HWPERF_IS_IONODE(op) ||
+ !SN_HWPERF_IS_NODE(op)) {
+ continue;
+ }
+ c = sn_hwperf_obj_to_cnode(op);
+ if (!found_cpu && sn_hwperf_has_cpus(c)) {
+ if (near_cpu_node)
+ *near_cpu_node = c;
+ found_cpu++;
+ }
+ if (!found_mem && sn_hwperf_has_mem(c)) {
+ if (near_mem_node)
+ *near_mem_node = c;
+ found_mem++;
+ }
+ if (found_cpu && found_mem)
break;
- *p2 = '\0';
- seq_printf(s, "pcibus %d %s-%s\n",
- *ordinal, obj->location, p1);
- (*ordinal)++;
- p1 = p2 + 1;
}
}
- free_page((unsigned long)pg);
+
+ if (!found_cpu || !found_mem)
+ e = -ENODATA;
+
+err:
+ return e;
}
+
static int sn_topology_show(struct seq_file *s, void *d)
{
int sz;
@@ -215,7 +384,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
struct sn_hwperf_object_info *p;
struct sn_hwperf_object_info *obj = d; /* this object */
struct sn_hwperf_object_info *objs = s->private; /* all objects */
- int rack, bay, slot, slab;
u8 shubtype;
u8 system_size;
u8 sharing_size;
@@ -225,7 +393,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
u8 region_size;
u16 nasid_mask;
int nasid_msb;
- int pci_bus_ordinal = 0;
if (obj == objs) {
seq_printf(s, "# sn_topology version 2\n");
@@ -253,6 +420,8 @@ static int sn_topology_show(struct seq_file *s, void *d)
shubtype ? "shub2" : "shub1",
(u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
system_size, sharing_size, coher, region_size);
+
+ print_pci_topology(s);
}
if (SN_HWPERF_FOREIGN(obj)) {
@@ -272,11 +441,24 @@ static int sn_topology_show(struct seq_file *s, void *d)
if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))
seq_putc(s, '\n');
else {
+ cnodeid_t near_mem = -1;
+ cnodeid_t near_cpu = -1;
+
seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
- for (i=0; i < numionodes; i++) {
- seq_printf(s, i ? ":%d" : ", dist %d",
- node_distance(ordinal, i));
+
+ if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt,
+ ordinal, &near_mem, &near_cpu) == 0) {
+ seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d",
+ near_mem, near_cpu);
+ }
+
+ if (!SN_HWPERF_IS_IONODE(obj)) {
+ for_each_online_node(i) {
+ seq_printf(s, i ? ":%d" : ", dist %d",
+ node_distance(ordinal, i));
+ }
}
+
seq_putc(s, '\n');
/*
@@ -300,17 +482,6 @@ static int sn_topology_show(struct seq_file *s, void *d)
seq_putc(s, '\n');
}
}
-
- /*
- * PCI busses attached to this node, if any
- */
- if (sn_hwperf_location_to_bpos(obj->location,
- &rack, &bay, &slot, &slab)) {
- /* export pci bus info */
- print_pci_topology(s, obj, &pci_bus_ordinal,
- rack, bay, slot, slab);
-
- }
}
if (obj->ports) {
@@ -572,6 +743,8 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
memset(p, 0, a.sz);
for (i = 0; i < nobj; i++) {
+ if (!SN_HWPERF_IS_NODE(objs + i))
+ continue;
node = sn_hwperf_obj_to_cnode(objs + i);
for_each_online_cpu(j) {
if (node != cpu_to_node(j))
@@ -598,7 +771,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
case SN_HWPERF_GET_NODE_NASID:
if (a.sz != sizeof(u64) ||
- (node = a.arg) < 0 || node >= numionodes) {
+ (node = a.arg) < 0 || !node_possible(node)) {
r = -EINVAL;
goto error;
}
@@ -627,6 +800,14 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
vfree(objs);
goto error;
}
+
+ if (!SN_HWPERF_IS_NODE(objs + i) &&
+ !SN_HWPERF_IS_IONODE(objs + i)) {
+ r = -ENOENT;
+ vfree(objs);
+ goto error;
+ }
+
*(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);
vfree(objs);
}
@@ -692,6 +873,7 @@ static int sn_hwperf_init(void)
/* single threaded, once-only initialization */
down(&sn_hwperf_init_mutex);
+
if (sn_hwperf_salheap) {
up(&sn_hwperf_init_mutex);
return e;
@@ -742,19 +924,6 @@ out:
sn_hwperf_salheap = NULL;
sn_hwperf_obj_cnt = 0;
}
-
- if (!e) {
- /*
- * Register a dynamic misc device for ioctl. Platforms
- * supporting hotplug will create /dev/sn_hwperf, else
- * user can to look up the minor number in /proc/misc.
- */
- if ((e = misc_register(&sn_hwperf_dev)) != 0) {
- printk(KERN_ERR "sn_hwperf_init: misc register "
- "for \"sn_hwperf\" failed, err %d\n", e);
- }
- }
-
up(&sn_hwperf_init_mutex);
return e;
}
@@ -782,3 +951,41 @@ int sn_topology_release(struct inode *inode, struct file *file)
vfree(seq->private);
return seq_release(inode, file);
}
+
+int sn_hwperf_get_nearest_node(cnodeid_t node,
+ cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node)
+{
+ int e;
+ int nobj;
+ struct sn_hwperf_object_info *objbuf;
+
+ if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
+ e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj,
+ node, near_mem_node, near_cpu_node);
+ vfree(objbuf);
+ }
+
+ return e;
+}
+
+static int __devinit sn_hwperf_misc_register_init(void)
+{
+ int e;
+
+ sn_hwperf_init();
+
+ /*
+ * Register a dynamic misc device for hwperf ioctls. Platforms
+ * supporting hotplug will create /dev/sn_hwperf, else user
+ * can to look up the minor number in /proc/misc.
+ */
+ if ((e = misc_register(&sn_hwperf_dev)) != 0) {
+ printk(KERN_ERR "sn_hwperf_misc_register_init: failed to "
+ "register misc device for \"%s\"\n", sn_hwperf_dev.name);
+ }
+
+ return e;
+}
+
+device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */
+EXPORT_SYMBOL(sn_hwperf_get_nearest_node);
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
index 266a3a84c01..a06719d752a 100644
--- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
+++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/config.h>
#include <asm/uaccess.h>
@@ -15,7 +15,7 @@
static int partition_id_show(struct seq_file *s, void *p)
{
- seq_printf(s, "%d\n", sn_local_partid());
+ seq_printf(s, "%d\n", sn_partition_id);
return 0;
}
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
index cde7375390b..adf5db2e2af 100644
--- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c
+++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
@@ -1,7 +1,7 @@
/*
*
*
- * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -50,14 +50,16 @@ void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
LED_CPU_HEARTBEAT, LED_CPU_HEARTBEAT);
}
- if (enable_shub_wars_1_1()) {
- /* Bugfix code for SHUB 1.1 */
- if (pda->pio_shub_war_cam_addr)
- *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+ if (is_shub1()) {
+ if (enable_shub_wars_1_1()) {
+ /* Bugfix code for SHUB 1.1 */
+ if (pda->pio_shub_war_cam_addr)
+ *pda->pio_shub_war_cam_addr = 0x8000000000000010UL;
+ }
+ if (pda->sn_lb_int_war_ticks == 0)
+ sn_lb_int_war_check();
+ pda->sn_lb_int_war_ticks++;
+ if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
+ pda->sn_lb_int_war_ticks = 0;
}
- if (pda->sn_lb_int_war_ticks == 0)
- sn_lb_int_war_check();
- pda->sn_lb_int_war_ticks++;
- if (pda->sn_lb_int_war_ticks >= SN_LB_INT_WAR_INTERVAL)
- pda->sn_lb_int_war_ticks = 0;
}
diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile
index 2f915bce25f..321576b1b42 100644
--- a/arch/ia64/sn/pci/Makefile
+++ b/arch/ia64/sn/pci/Makefile
@@ -7,4 +7,4 @@
#
# Makefile for the sn pci general routines.
-obj-y := pci_dma.o tioca_provider.o pcibr/
+obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index b058dc2a0b9..34093476e96 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -215,8 +215,8 @@ void sn_dma_flush(uint64_t addr)
int is_tio;
int wid_num;
int i, j;
- int bwin;
uint64_t flags;
+ uint64_t itte;
struct hubdev_info *hubinfo;
volatile struct sn_flush_device_list *p;
struct sn_flush_nasid_entry *flush_nasid_list;
@@ -233,31 +233,36 @@ void sn_dma_flush(uint64_t addr)
if (!hubinfo) {
BUG();
}
- is_tio = (nasid & 1);
- if (is_tio) {
- wid_num = TIO_SWIN_WIDGETNUM(addr);
- bwin = TIO_BWIN_WINDOWNUM(addr);
- } else {
- wid_num = SWIN_WIDGETNUM(addr);
- bwin = BWIN_WINDOWNUM(addr);
- }
flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
if (flush_nasid_list->widget_p == NULL)
return;
- if (bwin > 0) {
- uint64_t itte = flush_nasid_list->iio_itte[bwin];
- if (is_tio) {
- wid_num = (itte >> TIO_ITTE_WIDGET_SHIFT) &
- TIO_ITTE_WIDGET_MASK;
- } else {
- wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) &
- IIO_ITTE_WIDGET_MASK;
- }
+ is_tio = (nasid & 1);
+ if (is_tio) {
+ int itte_index;
+
+ if (TIO_HWIN(addr))
+ itte_index = 0;
+ else if (TIO_BWIN_WINDOWNUM(addr))
+ itte_index = TIO_BWIN_WINDOWNUM(addr);
+ else
+ itte_index = -1;
+
+ if (itte_index >= 0) {
+ itte = flush_nasid_list->iio_itte[itte_index];
+ if (! TIO_ITTE_VALID(itte))
+ return;
+ wid_num = TIO_ITTE_WIDGET(itte);
+ } else
+ wid_num = TIO_SWIN_WIDGETNUM(addr);
+ } else {
+ if (BWIN_WINDOWNUM(addr)) {
+ itte = flush_nasid_list->iio_itte[BWIN_WINDOWNUM(addr)];
+ wid_num = IIO_ITTE_WIDGET(itte);
+ } else
+ wid_num = SWIN_WIDGETNUM(addr);
}
- if (flush_nasid_list->widget_p == NULL)
- return;
if (flush_nasid_list->widget_p[wid_num] == NULL)
return;
p = &flush_nasid_list->widget_p[wid_num][0];
@@ -283,10 +288,16 @@ void sn_dma_flush(uint64_t addr)
/*
* For TIOCP use the Device(x) Write Request Buffer Flush Bridge
* register since it ensures the data has entered the coherence
- * domain, unlike PIC
+ * domain, unlike PIC.
*/
if (is_tio) {
- uint32_t tio_id = REMOTE_HUB_L(nasid, TIO_NODE_ID);
+ /*
+ * Note: devices behind TIOCE should never be matched in the
+ * above code, and so the following code is PIC/CP centric.
+ * If CE ever needs the sn_dma_flush mechanism, we will have
+ * to account for that here and in tioce_bus_fixup().
+ */
+ uint32_t tio_id = HUB_L(TIO_IOSPACE_ADDR(nasid, TIO_NODE_ID));
uint32_t revnum = XWIDGET_PART_REV_NUM(tio_id);
/* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */
@@ -306,7 +317,8 @@ void sn_dma_flush(uint64_t addr)
*(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
/* wait for the interrupt to come back. */
- while (*(p->sfdl_flush_addr) != 0x10f) ;
+ while (*(p->sfdl_flush_addr) != 0x10f)
+ cpu_relax();
/* okay, everything is synched up. */
spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index b95e928636a..7b03b8084ff 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -15,6 +15,7 @@
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn2/sn_hwperf.h>
#include "xtalk/xwidgetdev.h"
#include "xtalk/hubdev.h"
@@ -60,7 +61,7 @@ static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
ret_stuff.status = 0;
ret_stuff.v0 = 0;
- segment = 0;
+ segment = soft->pbi_buscommon.bs_persist_segment;
busnum = soft->pbi_buscommon.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff,
(u64) SN_SAL_IOIF_ERROR_INTERRUPT,
@@ -88,6 +89,7 @@ void *
pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
{
int nasid, cnode, j;
+ cnodeid_t near_cnode;
struct hubdev_info *hubdev_info;
struct pcibus_info *soft;
struct sn_flush_device_list *sn_flush_device_list;
@@ -115,7 +117,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
/*
* register the bridge's error interrupt handler
*/
- if (request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler,
+ if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler,
SA_SHIRQ, "PCIBR error", (void *)(soft))) {
printk(KERN_WARNING
"pcibr cannot allocate interrupt for error handler\n");
@@ -142,9 +144,12 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
j++, sn_flush_device_list++) {
if (sn_flush_device_list->sfdl_slot == -1)
continue;
- if (sn_flush_device_list->
- sfdl_persistent_busnum ==
- soft->pbi_buscommon.bs_persist_busnum)
+ if ((sn_flush_device_list->
+ sfdl_persistent_segment ==
+ soft->pbi_buscommon.bs_persist_segment) &&
+ (sn_flush_device_list->
+ sfdl_persistent_busnum ==
+ soft->pbi_buscommon.bs_persist_busnum))
sn_flush_device_list->sfdl_pcibus_info =
soft;
}
@@ -158,12 +163,18 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
memset(soft->pbi_int_ate_resource.ate, 0,
(soft->pbi_int_ate_size * sizeof(uint64_t)));
- if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP)
- /*
- * TIO PCI Bridge with no closest node information.
- * FIXME: Find another way to determine the closest node
- */
- controller->node = -1;
+ if (prom_bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) {
+ /* TIO PCI Bridge: find nearest node with CPUs */
+ int e = sn_hwperf_get_nearest_node(cnode, NULL, &near_cnode);
+
+ if (e < 0) {
+ near_cnode = (cnodeid_t)-1; /* use any node */
+ printk(KERN_WARNING "pcibr_bus_fixup: failed to find "
+ "near node with CPUs to TIO node %d, err=%d\n",
+ cnode, e);
+ }
+ controller->node = near_cnode;
+ }
else
controller->node = cnode;
return soft;
@@ -175,6 +186,9 @@ void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
struct pcibus_info *pcibus_info;
int bit = sn_irq_info->irq_int_bit;
+ if (! sn_irq_info->irq_bridge)
+ return;
+
pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
if (pcidev_info) {
pcibus_info =
@@ -184,7 +198,7 @@ void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
}
}
-void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info)
+void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)
{
struct pcidev_info *pcidev_info;
struct pcibus_info *pcibus_info;
@@ -219,6 +233,8 @@ struct sn_pcibus_provider pcibr_provider = {
.dma_map_consistent = pcibr_dma_map_consistent,
.dma_unmap = pcibr_dma_unmap,
.bus_fixup = pcibr_bus_fixup,
+ .force_interrupt = pcibr_force_interrupt,
+ .target_interrupt = pcibr_target_interrupt
};
int
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index 5d76a758146..ea09c12f025 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -559,7 +559,7 @@ tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
ret_stuff.status = 0;
ret_stuff.v0 = 0;
- segment = 0;
+ segment = soft->ca_common.bs_persist_segment;
busnum = soft->ca_common.bs_persist_busnum;
SAL_CALL_NOLOCK(ret_stuff,
@@ -622,7 +622,8 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
nasid_to_cnodeid(tioca_common->ca_closest_nasid);
tioca_common->ca_kernel_private = (uint64_t) tioca_kern;
- bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum);
+ bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment,
+ tioca_common->ca_common.bs_persist_busnum);
BUG_ON(!bus);
tioca_kern->ca_devices = &bus->devices;
@@ -656,6 +657,8 @@ static struct sn_pcibus_provider tioca_pci_interfaces = {
.dma_map_consistent = tioca_dma_map,
.dma_unmap = tioca_dma_unmap,
.bus_fixup = tioca_bus_fixup,
+ .force_interrupt = NULL,
+ .target_interrupt = NULL
};
/**
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
new file mode 100644
index 00000000000..8e75db2b825
--- /dev/null
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -0,0 +1,771 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/tioce_provider.h>
+
+/**
+ * Bus address ranges for the 5 flavors of TIOCE DMA
+ */
+
+#define TIOCE_D64_MIN 0x8000000000000000UL
+#define TIOCE_D64_MAX 0xffffffffffffffffUL
+#define TIOCE_D64_ADDR(a) ((a) >= TIOCE_D64_MIN)
+
+#define TIOCE_D32_MIN 0x0000000080000000UL
+#define TIOCE_D32_MAX 0x00000000ffffffffUL
+#define TIOCE_D32_ADDR(a) ((a) >= TIOCE_D32_MIN && (a) <= TIOCE_D32_MAX)
+
+#define TIOCE_M32_MIN 0x0000000000000000UL
+#define TIOCE_M32_MAX 0x000000007fffffffUL
+#define TIOCE_M32_ADDR(a) ((a) >= TIOCE_M32_MIN && (a) <= TIOCE_M32_MAX)
+
+#define TIOCE_M40_MIN 0x0000004000000000UL
+#define TIOCE_M40_MAX 0x0000007fffffffffUL
+#define TIOCE_M40_ADDR(a) ((a) >= TIOCE_M40_MIN && (a) <= TIOCE_M40_MAX)
+
+#define TIOCE_M40S_MIN 0x0000008000000000UL
+#define TIOCE_M40S_MAX 0x000000ffffffffffUL
+#define TIOCE_M40S_ADDR(a) ((a) >= TIOCE_M40S_MIN && (a) <= TIOCE_M40S_MAX)
+
+/*
+ * ATE manipulation macros.
+ */
+
+#define ATE_PAGESHIFT(ps) (__ffs(ps))
+#define ATE_PAGEMASK(ps) ((ps)-1)
+
+#define ATE_PAGE(x, ps) ((x) >> ATE_PAGESHIFT(ps))
+#define ATE_NPAGES(start, len, pagesize) \
+ (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
+
+#define ATE_VALID(ate) ((ate) & (1UL << 63))
+#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
+
+/*
+ * Flavors of ate-based mapping supported by tioce_alloc_map()
+ */
+
+#define TIOCE_ATE_M32 1
+#define TIOCE_ATE_M40 2
+#define TIOCE_ATE_M40S 3
+
+#define KB(x) ((x) << 10)
+#define MB(x) ((x) << 20)
+#define GB(x) ((x) << 30)
+
+/**
+ * tioce_dma_d64 - create a DMA mapping using 64-bit direct mode
+ * @ct_addr: system coretalk address
+ *
+ * Map @ct_addr into 64-bit CE bus space. No device context is necessary
+ * and no CE mapping are consumed.
+ *
+ * Bits 53:0 come from the coretalk address. The remaining bits are set as
+ * follows:
+ *
+ * 63 - must be 1 to indicate d64 mode to CE hardware
+ * 62 - barrier bit ... controlled with tioce_dma_barrier()
+ * 61 - 0 since this is not an MSI transaction
+ * 60:54 - reserved, MBZ
+ */
+static uint64_t
+tioce_dma_d64(unsigned long ct_addr)
+{
+ uint64_t bus_addr;
+
+ bus_addr = ct_addr | (1UL << 63);
+
+ return bus_addr;
+}
+
+/**
+ * pcidev_to_tioce - return misc ce related pointers given a pci_dev
+ * @pci_dev: pci device context
+ * @base: ptr to store struct tioce_mmr * for the CE holding this device
+ * @kernel: ptr to store struct tioce_kernel * for the CE holding this device
+ * @port: ptr to store the CE port number that this device is on
+ *
+ * Return pointers to various CE-related structures for the CE upstream of
+ * @pci_dev.
+ */
+static inline void
+pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
+ struct tioce_kernel **kernel, int *port)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce_kernel *ce_kernel;
+
+ pcidev_info = SN_PCIDEV_INFO(pdev);
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
+
+ if (base)
+ *base = (struct tioce *)ce_common->ce_pcibus.bs_base;
+ if (kernel)
+ *kernel = ce_kernel;
+
+ /*
+ * we use port as a zero-based value internally, even though the
+ * documentation is 1-based.
+ */
+ if (port)
+ *port =
+ (pdev->bus->number < ce_kernel->ce_port1_secondary) ? 0 : 1;
+}
+
+/**
+ * tioce_alloc_map - Given a coretalk address, map it to pcie bus address
+ * space using one of the various ATE-based address modes.
+ * @ce_kern: tioce context
+ * @type: map mode to use
+ * @port: 0-based port that the requesting device is downstream of
+ * @ct_addr: the coretalk address to map
+ * @len: number of bytes to map
+ *
+ * Given the addressing type, set up various paramaters that define the
+ * ATE pool to use. Search for a contiguous block of entries to cover the
+ * length, and if enough resources exist, fill in the ATE's and construct a
+ * tioce_dmamap struct to track the mapping.
+ */
+static uint64_t
+tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
+ uint64_t ct_addr, int len)
+{
+ int i;
+ int j;
+ int first;
+ int last;
+ int entries;
+ int nates;
+ int pagesize;
+ uint64_t *ate_shadow;
+ uint64_t *ate_reg;
+ uint64_t addr;
+ struct tioce *ce_mmr;
+ uint64_t bus_base;
+ struct tioce_dmamap *map;
+
+ ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
+
+ switch (type) {
+ case TIOCE_ATE_M32:
+ /*
+ * The first 64 entries of the ate3240 pool are dedicated to
+ * super-page (TIOCE_ATE_M40S) mode.
+ */
+ first = 64;
+ entries = TIOCE_NUM_M3240_ATES - 64;
+ ate_shadow = ce_kern->ce_ate3240_shadow;
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = ce_kern->ce_ate3240_pagesize;
+ bus_base = TIOCE_M32_MIN;
+ break;
+ case TIOCE_ATE_M40:
+ first = 0;
+ entries = TIOCE_NUM_M40_ATES;
+ ate_shadow = ce_kern->ce_ate40_shadow;
+ ate_reg = ce_mmr->ce_ure_ate40;
+ pagesize = MB(64);
+ bus_base = TIOCE_M40_MIN;
+ break;
+ case TIOCE_ATE_M40S:
+ /*
+ * ate3240 entries 0-31 are dedicated to port1 super-page
+ * mappings. ate3240 entries 32-63 are dedicated to port2.
+ */
+ first = port * 32;
+ entries = 32;
+ ate_shadow = ce_kern->ce_ate3240_shadow;
+ ate_reg = ce_mmr->ce_ure_ate3240;
+ pagesize = GB(16);
+ bus_base = TIOCE_M40S_MIN;
+ break;
+ default:
+ return 0;
+ }
+
+ nates = ATE_NPAGES(ct_addr, len, pagesize);
+ if (nates > entries)
+ return 0;
+
+ last = first + entries - nates;
+ for (i = first; i <= last; i++) {
+ if (ATE_VALID(ate_shadow[i]))
+ continue;
+
+ for (j = i; j < i + nates; j++)
+ if (ATE_VALID(ate_shadow[j]))
+ break;
+
+ if (j >= i + nates)
+ break;
+ }
+
+ if (i > last)
+ return 0;
+
+ map = kcalloc(1, sizeof(struct tioce_dmamap), GFP_ATOMIC);
+ if (!map)
+ return 0;
+
+ addr = ct_addr;
+ for (j = 0; j < nates; j++) {
+ uint64_t ate;
+
+ ate = ATE_MAKE(addr, pagesize);
+ ate_shadow[i + j] = ate;
+ ate_reg[i + j] = ate;
+ addr += pagesize;
+ }
+
+ map->refcnt = 1;
+ map->nbytes = nates * pagesize;
+ map->ct_start = ct_addr & ~ATE_PAGEMASK(pagesize);
+ map->pci_start = bus_base + (i * pagesize);
+ map->ate_hw = &ate_reg[i];
+ map->ate_shadow = &ate_shadow[i];
+ map->ate_count = nates;
+
+ list_add(&map->ce_dmamap_list, &ce_kern->ce_dmamap_list);
+
+ return (map->pci_start + (ct_addr - map->ct_start));
+}
+
+/**
+ * tioce_dma_d32 - create a DMA mapping using 32-bit direct mode
+ * @pdev: linux pci_dev representing the function
+ * @paddr: system physical address
+ *
+ * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
+ */
+static uint64_t
+tioce_dma_d32(struct pci_dev *pdev, uint64_t ct_addr)
+{
+ int dma_ok;
+ int port;
+ struct tioce *ce_mmr;
+ struct tioce_kernel *ce_kern;
+ uint64_t ct_upper;
+ uint64_t ct_lower;
+ dma_addr_t bus_addr;
+
+ ct_upper = ct_addr & ~0x3fffffffUL;
+ ct_lower = ct_addr & 0x3fffffffUL;
+
+ pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+ if (ce_kern->ce_port[port].dirmap_refcnt == 0) {
+ volatile uint64_t tmp;
+
+ ce_kern->ce_port[port].dirmap_shadow = ct_upper;
+ ce_mmr->ce_ure_dir_map[port] = ct_upper;
+ tmp = ce_mmr->ce_ure_dir_map[port];
+ dma_ok = 1;
+ } else
+ dma_ok = (ce_kern->ce_port[port].dirmap_shadow == ct_upper);
+
+ if (dma_ok) {
+ ce_kern->ce_port[port].dirmap_refcnt++;
+ bus_addr = TIOCE_D32_MIN + ct_lower;
+ } else
+ bus_addr = 0;
+
+ return bus_addr;
+}
+
+/**
+ * tioce_dma_barrier - swizzle a TIOCE bus address to include or exclude
+ * the barrier bit.
+ * @bus_addr: bus address to swizzle
+ *
+ * Given a TIOCE bus address, set the appropriate bit to indicate barrier
+ * attributes.
+ */
+static uint64_t
+tioce_dma_barrier(uint64_t bus_addr, int on)
+{
+ uint64_t barrier_bit;
+
+ /* barrier not supported in M40/M40S mode */
+ if (TIOCE_M40_ADDR(bus_addr) || TIOCE_M40S_ADDR(bus_addr))
+ return bus_addr;
+
+ if (TIOCE_D64_ADDR(bus_addr))
+ barrier_bit = (1UL << 62);
+ else /* must be m32 or d32 */
+ barrier_bit = (1UL << 30);
+
+ return (on) ? (bus_addr | barrier_bit) : (bus_addr & ~barrier_bit);
+}
+
+/**
+ * tioce_dma_unmap - release CE mapping resources
+ * @pdev: linux pci_dev representing the function
+ * @bus_addr: bus address returned by an earlier tioce_dma_map
+ * @dir: mapping direction (unused)
+ *
+ * Locate mapping resources associated with @bus_addr and release them.
+ * For mappings created using the direct modes there are no resources
+ * to release.
+ */
+void
+tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
+{
+ int i;
+ int port;
+ struct tioce_kernel *ce_kern;
+ struct tioce *ce_mmr;
+ unsigned long flags;
+
+ bus_addr = tioce_dma_barrier(bus_addr, 0);
+ pcidev_to_tioce(pdev, &ce_mmr, &ce_kern, &port);
+
+ /* nothing to do for D64 */
+
+ if (TIOCE_D64_ADDR(bus_addr))
+ return;
+
+ spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+ if (TIOCE_D32_ADDR(bus_addr)) {
+ if (--ce_kern->ce_port[port].dirmap_refcnt == 0) {
+ ce_kern->ce_port[port].dirmap_shadow = 0;
+ ce_mmr->ce_ure_dir_map[port] = 0;
+ }
+ } else {
+ struct tioce_dmamap *map;
+
+ list_for_each_entry(map, &ce_kern->ce_dmamap_list,
+ ce_dmamap_list) {
+ uint64_t last;
+
+ last = map->pci_start + map->nbytes - 1;
+ if (bus_addr >= map->pci_start && bus_addr <= last)
+ break;
+ }
+
+ if (&map->ce_dmamap_list == &ce_kern->ce_dmamap_list) {
+ printk(KERN_WARNING
+ "%s: %s - no map found for bus_addr 0x%lx\n",
+ __FUNCTION__, pci_name(pdev), bus_addr);
+ } else if (--map->refcnt == 0) {
+ for (i = 0; i < map->ate_count; i++) {
+ map->ate_shadow[i] = 0;
+ map->ate_hw[i] = 0;
+ }
+
+ list_del(&map->ce_dmamap_list);
+ kfree(map);
+ }
+ }
+
+ spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+}
+
+/**
+ * tioce_do_dma_map - map pages for PCI DMA
+ * @pdev: linux pci_dev representing the function
+ * @paddr: host physical address to map
+ * @byte_count: bytes to map
+ *
+ * This is the main wrapper for mapping host physical pages to CE PCI space.
+ * The mapping mode used is based on the device's dma_mask.
+ */
+static uint64_t
+tioce_do_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count,
+ int barrier)
+{
+ unsigned long flags;
+ uint64_t ct_addr;
+ uint64_t mapaddr = 0;
+ struct tioce_kernel *ce_kern;
+ struct tioce_dmamap *map;
+ int port;
+ uint64_t dma_mask;
+
+ dma_mask = (barrier) ? pdev->dev.coherent_dma_mask : pdev->dma_mask;
+
+ /* cards must be able to address at least 31 bits */
+ if (dma_mask < 0x7fffffffUL)
+ return 0;
+
+ ct_addr = PHYS_TO_TIODMA(paddr);
+
+ /*
+ * If the device can generate 64 bit addresses, create a D64 map.
+ * Since this should never fail, bypass the rest of the checks.
+ */
+ if (dma_mask == ~0UL) {
+ mapaddr = tioce_dma_d64(ct_addr);
+ goto dma_map_done;
+ }
+
+ pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
+
+ spin_lock_irqsave(&ce_kern->ce_lock, flags);
+
+ /*
+ * D64 didn't work ... See if we have an existing map that covers
+ * this address range. Must account for devices dma_mask here since
+ * an existing map might have been done in a mode using more pci
+ * address bits than this device can support.
+ */
+ list_for_each_entry(map, &ce_kern->ce_dmamap_list, ce_dmamap_list) {
+ uint64_t last;
+
+ last = map->ct_start + map->nbytes - 1;
+ if (ct_addr >= map->ct_start &&
+ ct_addr + byte_count - 1 <= last &&
+ map->pci_start <= dma_mask) {
+ map->refcnt++;
+ mapaddr = map->pci_start + (ct_addr - map->ct_start);
+ break;
+ }
+ }
+
+ /*
+ * If we don't have a map yet, and the card can generate 40
+ * bit addresses, try the M40/M40S modes. Note these modes do not
+ * support a barrier bit, so if we need a consistent map these
+ * won't work.
+ */
+ if (!mapaddr && !barrier && dma_mask >= 0xffffffffffUL) {
+ /*
+ * We have two options for 40-bit mappings: 16GB "super" ATE's
+ * and 64MB "regular" ATE's. We'll try both if needed for a
+ * given mapping but which one we try first depends on the
+ * size. For requests >64MB, prefer to use a super page with
+ * regular as the fallback. Otherwise, try in the reverse order.
+ */
+
+ if (byte_count > MB(64)) {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+ port, ct_addr, byte_count);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+ ct_addr, byte_count);
+ } else {
+ mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
+ ct_addr, byte_count);
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
+ port, ct_addr, byte_count);
+ }
+ }
+
+ /*
+ * 32-bit direct is the next mode to try
+ */
+ if (!mapaddr && dma_mask >= 0xffffffffUL)
+ mapaddr = tioce_dma_d32(pdev, ct_addr);
+
+ /*
+ * Last resort, try 32-bit ATE-based map.
+ */
+ if (!mapaddr)
+ mapaddr =
+ tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
+ byte_count);
+
+ spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
+
+dma_map_done:
+ if (mapaddr & barrier)
+ mapaddr = tioce_dma_barrier(mapaddr, 1);
+
+ return mapaddr;
+}
+
+/**
+ * tioce_dma - standard pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit clear
+ * in the address.
+ */
+static uint64_t
+tioce_dma(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+ return tioce_do_dma_map(pdev, paddr, byte_count, 0);
+}
+
+/**
+ * tioce_dma_consistent - consistent pci dma map interface
+ * @pdev: pci device requesting the map
+ * @paddr: system physical address to map into pci space
+ * @byte_count: # bytes to map
+ *
+ * Simply call tioce_do_dma_map() to create a map with the barrier bit set
+ * in the address.
+ */ static uint64_t
+tioce_dma_consistent(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
+{
+ return tioce_do_dma_map(pdev, paddr, byte_count, 1);
+}
+
+/**
+ * tioce_error_intr_handler - SGI TIO CE error interrupt handler
+ * @irq: unused
+ * @arg: pointer to tioce_common struct for the given CE
+ * @pt: unused
+ *
+ * Handle a CE error interrupt. Simply a wrapper around a SAL call which
+ * defers processing to the SGI prom.
+ */ static irqreturn_t
+tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+{
+ struct tioce_common *soft = arg;
+ struct ia64_sal_retval ret_stuff;
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
+ soft->ce_pcibus.bs_persist_segment,
+ soft->ce_pcibus.bs_persist_busnum, 0, 0, 0, 0, 0);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * tioce_kern_init - init kernel structures related to a given TIOCE
+ * @tioce_common: ptr to a cached tioce_common struct that originated in prom
+ */ static struct tioce_kernel *
+tioce_kern_init(struct tioce_common *tioce_common)
+{
+ int i;
+ uint32_t tmp;
+ struct tioce *tioce_mmr;
+ struct tioce_kernel *tioce_kern;
+
+ tioce_kern = kcalloc(1, sizeof(struct tioce_kernel), GFP_KERNEL);
+ if (!tioce_kern) {
+ return NULL;
+ }
+
+ tioce_kern->ce_common = tioce_common;
+ spin_lock_init(&tioce_kern->ce_lock);
+ INIT_LIST_HEAD(&tioce_kern->ce_dmamap_list);
+ tioce_common->ce_kernel_private = (uint64_t) tioce_kern;
+
+ /*
+ * Determine the secondary bus number of the port2 logical PPB.
+ * This is used to decide whether a given pci device resides on
+ * port1 or port2. Note: We don't have enough plumbing set up
+ * here to use pci_read_config_xxx() so use the raw_pci_ops vector.
+ */
+
+ raw_pci_ops->read(tioce_common->ce_pcibus.bs_persist_segment,
+ tioce_common->ce_pcibus.bs_persist_busnum,
+ PCI_DEVFN(2, 0), PCI_SECONDARY_BUS, 1, &tmp);
+ tioce_kern->ce_port1_secondary = (uint8_t) tmp;
+
+ /*
+ * Set PMU pagesize to the largest size available, and zero out
+ * the ate's.
+ */
+
+ tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr->ce_ure_page_map &= ~CE_URE_PAGESIZE_MASK;
+ tioce_mmr->ce_ure_page_map |= CE_URE_256K_PAGESIZE;
+ tioce_kern->ce_ate3240_pagesize = KB(256);
+
+ for (i = 0; i < TIOCE_NUM_M40_ATES; i++) {
+ tioce_kern->ce_ate40_shadow[i] = 0;
+ tioce_mmr->ce_ure_ate40[i] = 0;
+ }
+
+ for (i = 0; i < TIOCE_NUM_M3240_ATES; i++) {
+ tioce_kern->ce_ate3240_shadow[i] = 0;
+ tioce_mmr->ce_ure_ate3240[i] = 0;
+ }
+
+ return tioce_kern;
+}
+
+/**
+ * tioce_force_interrupt - implement altix force_interrupt() backend for CE
+ * @sn_irq_info: sn asic irq that we need an interrupt generated for
+ *
+ * Given an sn_irq_info struct, set the proper bit in ce_adm_force_int to
+ * force a secondary interrupt to be generated. This is to work around an
+ * asic issue where there is a small window of opportunity for a legacy device
+ * interrupt to be lost.
+ */
+static void
+tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce *ce_mmr;
+ uint64_t force_int_val;
+
+ if (!sn_irq_info->irq_bridge)
+ return;
+
+ if (sn_irq_info->irq_bridge_type != PCIIO_ASIC_TYPE_TIOCE)
+ return;
+
+ pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ if (!pcidev_info)
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+ /*
+ * irq_int_bit is originally set up by prom, and holds the interrupt
+ * bit shift (not mask) as defined by the bit definitions in the
+ * ce_adm_int mmr. These shifts are not the same for the
+ * ce_adm_force_int register, so do an explicit mapping here to make
+ * things clearer.
+ */
+
+ switch (sn_irq_info->irq_int_bit) {
+ case CE_ADM_INT_PCIE_PORT1_DEV_A_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_A_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_B_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_B_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_C_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_C_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT1_DEV_D_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT1_DEV_D_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_A_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_A_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_B_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_B_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_C_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_C_SHFT;
+ break;
+ case CE_ADM_INT_PCIE_PORT2_DEV_D_SHFT:
+ force_int_val = 1UL << CE_ADM_FORCE_INT_PCIE_PORT2_DEV_D_SHFT;
+ break;
+ default:
+ return;
+ }
+ ce_mmr->ce_adm_force_int = force_int_val;
+}
+
+/**
+ * tioce_target_interrupt - implement set_irq_affinity for tioce resident
+ * functions. Note: only applies to line interrupts, not MSI's.
+ *
+ * @sn_irq_info: SN IRQ context
+ *
+ * Given an sn_irq_info, set the associated CE device's interrupt destination
+ * register. Since the interrupt destination registers are on a per-ce-slot
+ * basis, this will retarget line interrupts for all functions downstream of
+ * the slot.
+ */
+static void
+tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
+{
+ struct pcidev_info *pcidev_info;
+ struct tioce_common *ce_common;
+ struct tioce *ce_mmr;
+ int bit;
+
+ pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+ if (!pcidev_info)
+ return;
+
+ ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
+ ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+
+ bit = sn_irq_info->irq_int_bit;
+
+ ce_mmr->ce_adm_int_mask |= (1UL << bit);
+ ce_mmr->ce_adm_int_dest[bit] =
+ ((uint64_t)sn_irq_info->irq_irq << INTR_VECTOR_SHFT) |
+ sn_irq_info->irq_xtalkaddr;
+ ce_mmr->ce_adm_int_mask &= ~(1UL << bit);
+
+ tioce_force_interrupt(sn_irq_info);
+}
+
+/**
+ * tioce_bus_fixup - perform final PCI fixup for a TIO CE bus
+ * @prom_bussoft: Common prom/kernel struct representing the bus
+ *
+ * Replicates the tioce_common pointed to by @prom_bussoft in kernel
+ * space. Allocates and initializes a kernel-only area for a given CE,
+ * and sets up an irq for handling CE error interrupts.
+ *
+ * On successful setup, returns the kernel version of tioce_common back to
+ * the caller.
+ */
+static void *
+tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)
+{
+ struct tioce_common *tioce_common;
+
+ /*
+ * Allocate kernel bus soft and copy from prom.
+ */
+
+ tioce_common = kcalloc(1, sizeof(struct tioce_common), GFP_KERNEL);
+ if (!tioce_common)
+ return NULL;
+
+ memcpy(tioce_common, prom_bussoft, sizeof(struct tioce_common));
+ tioce_common->ce_pcibus.bs_base |= __IA64_UNCACHED_OFFSET;
+
+ if (tioce_kern_init(tioce_common) == NULL) {
+ kfree(tioce_common);
+ return NULL;
+ }
+
+ if (request_irq(SGI_PCIASIC_ERROR,
+ tioce_error_intr_handler,
+ SA_SHIRQ, "TIOCE error", (void *)tioce_common))
+ printk(KERN_WARNING
+ "%s: Unable to get irq %d. "
+ "Error interrupts won't be routed for "
+ "TIOCE bus %04x:%02x\n",
+ __FUNCTION__, SGI_PCIASIC_ERROR,
+ tioce_common->ce_pcibus.bs_persist_segment,
+ tioce_common->ce_pcibus.bs_persist_busnum);
+
+ return tioce_common;
+}
+
+static struct sn_pcibus_provider tioce_pci_interfaces = {
+ .dma_map = tioce_dma,
+ .dma_map_consistent = tioce_dma_consistent,
+ .dma_unmap = tioce_dma_unmap,
+ .bus_fixup = tioce_bus_fixup,
+ .force_interrupt = tioce_force_interrupt,
+ .target_interrupt = tioce_target_interrupt
+};
+
+/**
+ * tioce_init_provider - init SN PCI provider ops for TIO CE
+ */
+int
+tioce_init_provider(void)
+{
+ sn_pci_provider[PCIIO_ASIC_TYPE_TIOCE] = &tioce_pci_interfaces;
+ return 0;
+}
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index 117f183f0b4..8520df9cee6 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -71,21 +71,31 @@ config M5206e
help
Motorola ColdFire 5206e processor support.
+config M523x
+ bool "MCF523x"
+ help
+ Freescale Coldfire 5230/1/2/4/5 processor support
+
config M5249
bool "MCF5249"
help
Motorola ColdFire 5249 processor support.
-config M527x
- bool "MCF527x"
+config M5271
+ bool "MCF5271"
help
- Freescale (Motorola) ColdFire 5270/5271/5274/5275 processor support.
+ Freescale (Motorola) ColdFire 5270/5271 processor support.
config M5272
bool "MCF5272"
help
Motorola ColdFire 5272 processor support.
+config M5275
+ bool "MCF5275"
+ help
+ Freescale (Motorola) ColdFire 5274/5275 processor support.
+
config M528x
bool "MCF528x"
help
@@ -103,9 +113,14 @@ config M5407
endchoice
+config M527x
+ bool
+ depends on (M5271 || M5275)
+ default y
+
config COLDFIRE
bool
- depends on (M5206 || M5206e || M5249 || M527x || M5272 || M528x || M5307 || M5407)
+ depends on (M5206 || M5206e || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407)
default y
choice
@@ -183,6 +198,11 @@ config CLOCK_60MHz
help
Select a 60MHz CPU clock frequency.
+config CLOCK_62_5MHz
+ bool "62.5MHz"
+ help
+ Select a 62.5MHz CPU clock frequency.
+
config CLOCK_64MHz
bool "64MHz"
help
@@ -302,6 +322,12 @@ config ELITE
help
Support for the Motorola M5206eLITE board.
+config M5235EVB
+ bool "Freescale M5235EVB support"
+ depends on M523x
+ help
+ Support for the Freescale M5235EVB board.
+
config M5249C3
bool "Motorola M5249C3 board support"
depends on M5249
@@ -310,13 +336,13 @@ config M5249C3
config M5271EVB
bool "Freescale (Motorola) M5271EVB board support"
- depends on M527x
+ depends on M5271
help
Support for the Freescale (Motorola) M5271EVB board.
config M5275EVB
bool "Freescale (Motorola) M5275EVB board support"
- depends on M527x
+ depends on M5275
help
Support for the Freescale (Motorola) M5275EVB board.
@@ -343,6 +369,12 @@ config COBRA5282
depends on M528x
help
Support for the senTec COBRA5282 board.
+
+config SOM5282EM
+ bool "EMAC.Inc SOM5282EM board support"
+ depends on M528x
+ help
+ Support for the EMAC.Inc SOM5282EM module.
config ARN5307
bool "Arnewsh 5307 board support"
@@ -410,6 +442,12 @@ config CPU16B
help
Support for the SNEHA CPU16B board.
+config MOD5272
+ bool "Netburner MOD-5272 board support"
+ depends on M5272
+ help
+ Support for the Netburner MOD-5272 board.
+
config ROMFS_FROM_ROM
bool " ROMFS image not RAM resident"
depends on (NETtel || SNAPGEAR)
@@ -430,7 +468,7 @@ config ARNEWSH
config MOTOROLA
bool
default y
- depends on (M5206eC3 || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
+ depends on (M5206eC3 || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3)
config HW_FEITH
bool
@@ -441,6 +479,11 @@ config senTec
bool
default y
depends on (COBRA5272 || COBRA5282)
+
+config EMAC_INC
+ bool
+ default y
+ depends on (SOM5282EM)
config SNEHA
bool
@@ -455,6 +498,15 @@ config LARGE_ALLOCS
a lot of RAM, and you need to able to allocate very large
contiguous chunks. If unsure, say N.
+config 4KSTACKS
+ bool "Use 4Kb for kernel stacks instead of 8Kb"
+ default y
+ help
+ If you say Y here the kernel will use a 4Kb stacksize for the
+ kernel stack attached to each process/thread. This facilitates
+ running more threads on a system and also reduces the pressure
+ on the VM subsystem for higher order allocations.
+
choice
prompt "RAM size"
default AUTO
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
index a254aa9d499..97022ed0da3 100644
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -14,6 +14,7 @@ platform-$(CONFIG_M68VZ328) := 68VZ328
platform-$(CONFIG_M68360) := 68360
platform-$(CONFIG_M5206) := 5206
platform-$(CONFIG_M5206e) := 5206e
+platform-$(CONFIG_M523x) := 523x
platform-$(CONFIG_M5249) := 5249
platform-$(CONFIG_M527x) := 527x
platform-$(CONFIG_M5272) := 5272
@@ -29,6 +30,7 @@ board-$(CONFIG_UCQUICC) := uCquicc
board-$(CONFIG_DRAGEN2) := de2
board-$(CONFIG_ARNEWSH) := ARNEWSH
board-$(CONFIG_MOTOROLA) := MOTOROLA
+board-$(CONFIG_M5235EVB) := M5235EVB
board-$(CONFIG_M5271EVB) := M5271EVB
board-$(CONFIG_M5275EVB) := M5275EVB
board-$(CONFIG_M5282EVB) := M5282EVB
@@ -39,6 +41,7 @@ board-$(CONFIG_SECUREEDGEMP3) := MP3
board-$(CONFIG_CLEOPATRA) := CLEOPATRA
board-$(CONFIG_senTec) := senTec
board-$(CONFIG_SNEHA) := SNEHA
+board-$(CONFIG_MOD5272) := MOD5272
BOARD := $(board-y)
model-$(CONFIG_RAMKERNEL) := ram
@@ -53,6 +56,7 @@ MODEL := $(model-y)
#
cpuclass-$(CONFIG_M5206) := 5307
cpuclass-$(CONFIG_M5206e) := 5307
+cpuclass-$(CONFIG_M523x) := 5307
cpuclass-$(CONFIG_M5249) := 5307
cpuclass-$(CONFIG_M527x) := 5307
cpuclass-$(CONFIG_M5272) := 5307
@@ -76,6 +80,7 @@ export PLATFORM BOARD MODEL CPUCLASS
#
cflags-$(CONFIG_M5206) := -m5200 -Wa,-S -Wa,-m5200
cflags-$(CONFIG_M5206e) := -m5200 -Wa,-S -Wa,-m5200
+cflags-$(CONFIG_M523x) := -m5307 -Wa,-S -Wa,-m5307
cflags-$(CONFIG_M5249) := -m5200 -Wa,-S -Wa,-m5200
cflags-$(CONFIG_M527x) := -m5307 -Wa,-S -Wa,-m5307
cflags-$(CONFIG_M5272) := -m5307 -Wa,-S -Wa,-m5307
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig
index e4bd31be966..87f2d6587c5 100644
--- a/arch/m68knommu/defconfig
+++ b/arch/m68knommu/defconfig
@@ -1,24 +1,48 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.13-uc0
+# Wed Aug 31 15:03:26 2005
#
+CONFIG_M68KNOMMU=y
# CONFIG_MMU is not set
# CONFIG_FPU is not set
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
-# CONFIG_SYSVIPC is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -34,9 +58,11 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_M68360 is not set
# CONFIG_M5206 is not set
# CONFIG_M5206e is not set
+# CONFIG_M523x is not set
# CONFIG_M5249 is not set
-# CONFIG_M527x is not set
+# CONFIG_M5271 is not set
CONFIG_M5272=y
+# CONFIG_M5275 is not set
# CONFIG_M528x is not set
# CONFIG_M5307 is not set
# CONFIG_M5407 is not set
@@ -54,6 +80,8 @@ CONFIG_COLDFIRE=y
# CONFIG_CLOCK_50MHz is not set
# CONFIG_CLOCK_54MHz is not set
# CONFIG_CLOCK_60MHz is not set
+# CONFIG_CLOCK_62_5MHz is not set
+# CONFIG_CLOCK_64MHz is not set
CONFIG_CLOCK_66MHz=y
# CONFIG_CLOCK_70MHz is not set
# CONFIG_CLOCK_100MHz is not set
@@ -65,13 +93,19 @@ CONFIG_CLOCK_66MHz=y
# Platform
#
CONFIG_M5272C3=y
+# CONFIG_COBRA5272 is not set
+# CONFIG_CANCam is not set
+# CONFIG_SCALES is not set
# CONFIG_NETtel is not set
+# CONFIG_CPU16B is not set
+# CONFIG_MOD5272 is not set
CONFIG_MOTOROLA=y
# CONFIG_LARGE_ALLOCS is not set
-# CONFIG_RAMAUTO is not set
+CONFIG_4KSTACKS=y
+CONFIG_RAMAUTO=y
# CONFIG_RAM4MB is not set
# CONFIG_RAM8MB is not set
-CONFIG_RAM16MB=y
+# CONFIG_RAM16MB is not set
# CONFIG_RAM32MB is not set
CONFIG_RAMAUTOBIT=y
# CONFIG_RAM8BIT is not set
@@ -79,20 +113,34 @@ CONFIG_RAMAUTOBIT=y
# CONFIG_RAM32BIT is not set
CONFIG_RAMKERNEL=y
# CONFIG_ROMKERNEL is not set
-# CONFIG_HIMEMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
#
# Executable file formats
#
-CONFIG_KCORE_AOUT=y
CONFIG_BINFMT_FLAT=y
# CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
#
# Power management options
@@ -100,12 +148,82 @@ CONFIG_BINFMT_FLAT=y
# CONFIG_PM is not set
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
# Memory Technology Devices (MTD)
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -116,35 +234,50 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
CONFIG_MTD_RAM=y
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_SNAPGEARuC is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
#
# Disk-On-Chip Device Drivers
#
-# CONFIG_MTD_DOC1000 is not set
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
@@ -159,21 +292,32 @@ CONFIG_MTD_UCLINUX=y
#
# Plug and Play support
#
-# CONFIG_PNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_BLKMEM is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
#
-# ATA/IDE/MFM/RLL support
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -190,249 +334,230 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
-# I2O device support
-#
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_XFRM_USER is not set
-# CONFIG_IPV6 is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
#
-CONFIG_IPV6_SCTP__=y
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
#
-# QoS and/or fair queueing
+# I2O device support
#
-# CONFIG_NET_SCHED is not set
#
-# Network testing
+# Network device support
#
-# CONFIG_NET_PKTGEN is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NET_PCI is not set
CONFIG_FEC=y
+# CONFIG_FEC2 is not set
#
# Ethernet (1000 Mbit)
#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
-# Wireless LAN (non-hamradio)
+# ISDN subsystem
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_ISDN is not set
#
-# Token Ring devices (depends on LLC=y)
+# Telephony Support
#
-# CONFIG_SHAPER is not set
+# CONFIG_PHONE is not set
#
-# Wan interfaces
+# Input device support
#
-# CONFIG_WAN is not set
+# CONFIG_INPUT is not set
#
-# Amateur Radio support
+# Hardware I/O ports
#
-# CONFIG_HAMRADIO is not set
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
#
-# IrDA (infrared) support
+# Character devices
#
-# CONFIG_IRDA is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_LEDMAN is not set
+# CONFIG_RESETSWITCH is not set
#
-# ISDN subsystem
+# Serial drivers
#
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_SERIAL_8250 is not set
#
-# Telephony Support
+# Non-8250 serial port support
#
-# CONFIG_PHONE is not set
+CONFIG_SERIAL_COLDFIRE=y
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
#
-# Input device support
+# IPMI
#
-CONFIG_INPUT=y
+# CONFIG_IPMI_HANDLER is not set
#
-# Userland interfaces
+# Watchdog Cards
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_MCFWATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
#
-# Input I/O drivers
+# Ftape, the floppy tape device driver
#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_RAW_DRIVER is not set
#
-# Input Device Drivers
+# TPM devices
#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_MCF_QSPI is not set
+# CONFIG_M41T11M6 is not set
#
-# Character devices
+# I2C support
#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_RESETSWITCH is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
#
-# Serial drivers
+# Dallas's 1-wire bus
#
-# CONFIG_SERIAL_8250 is not set
+# CONFIG_W1 is not set
#
-# Non-8250 serial port support
+# Hardware Monitoring support
#
-CONFIG_SERIAL_COLDFIRE=y
-# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HWMON is not set
#
-# I2C support
+# Misc devices
#
-# CONFIG_I2C is not set
#
-# I2C Hardware Sensors Mainboard support
+# Multimedia devices
#
+# CONFIG_VIDEO_DEV is not set
#
-# I2C Hardware Sensors Chip support
+# Digital Video Broadcasting Devices
#
+# CONFIG_DVB is not set
#
-# Mice
+# Graphics support
#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_FB is not set
#
-# IPMI
+# SPI support
#
-# CONFIG_IPMI_HANDLER is not set
+# CONFIG_SPI is not set
#
-# Watchdog Cards
+# Sound
#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
+# CONFIG_SOUND is not set
#
-# Ftape, the floppy tape device driver
+# USB support
#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
#
-# Multimedia devices
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+
+#
+# SN Devices
#
-# CONFIG_VIDEO_DEV is not set
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+CONFIG_MAGIC_ROM_PTR=y
+# CONFIG_INOTIFY is not set
# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -445,15 +570,17 @@ CONFIG_ROMFS_FS=y
#
# DOS/FAT/NT Filesystems
#
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
+CONFIG_SYSFS=y
# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
@@ -462,6 +589,7 @@ CONFIG_RAMFS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
@@ -479,12 +607,10 @@ CONFIG_RAMFS=y
#
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
@@ -494,30 +620,19 @@ CONFIG_RAMFS=y
CONFIG_MSDOS_PARTITION=y
#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-
-#
-# Bluetooth support
+# Native Language Support
#
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_FULLDEBUG is not set
-# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HIGHPROFILE is not set
+# CONFIG_BOOTPARAM is not set
# CONFIG_DUMPTOFLASH is not set
# CONFIG_NO_KERNEL_MSG is not set
# CONFIG_BDM_DISABLE is not set
@@ -525,6 +640,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Security options
#
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
@@ -533,6 +649,12 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_CRYPTO is not set
#
+# Hardware crypto devices
+#
+
+#
# Library routines
#
+# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 557238596dc..a220345e974 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -6,7 +6,7 @@
* Copyleft ()) 2000 James D. Schettine {james@telos-systems.com}
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* Copyright (C) 1995 Hamish Macdonald
- * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
+ * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
* Copyright (C) 2001 Lineo, Inc. <www.lineo.com>
*
* 68VZ328 Fixes/support Evan Stawnyczy <e@lineo.ca>
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/fb.h>
+#include <linux/module.h>
#include <linux/console.h>
#include <linux/genhd.h>
#include <linux/errno.h>
@@ -45,6 +46,9 @@ unsigned long rom_length;
unsigned long memory_start;
unsigned long memory_end;
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+
char command_line[COMMAND_LINE_SIZE];
/* setup some dummy routines */
@@ -103,15 +107,21 @@ void (*mach_power_off)( void ) = NULL;
#if defined(CONFIG_M5206e)
#define CPU "COLDFIRE(m5206e)"
#endif
+#if defined(CONFIG_M523x)
+ #define CPU "COLDFIRE(m523x)"
+#endif
#if defined(CONFIG_M5249)
#define CPU "COLDFIRE(m5249)"
#endif
-#if defined(CONFIG_M527x)
- #define CPU "COLDFIRE(m5270/5271/5274/5275)"
+#if defined(CONFIG_M5271)
+ #define CPU "COLDFIRE(m5270/5271)"
#endif
#if defined(CONFIG_M5272)
#define CPU "COLDFIRE(m5272)"
#endif
+#if defined(CONFIG_M5275)
+ #define CPU "COLDFIRE(m5274/5275)"
+#endif
#if defined(CONFIG_M528x)
#define CPU "COLDFIRE(m5280/5282)"
#endif
@@ -152,7 +162,7 @@ void setup_arch(char **cmdline_p)
init_mm.start_code = (unsigned long) &_stext;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
- init_mm.brk = (unsigned long) 0;
+ init_mm.brk = (unsigned long) 0;
config_BSP(&command_line[0], sizeof(command_line));
@@ -171,7 +181,7 @@ void setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_ELITE
printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
-#endif
+#endif
#ifdef CONFIG_TELOS
printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n");
#endif
@@ -200,6 +210,9 @@ void setup_arch(char **cmdline_p)
#ifdef CONFIG_DRAGEN2
printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
#endif
+#ifdef CONFIG_M5235EVB
+ printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)");
+#endif
#ifdef DEBUG
printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
@@ -223,7 +236,7 @@ void setup_arch(char **cmdline_p)
saved_command_line[COMMAND_LINE_SIZE-1] = 0;
#ifdef DEBUG
- if (strlen(*cmdline_p))
+ if (strlen(*cmdline_p))
printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
#endif
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index ad7dc6347f1..5bc06846286 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -21,6 +21,7 @@
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/a.out.h>
#include <linux/user.h>
@@ -38,7 +39,7 @@
#include <asm/machdep.h>
#include <asm/siginfo.h>
-static char *vec_names[] = {
+static char const * const vec_names[] = {
"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
"PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
@@ -106,17 +107,20 @@ asmlinkage void buserr_c(struct frame *fp)
int kstack_depth_to_print = 48;
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_stack(struct task_struct *task, unsigned long *stack)
{
- unsigned long *stack, *endstack, addr;
+ unsigned long *endstack, addr;
extern char _start, _etext;
int i;
- if (esp == NULL)
- esp = (unsigned long *) &esp;
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.ksp;
+ else
+ stack = (unsigned long *)&stack;
+ }
- stack = esp;
- addr = (unsigned long) esp;
+ addr = (unsigned long) stack;
endstack = (unsigned long *) PAGE_ALIGN(addr);
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
@@ -306,6 +310,8 @@ void dump_stack(void)
show_stack(current, &stack);
}
+EXPORT_SYMBOL(dump_stack);
+
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpemu_signal(int signal, int code, void *addr)
{
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 31cb12892da..47f06787190 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -107,7 +107,7 @@
*/
#if defined(CONFIG_ELITE)
#define RAM_START 0x30020000
-#define RAM_END 0xe0000
+#define RAM_LENGTH 0xe0000
#endif
/*
@@ -118,7 +118,8 @@
#if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
- defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB)
+ defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB) || \
+ defined(CONFIG_M5235EVB)
#define RAM_START 0x20000
#define RAM_LENGTH 0x3e0000
#endif
@@ -145,6 +146,16 @@
#define RAM_LENGTH 0x3f0000
#endif
+
+/*
+ * The EMAC SoM-5282EM module.
+ */
+#if defined(CONFIG_SOM5282EM)
+#define RAM_START 0x10000
+#define RAM_LENGTH 0xff0000
+#endif
+
+
/*
* These flash boot boards use all of ram for operation. Again the
* actual memory size is not important here, assume at least 4MiB.
@@ -158,7 +169,7 @@
#endif
/*
- * Sneha Boards mimimun memmory
+ * Sneha Boards mimimun memory
* The end of RAM will vary depending on how much ram is fitted,
* but this isn't important here, we assume at least 4MiB.
*/
@@ -167,6 +178,12 @@
#define RAM_LENGTH 0x3e0000
#endif
+#if defined(CONFIG_MOD5272)
+#define RAM_START 0x02000000
+#define RAM_LENGTH 0x00800000
+#define RAMVEC_START 0x20000000
+#define RAMVEC_LENGTH 0x00000400
+#endif
#if defined(CONFIG_RAMKERNEL)
#define TEXT ram
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
new file mode 100644
index 00000000000..22767ce506e
--- /dev/null
+++ b/arch/m68knommu/platform/523x/config.c
@@ -0,0 +1,82 @@
+/***************************************************************************/
+
+/*
+ * linux/arch/m68knommu/platform/523x/config.c
+ *
+ * Sub-architcture dependant initialization code for the Freescale
+ * 523x CPUs.
+ *
+ * Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void);
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_pit_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+/***************************************************************************/
+
+/*
+ * DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+ MCF_MBAR + MCFDMA_BASE0,
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_disableall(void)
+{
+ *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
+ *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
+}
+
+/***************************************************************************/
+
+void mcf_autovector(unsigned int vec)
+{
+ /* Everything is auto-vectored on the 5272 */
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+ mcf_disableall();
+
+#ifdef CONFIG_BOOTPARAM
+ strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+ commandp[size-1] = 0;
+#else
+ memset(commandp, 0, size);
+#endif
+
+ mach_sched_init = coldfire_pit_init;
+ mach_tick = coldfire_pit_tick;
+ mach_gettimeoffset = coldfire_pit_offset;
+ mach_trap_init = coldfire_trap_init;
+ mach_reset = coldfire_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S
index c7d7a395c4c..7f4ba837901 100644
--- a/arch/m68knommu/platform/5307/head.S
+++ b/arch/m68knommu/platform/5307/head.S
@@ -39,14 +39,18 @@
* Memory size exceptions for special cases. Some boards may be set
* for auto memory sizing, but we can't do it that way for some reason.
* For example the 5206eLITE board has static RAM, and auto-detecting
- * the SDRAM will do you no good at all.
+ * the SDRAM will do you no good at all. Same goes for the MOD5272.
*/
#ifdef CONFIG_RAMAUTO
#if defined(CONFIG_M5206eLITE)
-#define MEM_SIZE 0x00100000 /* 1MiB default memory */
+#define MEM_SIZE 0x00100000 /* 1MiB default memory */
+#endif
+#if defined(CONFIG_MOD5272)
+#define MEM_SIZE 0x00800000 /* 8MiB default memory */
#endif
#endif /* CONFIG_RAMAUTO */
+
/*
* If we don't have a fixed memory size now, then lets build in code
* to auto detect the DRAM size. Obviously this is the prefered
@@ -100,11 +104,15 @@
/*
* Most ColdFire boards have their DRAM starting at address 0.
- * Notable exception is the 5206eLITE board.
+ * Notable exception is the 5206eLITE board, another is the MOD5272.
*/
#if defined(CONFIG_M5206eLITE)
#define MEM_BASE 0x30000000
#endif
+#if defined(CONFIG_MOD5272)
+#define MEM_BASE 0x02000000
+#define VBR_BASE 0x20000000 /* vectors in SRAM */
+#endif
#ifndef MEM_BASE
#define MEM_BASE 0x00000000 /* memory base at address 0 */
@@ -188,6 +196,7 @@ _start:
movel %a7,_rambase
GET_MEM_SIZE /* macro code determines size */
+ addl %a7,%d0
movel %d0,_ramend /* set end ram addr */
/*
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index 0f5d1fe8eb5..7d8990d784a 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -79,7 +79,7 @@ ENTRY(system_call)
movel %sp@(PT_ORIG_D0),%d0
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
jne do_trace
@@ -105,7 +105,7 @@ Luser_return:
andw #ALLOWINT,%sr
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
andl #_TIF_WORK_MASK,%d1
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index f7bc80a60e0..8ff48adf24a 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -96,7 +96,7 @@ Luser_return:
andw #ALLOWINT,%sr
movel %sp,%d1 /* get thread_info pointer */
- andl #0xffffe000,%d1
+ andl #-THREAD_SIZE,%d1
movel %d1,%a2
move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
andl #_TIF_WORK_MASK,%d1
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index f9b0d778dd8..d1b6e6dcb50 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -21,11 +21,13 @@ CC := $(CC) -m32
endif
LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic
-CPPFLAGS += -Iarch/$(ARCH)
+CPPFLAGS += -Iarch/$(ARCH) -Iinclude3
AFLAGS += -Iarch/$(ARCH)
CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe \
-ffixed-r2 -mmultiple
CPP = $(CC) -E $(CFLAGS)
+# Temporary hack until we have migrated to asm-powerpc
+LINUXINCLUDE += -Iinclude3
CHECKFLAGS += -D__powerpc__
@@ -101,6 +103,7 @@ endef
archclean:
$(Q)$(MAKE) $(clean)=arch/ppc/boot
+ $(Q)rm -rf include3
prepare: include/asm-$(ARCH)/offsets.h checkbin
@@ -110,6 +113,12 @@ arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
$(call filechk,gen-asm-offsets)
+# Temporary hack until we have migrated to asm-powerpc
+include/asm: include3/asm
+include3/asm:
+ $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi
+ $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm
+
# Use the file '.tmp_gas_check' for binutils tests, as gas won't output
# to stdout and these checks are run even on install targets.
TOUT := .tmp_gas_check
diff --git a/arch/ppc/boot/utils/addRamDisk.c b/arch/ppc/boot/utils/addRamDisk.c
deleted file mode 100644
index 93400dfcce7..00000000000
--- a/arch/ppc/boot/utils/addRamDisk.c
+++ /dev/null
@@ -1,203 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-
-#define ElfHeaderSize (64 * 1024)
-#define ElfPages (ElfHeaderSize / 4096)
-#define KERNELBASE (0xc0000000)
-
-void get4k(FILE *file, char *buf )
-{
- unsigned j;
- unsigned num = fread(buf, 1, 4096, file);
- for ( j=num; j<4096; ++j )
- buf[j] = 0;
-}
-
-void put4k(FILE *file, char *buf )
-{
- fwrite(buf, 1, 4096, file);
-}
-
-void death(const char *msg, FILE *fdesc, const char *fname)
-{
- printf(msg);
- fclose(fdesc);
- unlink(fname);
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- char inbuf[4096];
- FILE *ramDisk = NULL;
- FILE *inputVmlinux = NULL;
- FILE *outputVmlinux = NULL;
- unsigned i = 0;
- u_int32_t ramFileLen = 0;
- u_int32_t ramLen = 0;
- u_int32_t roundR = 0;
- u_int32_t kernelLen = 0;
- u_int32_t actualKernelLen = 0;
- u_int32_t round = 0;
- u_int32_t roundedKernelLen = 0;
- u_int32_t ramStartOffs = 0;
- u_int32_t ramPages = 0;
- u_int32_t roundedKernelPages = 0;
- u_int32_t hvReleaseData = 0;
- u_int32_t eyeCatcher = 0xc8a5d9c4;
- u_int32_t naca = 0;
- u_int32_t xRamDisk = 0;
- u_int32_t xRamDiskSize = 0;
- if ( argc < 2 ) {
- printf("Name of RAM disk file missing.\n");
- exit(1);
- }
-
- if ( argc < 3 ) {
- printf("Name of vmlinux file missing.\n");
- exit(1);
- }
-
- if ( argc < 4 ) {
- printf("Name of vmlinux output file missing.\n");
- exit(1);
- }
-
- ramDisk = fopen(argv[1], "r");
- if ( ! ramDisk ) {
- printf("RAM disk file \"%s\" failed to open.\n", argv[1]);
- exit(1);
- }
- inputVmlinux = fopen(argv[2], "r");
- if ( ! inputVmlinux ) {
- printf("vmlinux file \"%s\" failed to open.\n", argv[2]);
- exit(1);
- }
- outputVmlinux = fopen(argv[3], "w+");
- if ( ! outputVmlinux ) {
- printf("output vmlinux file \"%s\" failed to open.\n", argv[3]);
- exit(1);
- }
- fseek(ramDisk, 0, SEEK_END);
- ramFileLen = ftell(ramDisk);
- fseek(ramDisk, 0, SEEK_SET);
- printf("%s file size = %d\n", argv[1], ramFileLen);
-
- ramLen = ramFileLen;
-
- roundR = 4096 - (ramLen % 4096);
- if ( roundR ) {
- printf("Rounding RAM disk file up to a multiple of 4096, adding %d\n", roundR);
- ramLen += roundR;
- }
-
- printf("Rounded RAM disk size is %d\n", ramLen);
- fseek(inputVmlinux, 0, SEEK_END);
- kernelLen = ftell(inputVmlinux);
- fseek(inputVmlinux, 0, SEEK_SET);
- printf("kernel file size = %d\n", kernelLen);
- if ( kernelLen == 0 ) {
- printf("You must have a linux kernel specified as argv[2]\n");
- exit(1);
- }
-
- actualKernelLen = kernelLen - ElfHeaderSize;
-
- printf("actual kernel length (minus ELF header) = %d\n", actualKernelLen);
-
- round = actualKernelLen % 4096;
- roundedKernelLen = actualKernelLen;
- if ( round )
- roundedKernelLen += (4096 - round);
-
- printf("actual kernel length rounded up to a 4k multiple = %d\n", roundedKernelLen);
-
- ramStartOffs = roundedKernelLen;
- ramPages = ramLen / 4096;
-
- printf("RAM disk pages to copy = %d\n", ramPages);
-
- // Copy 64K ELF header
- for (i=0; i<(ElfPages); ++i) {
- get4k( inputVmlinux, inbuf );
- put4k( outputVmlinux, inbuf );
- }
-
- roundedKernelPages = roundedKernelLen / 4096;
-
- fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
-
- for ( i=0; i<roundedKernelPages; ++i ) {
- get4k( inputVmlinux, inbuf );
- put4k( outputVmlinux, inbuf );
- }
-
- for ( i=0; i<ramPages; ++i ) {
- get4k( ramDisk, inbuf );
- put4k( outputVmlinux, inbuf );
- }
-
- /* Close the input files */
- fclose(ramDisk);
- fclose(inputVmlinux);
- /* And flush the written output file */
- fflush(outputVmlinux);
-
- /* fseek to the hvReleaseData pointer */
- fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
- if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
- death("Could not read hvReleaseData pointer\n", outputVmlinux, argv[3]);
- }
- hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
- printf("hvReleaseData is at %08x\n", hvReleaseData);
-
- /* fseek to the hvReleaseData */
- fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
- if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
- death("Could not read hvReleaseData\n", outputVmlinux, argv[3]);
- }
- /* Check hvReleaseData sanity */
- if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
- death("hvReleaseData is invalid\n", outputVmlinux, argv[3]);
- }
- /* Get the naca pointer */
- naca = ntohl(*((u_int32_t *) &inbuf[0x0c])) - KERNELBASE;
- printf("naca is at %08x\n", naca);
-
- /* fseek to the naca */
- fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
- if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
- death("Could not read naca\n", outputVmlinux, argv[3]);
- }
- xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
- xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
- /* Make sure a RAM disk isn't already present */
- if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
- death("RAM disk is already attached to this kernel\n", outputVmlinux, argv[3]);
- }
- /* Fill in the values */
- *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
- *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
-
- /* Write out the new naca */
- fflush(outputVmlinux);
- fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
- if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
- death("Could not write naca\n", outputVmlinux, argv[3]);
- }
- printf("RAM Disk of 0x%x pages size is attached to the kernel at offset 0x%08x\n",
- ramPages, ramStartOffs);
-
- /* Done */
- fclose(outputVmlinux);
- /* Set permission to executable */
- chmod(argv[3], S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
-
- return 0;
-}
-
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
index 468721d9ebd..3fb1fb619d2 100644
--- a/arch/ppc/kernel/cpu_setup_6xx.S
+++ b/arch/ppc/kernel/cpu_setup_6xx.S
@@ -249,8 +249,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
sync
isync
- /* Enable L2 HW prefetch
+ /* Enable L2 HW prefetch, if L2 is enabled
*/
+ mfspr r3,SPRN_L2CR
+ andis. r3,r3,L2CR_L2E@h
+ beqlr
mfspr r3,SPRN_MSSCR0
ori r3,r3,3
sync
diff --git a/arch/ppc/kernel/l2cr.S b/arch/ppc/kernel/l2cr.S
index c3944104826..861115249b3 100644
--- a/arch/ppc/kernel/l2cr.S
+++ b/arch/ppc/kernel/l2cr.S
@@ -156,6 +156,26 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
The bit moved on the 7450.....
****/
+BEGIN_FTR_SECTION
+ /* Disable L2 prefetch on some 745x and try to ensure
+ * L2 prefetch engines are idle. As explained by errata
+ * text, we can't be sure they are, we just hope very hard
+ * that well be enough (sic !). At least I noticed Apple
+ * doesn't even bother doing the dcbf's here...
+ */
+ mfspr r4,SPRN_MSSCR0
+ rlwinm r4,r4,0,0,29
+ sync
+ mtspr SPRN_MSSCR0,r4
+ sync
+ isync
+ lis r4,KERNELBASE@h
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+
/* TODO: use HW flush assist when available */
lis r4,0x0002
@@ -230,7 +250,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
oris r3,r3,0x8000
mtspr SPRN_L2CR,r3
sync
-
+
+ /* Enable L2 HW prefetch on 744x/745x */
+BEGIN_FTR_SECTION
+ mfspr r3,SPRN_MSSCR0
+ ori r3,r3,3
+ sync
+ mtspr SPRN_MSSCR0,r3
+ sync
+ isync
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
4:
/* Restore HID0[DPM] to whatever it was before */
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index a3702cfe8f7..4c888da89b3 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -57,7 +57,7 @@ unsigned char __res[sizeof(bd_t)];
extern void m8xx_ide_init(void);
extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset();
+extern void m8xx_cpm_reset(void);
extern void m8xx_wdt_handler_install(bd_t *bp);
extern void rpxfb_alloc_pages(void);
extern void cpm_interrupt_init(void);
@@ -266,8 +266,8 @@ m8xx_show_percpuinfo(struct seq_file *m, int i)
bp = (bd_t *)__res;
- seq_printf(m, "clock\t\t: %ldMHz\n"
- "bus clock\t: %ldMHz\n",
+ seq_printf(m, "clock\t\t: %uMHz\n"
+ "bus clock\t: %uMHz\n",
bp->bi_intfreq / 1000000,
bp->bi_busfreq / 1000000);
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index 2ce87836c67..13b262f1021 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -302,12 +302,6 @@ config GENERIC_HARDIRQS
bool
default y
-config MSCHUNKS
- bool
- depends on PPC_ISERIES
- default y
-
-
config PPC_RTAS
bool
depends on PPC_PSERIES || PPC_BPA
@@ -350,13 +344,46 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+source "fs/Kconfig.binfmt"
+
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs"
+ depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
+ select HOTPLUG
+ ---help---
+ Say Y here to be able to turn CPUs off and on.
+
+ Say N if you are unsure.
+
+config PROC_DEVICETREE
+ bool "Support for Open Firmware device tree in /proc"
+ depends on !PPC_ISERIES
+ help
+ This option adds a device-tree directory under /proc which contains
+ an image of the device tree that the kernel copies from Open
+ Firmware. If unsure, say Y here.
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+ depends on !PPC_ISERIES
+
+config CMDLINE
+ string "Initial kernel command string"
+ depends on CMDLINE_BOOL
+ default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
+ help
+ On some platforms, there is currently no way for the boot loader to
+ pass arguments to the kernel. For these platforms, you can supply
+ some command-line options at build time by entering them here. In
+ most cases you will need to specify the root device here.
+
endmenu
config ISA_DMA_API
bool
default y
-menu "General setup"
+menu "Bus Options"
config ISA
bool
@@ -389,45 +416,12 @@ config PCI_DOMAINS
bool
default PCI
-source "fs/Kconfig.binfmt"
-
source "drivers/pci/Kconfig"
-config HOTPLUG_CPU
- bool "Support for hot-pluggable CPUs"
- depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
- select HOTPLUG
- ---help---
- Say Y here to be able to turn CPUs off and on.
-
- Say N if you are unsure.
-
source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
-config PROC_DEVICETREE
- bool "Support for Open Firmware device tree in /proc"
- depends on !PPC_ISERIES
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware. If unsure, say Y here.
-
-config CMDLINE_BOOL
- bool "Default bootloader kernel arguments"
- depends on !PPC_ISERIES
-
-config CMDLINE
- string "Initial kernel command string"
- depends on CMDLINE_BOOL
- default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
- help
- On some platforms, there is currently no way for the boot loader to
- pass arguments to the kernel. For these platforms, you can supply
- some command-line options at build time by entering them here. In
- most cases you will need to specify the root device here.
-
endmenu
source "net/Kconfig"
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
index 731b8475833..6350cce82ef 100644
--- a/arch/ppc64/Makefile
+++ b/arch/ppc64/Makefile
@@ -55,6 +55,8 @@ LDFLAGS := -m elf64ppc
LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD)
CFLAGS += -msoft-float -pipe -mminimal-toc -mtraceback=none \
-mcall-aixdesc
+# Temporary hack until we have migrated to asm-powerpc
+CPPFLAGS += -Iinclude3
GCC_VERSION := $(call cc-version)
GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;)
@@ -112,6 +114,7 @@ all: $(KBUILD_IMAGE)
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
+ $(Q)rm -rf include3
prepare: include/asm-ppc64/offsets.h
@@ -121,6 +124,12 @@ arch/ppc64/kernel/asm-offsets.s: include/asm include/linux/version.h \
include/asm-ppc64/offsets.h: arch/ppc64/kernel/asm-offsets.s
$(call filechk,gen-asm-offsets)
+# Temporary hack until we have migrated to asm-powerpc
+include/asm: include3/asm
+include3/asm:
+ $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi;
+ $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm
+
define archhelp
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
echo ' zImage.initrd- Compressed kernel image with initrd attached,'
diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
index 683b2d43c15..2c5f5e73d00 100644
--- a/arch/ppc64/boot/Makefile
+++ b/arch/ppc64/boot/Makefile
@@ -22,8 +22,8 @@
HOSTCC := gcc
-BOOTCFLAGS := $(HOSTCFLAGS) $(LINUXINCLUDE) -fno-builtin
-BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional
+BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem $(shell $(CROSS32CC) -print-file-name=include)
+BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(srctree)/$(src)/zImage.lds
OBJCOPYFLAGS := contents,alloc,load,readonly,data
diff --git a/arch/ppc64/boot/addnote.c b/arch/ppc64/boot/addnote.c
index 719663a694b..8041a9845ab 100644
--- a/arch/ppc64/boot/addnote.c
+++ b/arch/ppc64/boot/addnote.c
@@ -157,7 +157,7 @@ main(int ac, char **av)
PUT_32BE(ns, strlen(arch) + 1);
PUT_32BE(ns + 4, N_DESCR * 4);
PUT_32BE(ns + 8, 0x1275);
- strcpy(&buf[ns + 12], arch);
+ strcpy((char *) &buf[ns + 12], arch);
ns += 12 + strlen(arch) + 1;
for (i = 0; i < N_DESCR; ++i, ns += 4)
PUT_32BE(ns, descr[i]);
@@ -172,7 +172,7 @@ main(int ac, char **av)
PUT_32BE(ns, strlen(rpaname) + 1);
PUT_32BE(ns + 4, sizeof(rpanote));
PUT_32BE(ns + 8, 0x12759999);
- strcpy(&buf[ns + 12], rpaname);
+ strcpy((char *) &buf[ns + 12], rpaname);
ns += 12 + ROUNDUP(strlen(rpaname) + 1);
for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
PUT_32BE(ns, rpanote[i]);
diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S
index 04d3e74cd72..3861e7f9cf1 100644
--- a/arch/ppc64/boot/crt0.S
+++ b/arch/ppc64/boot/crt0.S
@@ -9,7 +9,7 @@
* NOTE: this code runs in 32 bit mode and is packaged as ELF32.
*/
-#include <asm/ppc_asm.h>
+#include "ppc_asm.h"
.text
.globl _start
diff --git a/arch/ppc64/boot/div64.S b/arch/ppc64/boot/div64.S
index 38f7e466d7d..722f360a32a 100644
--- a/arch/ppc64/boot/div64.S
+++ b/arch/ppc64/boot/div64.S
@@ -13,7 +13,7 @@
* 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 "ppc_asm.h"
.globl __div64_32
__div64_32:
diff --git a/arch/ppc64/boot/elf.h b/arch/ppc64/boot/elf.h
new file mode 100644
index 00000000000..d4828fcf1cb
--- /dev/null
+++ b/arch/ppc64/boot/elf.h
@@ -0,0 +1,149 @@
+#ifndef _PPC_BOOT_ELF_H_
+#define _PPC_BOOT_ELF_H_
+
+/* 32-bit ELF base types. */
+typedef unsigned int Elf32_Addr;
+typedef unsigned short Elf32_Half;
+typedef unsigned int Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef unsigned int Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef unsigned long long Elf64_Addr;
+typedef unsigned short Elf64_Half;
+typedef signed short Elf64_SHalf;
+typedef unsigned long long Elf64_Off;
+typedef signed int Elf64_Sword;
+typedef unsigned int Elf64_Word;
+typedef unsigned long long Elf64_Xword;
+typedef signed long long Elf64_Sxword;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_TLS 7 /* Thread local storage segment */
+#define PT_LOOS 0x60000000 /* OS-specific */
+#define PT_HIOS 0x6fffffff /* OS-specific */
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_GNU_EH_FRAME 0x6474e550
+
+#define PT_GNU_STACK (PT_LOOS + 0x474e551)
+
+/* These constants define the different elf file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE 0
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC64 */
+
+#define EI_NIDENT 16
+
+typedef struct elf32_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+ header, p_flags. */
+#define PF_R 0x4
+#define PF_W 0x2
+#define PF_X 0x1
+
+typedef struct elf32_phdr {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_PAD 8
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+#define ELFOSABI_NONE 0
+#define ELFOSABI_LINUX 3
+
+#endif /* _PPC_BOOT_ELF_H_ */
diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c
index 199d9804f61..99e68cfbe68 100644
--- a/arch/ppc64/boot/main.c
+++ b/arch/ppc64/boot/main.c
@@ -8,36 +8,28 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include "ppc32-types.h"
+#include <stdarg.h>
+#include <stddef.h>
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
#include "zlib.h"
-#include <linux/elf.h>
-#include <linux/string.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-
-extern void *finddevice(const char *);
-extern int getprop(void *, const char *, void *, int);
-extern void printf(const char *fmt, ...);
-extern int sprintf(char *buf, const char *fmt, ...);
-void gunzip(void *, int, unsigned char *, int *);
-void *claim(unsigned int, unsigned int, unsigned int);
-void flush_cache(void *, unsigned long);
-void pause(void);
-extern void exit(void);
-
-unsigned long strlen(const char *s);
-void *memmove(void *dest, const void *src, unsigned long n);
-void *memcpy(void *dest, const void *src, unsigned long n);
+
+static void gunzip(void *, int, unsigned char *, int *);
+extern void flush_cache(void *, unsigned long);
+
/* Value picked to match that used by yaboot */
#define PROG_START 0x01400000
#define RAM_END (256<<20) // Fixme: use OF */
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-unsigned int heap_use;
-unsigned int heap_max;
+static char *avail_ram;
+static char *begin_avail, *end_avail;
+static char *avail_high;
+static unsigned int heap_use;
+static unsigned int heap_max;
extern char _start[];
extern char _vmlinux_start[];
@@ -52,9 +44,9 @@ struct addr_range {
unsigned long size;
unsigned long memsize;
};
-struct addr_range vmlinux = {0, 0, 0};
-struct addr_range vmlinuz = {0, 0, 0};
-struct addr_range initrd = {0, 0, 0};
+static struct addr_range vmlinux = {0, 0, 0};
+static struct addr_range vmlinuz = {0, 0, 0};
+static struct addr_range initrd = {0, 0, 0};
static char scratch[128<<10]; /* 128kB of scratch space for gunzip */
@@ -64,13 +56,6 @@ typedef void (*kernel_entry_t)( unsigned long,
void *);
-int (*prom)(void *);
-
-void *chosen_handle;
-void *stdin;
-void *stdout;
-void *stderr;
-
#undef DEBUG
static unsigned long claim_base = PROG_START;
@@ -277,7 +262,7 @@ void zfree(void *x, void *addr, unsigned nb)
#define DEFLATED 8
-void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
{
z_stream s;
int r, i, flags;
diff --git a/arch/ppc64/boot/page.h b/arch/ppc64/boot/page.h
new file mode 100644
index 00000000000..14eca30fef6
--- /dev/null
+++ b/arch/ppc64/boot/page.h
@@ -0,0 +1,34 @@
+#ifndef _PPC_BOOT_PAGE_H
+#define _PPC_BOOT_PAGE_H
+/*
+ * Copyright (C) 2001 PPC64 Team, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifdef __ASSEMBLY__
+#define ASM_CONST(x) x
+#else
+#define __ASM_CONST(x) x##UL
+#define ASM_CONST(x) __ASM_CONST(x)
+#endif
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr,size) _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
+
+#endif /* _PPC_BOOT_PAGE_H */
diff --git a/arch/ppc64/boot/ppc32-types.h b/arch/ppc64/boot/ppc32-types.h
deleted file mode 100644
index f7b8884f8f7..00000000000
--- a/arch/ppc64/boot/ppc32-types.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _PPC64_TYPES_H
-#define _PPC64_TYPES_H
-
-typedef __signed__ char __s8;
-typedef unsigned char __u8;
-
-typedef __signed__ short __s16;
-typedef unsigned short __u16;
-
-typedef __signed__ int __s32;
-typedef unsigned int __u32;
-
-typedef __signed__ long long __s64;
-typedef unsigned long long __u64;
-
-typedef signed char s8;
-typedef unsigned char u8;
-
-typedef signed short s16;
-typedef unsigned short u16;
-
-typedef signed int s32;
-typedef unsigned int u32;
-
-typedef signed long long s64;
-typedef unsigned long long u64;
-
-typedef struct {
- __u32 u[4];
-} __attribute((aligned(16))) __vector128;
-
-#define BITS_PER_LONG 32
-
-typedef __vector128 vector128;
-
-#endif /* _PPC64_TYPES_H */
diff --git a/arch/ppc64/boot/ppc_asm.h b/arch/ppc64/boot/ppc_asm.h
new file mode 100644
index 00000000000..1c2c2817f9b
--- /dev/null
+++ b/arch/ppc64/boot/ppc_asm.h
@@ -0,0 +1,62 @@
+#ifndef _PPC64_PPC_ASM_H
+#define _PPC64_PPC_ASM_H
+/*
+ *
+ * Definitions used by various bits of low-level assembly code on PowerPC.
+ *
+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
+ *
+ * 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.
+ */
+
+/* Condition Register Bit Fields */
+
+#define cr0 0
+#define cr1 1
+#define cr2 2
+#define cr3 3
+#define cr4 4
+#define cr5 5
+#define cr6 6
+#define cr7 7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+
+#endif /* _PPC64_PPC_ASM_H */
diff --git a/arch/ppc64/boot/prom.c b/arch/ppc64/boot/prom.c
index 5e48b80ff5a..4bea2f4dcb0 100644
--- a/arch/ppc64/boot/prom.c
+++ b/arch/ppc64/boot/prom.c
@@ -7,43 +7,19 @@
* 2 of the License, or (at your option) any later version.
*/
#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-
-extern __u32 __div64_32(unsigned long long *dividend, __u32 divisor);
-
-/* The unnecessary pointer compare is there
- * to check for type safety (n must be 64bit)
- */
-# define do_div(n,base) ({ \
- __u32 __base = (base); \
- __u32 __rem; \
- (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
- if (((n) >> 32) == 0) { \
- __rem = (__u32)(n) % __base; \
- (n) = (__u32)(n) / __base; \
- } else \
- __rem = __div64_32(&(n), __base); \
- __rem; \
- })
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
int (*prom)(void *);
void *chosen_handle;
+
void *stdin;
void *stdout;
void *stderr;
-void exit(void);
-void *finddevice(const char *name);
-int getprop(void *phandle, const char *name, void *buf, int buflen);
-void chrpboot(int a1, int a2, void *prom); /* in main.c */
-
-int printf(char *fmt, ...);
-
-/* there is no convenient header to get this from... -- paulus */
-extern unsigned long strlen(const char *);
int
write(void *handle, void *ptr, int nb)
@@ -210,107 +186,6 @@ fputs(char *str, void *f)
return write(f, str, n) == n? 0: -1;
}
-int
-readchar(void)
-{
- char ch;
-
- for (;;) {
- switch (read(stdin, &ch, 1)) {
- case 1:
- return ch;
- case -1:
- printf("read(stdin) returned -1\r\n");
- return -1;
- }
- }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
- int c;
-
- if (lineleft == 0) {
- lineptr = line;
- for (;;) {
- c = readchar();
- if (c == -1 || c == 4)
- break;
- if (c == '\r' || c == '\n') {
- *lineptr++ = '\n';
- putchar('\n');
- break;
- }
- switch (c) {
- case 0177:
- case '\b':
- if (lineptr > line) {
- putchar('\b');
- putchar(' ');
- putchar('\b');
- --lineptr;
- }
- break;
- case 'U' & 0x1F:
- while (lineptr > line) {
- putchar('\b');
- putchar(' ');
- putchar('\b');
- --lineptr;
- }
- break;
- default:
- if (lineptr >= &line[sizeof(line) - 1])
- putchar('\a');
- else {
- putchar(c);
- *lineptr++ = c;
- }
- }
- }
- lineleft = lineptr - line;
- lineptr = line;
- }
- if (lineleft == 0)
- return -1;
- --lineleft;
- return *lineptr++;
-}
-
-
-
-/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
-unsigned char _ctype[] = {
-_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
-_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
-_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
-_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
-_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
-_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
-_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
-_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
-_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
-_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
-_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
-_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
-_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
-_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
-_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
-_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
-_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
-_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
-_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
-_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
-_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
-
size_t strnlen(const char * s, size_t count)
{
const char *sc;
@@ -320,44 +195,30 @@ size_t strnlen(const char * s, size_t count)
return sc - s;
}
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
- unsigned long result = 0,value;
+extern unsigned int __div64_32(unsigned long long *dividend,
+ unsigned int divisor);
- if (!base) {
- base = 10;
- if (*cp == '0') {
- base = 8;
- cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
- cp++;
- base = 16;
- }
- }
- }
- while (isxdigit(*cp) &&
- (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
- result = result*base + value;
- cp++;
- }
- if (endp)
- *endp = (char *)cp;
- return result;
-}
-
-long simple_strtol(const char *cp,char **endp,unsigned int base)
-{
- if(*cp=='-')
- return -simple_strtoul(cp+1,endp,base);
- return simple_strtoul(cp,endp,base);
-}
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({ \
+ unsigned int __base = (base); \
+ unsigned int __rem; \
+ (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
+ if (((n) >> 32) == 0) { \
+ __rem = (unsigned int)(n) % __base; \
+ (n) = (unsigned int)(n) / __base; \
+ } else \
+ __rem = __div64_32(&(n), __base); \
+ __rem; \
+ })
static int skip_atoi(const char **s)
{
- int i=0;
+ int i, c;
- while (isdigit(**s))
- i = i*10 + *((*s)++) - '0';
+ for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
+ i = i*10 + c - '0';
return i;
}
@@ -436,9 +297,6 @@ static char * number(char * str, unsigned long long num, int base, int size, int
return str;
}
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
-
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
@@ -477,7 +335,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
/* get field width */
field_width = -1;
- if (isdigit(*fmt))
+ if ('0' <= *fmt && *fmt <= '9')
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
@@ -493,7 +351,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
precision = -1;
if (*fmt == '.') {
++fmt;
- if (isdigit(*fmt))
+ if ('0' <= *fmt && *fmt <= '9')
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
@@ -628,7 +486,7 @@ int sprintf(char * buf, const char *fmt, ...)
static char sprint_buf[1024];
int
-printf(char *fmt, ...)
+printf(const char *fmt, ...)
{
va_list args;
int n;
diff --git a/arch/ppc64/boot/prom.h b/arch/ppc64/boot/prom.h
new file mode 100644
index 00000000000..96ab5aec740
--- /dev/null
+++ b/arch/ppc64/boot/prom.h
@@ -0,0 +1,18 @@
+#ifndef _PPC_BOOT_PROM_H_
+#define _PPC_BOOT_PROM_H_
+
+extern int (*prom) (void *);
+extern void *chosen_handle;
+
+extern void *stdin;
+extern void *stdout;
+extern void *stderr;
+
+extern int write(void *handle, void *ptr, int nb);
+extern int read(void *handle, void *ptr, int nb);
+extern void exit(void);
+extern void pause(void);
+extern void *finddevice(const char *);
+extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
+extern int getprop(void *phandle, const char *name, void *buf, int buflen);
+#endif /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/ppc64/boot/stdio.h b/arch/ppc64/boot/stdio.h
new file mode 100644
index 00000000000..24bd3a8dee9
--- /dev/null
+++ b/arch/ppc64/boot/stdio.h
@@ -0,0 +1,16 @@
+#ifndef _PPC_BOOT_STDIO_H_
+#define _PPC_BOOT_STDIO_H_
+
+extern int printf(const char *fmt, ...);
+
+extern int sprintf(char *buf, const char *fmt, ...);
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+
+extern int putc(int c, void *f);
+extern int putchar(int c);
+extern int getchar(void);
+
+extern int fputs(char *str, void *f);
+
+#endif /* _PPC_BOOT_STDIO_H_ */
diff --git a/arch/ppc64/boot/string.S b/arch/ppc64/boot/string.S
index ba5f2d21c9e..7ade87ae771 100644
--- a/arch/ppc64/boot/string.S
+++ b/arch/ppc64/boot/string.S
@@ -9,7 +9,7 @@
* NOTE: this code runs in 32 bit mode and is packaged as ELF32.
*/
-#include <asm/ppc_asm.h>
+#include "ppc_asm.h"
.text
.globl strcpy
diff --git a/arch/ppc64/boot/string.h b/arch/ppc64/boot/string.h
new file mode 100644
index 00000000000..9289258bcbd
--- /dev/null
+++ b/arch/ppc64/boot/string.h
@@ -0,0 +1,16 @@
+#ifndef _PPC_BOOT_STRING_H_
+#define _PPC_BOOT_STRING_H_
+
+extern char *strcpy(char *dest, const char *src);
+extern char *strncpy(char *dest, const char *src, size_t n);
+extern char *strcat(char *dest, const char *src);
+extern int strcmp(const char *s1, const char *s2);
+extern size_t strlen(const char *s);
+extern size_t strnlen(const char *s, size_t count);
+
+extern void *memset(void *s, int c, size_t n);
+extern void *memmove(void *dest, const void *src, unsigned long n);
+extern void *memcpy(void *dest, const void *src, unsigned long n);
+extern int memcmp(const void *s1, const void *s2, size_t n);
+
+#endif /* _PPC_BOOT_STRING_H_ */
diff --git a/arch/ppc64/boot/zlib.c b/arch/ppc64/boot/zlib.c
index 78837e884b8..0d910cd2079 100644
--- a/arch/ppc64/boot/zlib.c
+++ b/arch/ppc64/boot/zlib.c
@@ -107,7 +107,7 @@ extern void *memcpy(void *, const void *, unsigned long);
/* Diagnostic functions */
#ifdef DEBUG_ZLIB
-# include <stdio.h>
+# include "stdio.h"
# ifndef verbose
# define verbose 0
# endif
diff --git a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig
index ab567741e80..fc83d933028 100644
--- a/arch/ppc64/configs/g5_defconfig
+++ b/arch/ppc64/configs/g5_defconfig
@@ -103,10 +103,10 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_GENERIC_HARDIRQS=y
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
diff --git a/arch/ppc64/configs/iSeries_defconfig b/arch/ppc64/configs/iSeries_defconfig
index 394ba18b58c..013d4e0e400 100644
--- a/arch/ppc64/configs/iSeries_defconfig
+++ b/arch/ppc64/configs/iSeries_defconfig
@@ -94,12 +94,11 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_GENERIC_HARDIRQS=y
-CONFIG_MSCHUNKS=y
CONFIG_LPARCFG=y
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
diff --git a/arch/ppc64/configs/maple_defconfig b/arch/ppc64/configs/maple_defconfig
index 2033fe663db..dd42892cd87 100644
--- a/arch/ppc64/configs/maple_defconfig
+++ b/arch/ppc64/configs/maple_defconfig
@@ -103,10 +103,10 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_GENERIC_HARDIRQS=y
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
diff --git a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig
index 297fd522948..29f7b80b0ef 100644
--- a/arch/ppc64/configs/pSeries_defconfig
+++ b/arch/ppc64/configs/pSeries_defconfig
@@ -112,10 +112,10 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_EEH=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_PPC_RTAS=y
diff --git a/arch/ppc64/defconfig b/arch/ppc64/defconfig
index c361e7727b7..7cb4750bb7a 100644
--- a/arch/ppc64/defconfig
+++ b/arch/ppc64/defconfig
@@ -114,10 +114,10 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
-CONFIG_HZ_100=y
-# CONFIG_HZ_250 is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
-CONFIG_HZ=100
+CONFIG_HZ=250
CONFIG_EEH=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_PPC_RTAS=y
diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
index 1c11031c838..0a9c23ca2f0 100644
--- a/arch/ppc64/kernel/LparData.c
+++ b/arch/ppc64/kernel/LparData.c
@@ -51,6 +51,17 @@ struct HvReleaseData hvReleaseData = {
0xf4, 0x4b, 0xf6, 0xf4 },
};
+/*
+ * The NACA. The first dword of the naca is required by the iSeries
+ * hypervisor to point to itVpdAreas. The hypervisor finds the NACA
+ * through the pointer in hvReleaseData.
+ */
+struct naca_struct naca = {
+ .xItVpdAreas = &itVpdAreas,
+ .xRamDisk = 0,
+ .xRamDiskSize = 0,
+};
+
extern void system_reset_iSeries(void);
extern void machine_check_iSeries(void);
extern void data_access_iSeries(void);
@@ -214,29 +225,3 @@ struct ItVpdAreas itVpdAreas = {
0,0
}
};
-
-struct msChunks msChunks;
-EXPORT_SYMBOL(msChunks);
-
-/* Depending on whether this is called from iSeries or pSeries setup
- * code, the location of the msChunks struct may or may not have
- * to be reloc'd, so we force the caller to do that for us by passing
- * in a pointer to the structure.
- */
-unsigned long
-msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size)
-{
- unsigned long offset = reloc_offset();
- struct msChunks *_msChunks = PTRRELOC(&msChunks);
-
- _msChunks->num_chunks = num_chunks;
- _msChunks->chunk_size = chunk_size;
- _msChunks->chunk_shift = __ilog2(chunk_size);
- _msChunks->chunk_mask = (1UL<<_msChunks->chunk_shift)-1;
-
- mem = _ALIGN(mem, sizeof(msChunks_entry));
- _msChunks->abs = (msChunks_entry *)(mem + offset);
- mem += num_chunks * sizeof(msChunks_entry);
-
- return mem;
-}
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index 2ecccb6b4f8..f4b3bfcc109 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -11,7 +11,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \
udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
ptrace32.o signal32.o rtc.o init_task.o \
lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
- iommu.o sysfs.o vdso.o pmc.o
+ iommu.o sysfs.o vdso.o pmc.o firmware.o
obj-y += vdso32/ vdso64/
obj-$(CONFIG_PPC_OF) += of_device.o
@@ -50,7 +50,10 @@ obj-$(CONFIG_LPARCFG) += lparcfg.o
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_HVCS) += hvcserver.o
-obj-$(CONFIG_IBMVIO) += vio.o
+
+vio-obj-$(CONFIG_PPC_PSERIES) += pSeries_vio.o
+vio-obj-$(CONFIG_PPC_ISERIES) += iSeries_vio.o
+obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y)
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_MPIC) += mpic.o
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
index abb9e5b5da0..17e35d0fed0 100644
--- a/arch/ppc64/kernel/asm-offsets.c
+++ b/arch/ppc64/kernel/asm-offsets.c
@@ -94,7 +94,8 @@ int main(void)
DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
#ifdef CONFIG_HUGETLB_PAGE
- DEFINE(PACAHTLBSEGS, offsetof(struct paca_struct, context.htlb_segs));
+ DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
+ DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
#endif /* CONFIG_HUGETLB_PAGE */
DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
index 77cec42f952..4847f2ac8c9 100644
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -5,7 +5,7 @@
*
* Modifications for ppc64:
* Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
- *
+ *
* 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
@@ -60,7 +60,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Power3+ */
.pvr_mask = 0xffff0000,
@@ -73,7 +72,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Northstar */
.pvr_mask = 0xffff0000,
@@ -86,7 +84,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Pulsar */
.pvr_mask = 0xffff0000,
@@ -99,7 +96,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* I-star */
.pvr_mask = 0xffff0000,
@@ -112,7 +108,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* S-star */
.pvr_mask = 0xffff0000,
@@ -125,7 +120,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power3,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Power4 */
.pvr_mask = 0xffff0000,
@@ -138,7 +132,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power4,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Power4+ */
.pvr_mask = 0xffff0000,
@@ -151,7 +144,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power4,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* PPC970 */
.pvr_mask = 0xffff0000,
@@ -166,7 +158,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_ppc970,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* PPC970FX */
.pvr_mask = 0xffff0000,
@@ -181,7 +172,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_ppc970,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* PPC970MP */
.pvr_mask = 0xffff0000,
@@ -196,7 +186,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_ppc970,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Power5 */
.pvr_mask = 0xffff0000,
@@ -211,7 +200,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power4,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* Power5 */
.pvr_mask = 0xffff0000,
@@ -226,7 +214,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power4,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* BE DD1.x */
.pvr_mask = 0xffff0000,
@@ -241,7 +228,6 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_be,
- .firmware_features = COMMON_PPC64_FW,
},
{ /* default match */
.pvr_mask = 0x00000000,
@@ -254,29 +240,5 @@ struct cpu_spec cpu_specs[] = {
.icache_bsize = 128,
.dcache_bsize = 128,
.cpu_setup = __setup_cpu_power4,
- .firmware_features = COMMON_PPC64_FW,
}
};
-
-firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
- {FW_FEATURE_PFT, "hcall-pft"},
- {FW_FEATURE_TCE, "hcall-tce"},
- {FW_FEATURE_SPRG0, "hcall-sprg0"},
- {FW_FEATURE_DABR, "hcall-dabr"},
- {FW_FEATURE_COPY, "hcall-copy"},
- {FW_FEATURE_ASR, "hcall-asr"},
- {FW_FEATURE_DEBUG, "hcall-debug"},
- {FW_FEATURE_PERF, "hcall-perf"},
- {FW_FEATURE_DUMP, "hcall-dump"},
- {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
- {FW_FEATURE_MIGRATE, "hcall-migrate"},
- {FW_FEATURE_PERFMON, "hcall-perfmon"},
- {FW_FEATURE_CRQ, "hcall-crq"},
- {FW_FEATURE_VIO, "hcall-vio"},
- {FW_FEATURE_RDMA, "hcall-rdma"},
- {FW_FEATURE_LLAN, "hcall-lLAN"},
- {FW_FEATURE_BULK, "hcall-bulk"},
- {FW_FEATURE_XDABR, "hcall-xdabr"},
- {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
- {FW_FEATURE_SPLPAR, "hcall-splpar"},
-};
diff --git a/arch/ppc64/kernel/firmware.c b/arch/ppc64/kernel/firmware.c
new file mode 100644
index 00000000000..d8432c0fb27
--- /dev/null
+++ b/arch/ppc64/kernel/firmware.c
@@ -0,0 +1,47 @@
+/*
+ * arch/ppc64/kernel/firmware.c
+ *
+ * Extracted from cputable.c
+ *
+ * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * Modifications for ppc64:
+ * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
+ * Copyright (C) 2005 Stephen Rothwell, 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/config.h>
+
+#include <asm/firmware.h>
+
+unsigned long ppc64_firmware_features;
+
+#ifdef CONFIG_PPC_PSERIES
+firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
+ {FW_FEATURE_PFT, "hcall-pft"},
+ {FW_FEATURE_TCE, "hcall-tce"},
+ {FW_FEATURE_SPRG0, "hcall-sprg0"},
+ {FW_FEATURE_DABR, "hcall-dabr"},
+ {FW_FEATURE_COPY, "hcall-copy"},
+ {FW_FEATURE_ASR, "hcall-asr"},
+ {FW_FEATURE_DEBUG, "hcall-debug"},
+ {FW_FEATURE_PERF, "hcall-perf"},
+ {FW_FEATURE_DUMP, "hcall-dump"},
+ {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
+ {FW_FEATURE_MIGRATE, "hcall-migrate"},
+ {FW_FEATURE_PERFMON, "hcall-perfmon"},
+ {FW_FEATURE_CRQ, "hcall-crq"},
+ {FW_FEATURE_VIO, "hcall-vio"},
+ {FW_FEATURE_RDMA, "hcall-rdma"},
+ {FW_FEATURE_LLAN, "hcall-lLAN"},
+ {FW_FEATURE_BULK, "hcall-bulk"},
+ {FW_FEATURE_XDABR, "hcall-xdabr"},
+ {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
+ {FW_FEATURE_SPLPAR, "hcall-splpar"},
+};
+#endif
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index accaa052d31..03695977562 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -23,14 +23,11 @@
* 2 of the License, or (at your option) any later version.
*/
-#define SECONDARY_PROCESSORS
-
#include <linux/config.h>
#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/mmu.h>
-#include <asm/naca.h>
#include <asm/systemcfg.h>
#include <asm/ppc_asm.h>
#include <asm/offsets.h>
@@ -45,18 +42,13 @@
#endif
/*
- * hcall interface to pSeries LPAR
- */
-#define H_SET_ASR 0x30
-
-/*
* We layout physical memory as follows:
* 0x0000 - 0x00ff : Secondary processor spin code
* 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x3fff : Interrupt support
- * 0x4000 - 0x4fff : NACA
- * 0x6000 : iSeries and common interrupt prologs
- * 0x9000 - 0x9fff : Initial segment table
+ * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs
+ * 0x6000 - 0x6fff : Initial (CPU0) segment table
+ * 0x7000 - 0x7fff : FWNMI data area
+ * 0x8000 - : Early init and support code
*/
/*
@@ -94,6 +86,7 @@ END_FTR_SECTION(0, 1)
/* Catch branch to 0 in real mode */
trap
+
#ifdef CONFIG_PPC_ISERIES
/*
* At offset 0x20, there is a pointer to iSeries LPAR data.
@@ -103,12 +96,12 @@ END_FTR_SECTION(0, 1)
.llong hvReleaseData-KERNELBASE
/*
- * At offset 0x28 and 0x30 are offsets to the msChunks
+ * At offset 0x28 and 0x30 are offsets to the mschunks_map
* array (used by the iSeries LPAR debugger to do translation
* between physical addresses and absolute addresses) and
* to the pidhash table (also used by the debugger)
*/
- .llong msChunks-KERNELBASE
+ .llong mschunks_map-KERNELBASE
.llong 0 /* pidhash-KERNELBASE SFRXXX */
/* Offset 0x38 - Pointer to start of embedded System.map */
@@ -120,7 +113,7 @@ embedded_sysmap_start:
embedded_sysmap_end:
.llong 0
-#else /* CONFIG_PPC_ISERIES */
+#endif /* CONFIG_PPC_ISERIES */
/* Secondary processors spin on this value until it goes to 1. */
.globl __secondary_hold_spinloop
@@ -155,7 +148,7 @@ _GLOBAL(__secondary_hold)
std r24,__secondary_hold_acknowledge@l(0)
sync
- /* All secondary cpu's wait here until told to start. */
+ /* All secondary cpus wait here until told to start. */
100: ld r4,__secondary_hold_spinloop@l(0)
cmpdi 0,r4,1
bne 100b
@@ -170,7 +163,6 @@ _GLOBAL(__secondary_hold)
BUG_OPCODE
#endif
#endif
-#endif
/* This value is used to mark exception frames on the stack. */
.section ".toc","aw"
@@ -502,33 +494,37 @@ system_call_pSeries:
STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
+ . = 0x3000
+
+/*** pSeries interrupt support ***/
+
/* moved from 0xf00 */
- STD_EXCEPTION_PSERIES(0x3000, performance_monitor)
+ STD_EXCEPTION_PSERIES(., performance_monitor)
- . = 0x3100
+ .align 7
_GLOBAL(do_stab_bolted_pSeries)
mtcrf 0x80,r12
mfspr r12,SPRG2
EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
-
- /* Space for the naca. Architected to be located at real address
- * NACA_PHYS_ADDR. Various tools rely on this location being fixed.
- * The first dword of the naca is required by iSeries LPAR to
- * point to itVpdAreas. On pSeries native, this value is not used.
- */
- . = NACA_PHYS_ADDR
- .globl __end_interrupts
-__end_interrupts:
-#ifdef CONFIG_PPC_ISERIES
- .globl naca
-naca:
- .llong itVpdAreas
- .llong 0 /* xRamDisk */
- .llong 0 /* xRamDiskSize */
+/*
+ * Vectors for the FWNMI option. Share common code.
+ */
+ .globl system_reset_fwnmi
+system_reset_fwnmi:
+ HMT_MEDIUM
+ mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
- . = 0x6100
+ .globl machine_check_fwnmi
+machine_check_fwnmi:
+ HMT_MEDIUM
+ mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+#ifdef CONFIG_PPC_ISERIES
/*** ISeries-LPAR interrupt handlers ***/
STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC)
@@ -626,9 +622,7 @@ system_reset_iSeries:
cmpwi 0,r23,0
beq iSeries_secondary_smp_loop /* Loop until told to go */
-#ifdef SECONDARY_PROCESSORS
bne .__secondary_start /* Loop until told to go */
-#endif
iSeries_secondary_smp_loop:
/* Let the Hypervisor know we are alive */
/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
@@ -671,51 +665,8 @@ hardware_interrupt_iSeries_masked:
ld r13,PACA_EXGEN+EX_R13(r13)
rfid
b . /* prevent speculative execution */
-#endif
-
-/*
- * Data area reserved for FWNMI option.
- */
- .= 0x7000
- .globl fwnmi_data_area
-fwnmi_data_area:
-
-#ifdef CONFIG_PPC_ISERIES
- . = LPARMAP_PHYS
-#include "lparmap.s"
#endif /* CONFIG_PPC_ISERIES */
-/*
- * Vectors for the FWNMI option. Share common code.
- */
- . = 0x8000
- .globl system_reset_fwnmi
-system_reset_fwnmi:
- HMT_MEDIUM
- mtspr SPRG1,r13 /* save r13 */
- RUNLATCH_ON(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
- .globl machine_check_fwnmi
-machine_check_fwnmi:
- HMT_MEDIUM
- mtspr SPRG1,r13 /* save r13 */
- RUNLATCH_ON(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
-
- /*
- * Space for the initial segment table
- * For LPAR, the hypervisor must fill in at least one entry
- * before we get control (with relocate on)
- */
- . = STAB0_PHYS_ADDR
- .globl __start_stab
-__start_stab:
-
- . = (STAB0_PHYS_ADDR + PAGE_SIZE)
- .globl __end_stab
-__end_stab:
-
-
/*** Common interrupt handlers ***/
STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception)
@@ -752,8 +703,8 @@ machine_check_common:
* R9 contains the saved CR, r13 points to the paca,
* r10 contains the (bad) kernel stack pointer,
* r11 and r12 contain the saved SRR0 and SRR1.
- * We switch to using the paca guard page as an emergency stack,
- * save the registers there, and call kernel_bad_stack(), which panics.
+ * We switch to using an emergency stack, save the registers there,
+ * and call kernel_bad_stack(), which panics.
*/
bad_stack:
ld r1,PACAEMERGSP(r13)
@@ -906,6 +857,62 @@ fp_unavailable_common:
bl .kernel_fp_unavailable_exception
BUG_OPCODE
+/*
+ * load_up_fpu(unused, unused, tsk)
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * On SMP we know the fpu is free, since we give it up every
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
+ */
+_STATIC(load_up_fpu)
+ mfmsr r5 /* grab the current MSR */
+ ori r5,r5,MSR_FP
+ mtmsrd r5 /* enable use of fpu now */
+ isync
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another. Instead we call giveup_fpu in switch_to.
+ *
+ */
+#ifndef CONFIG_SMP
+ ld r3,last_task_used_math@got(r2)
+ ld r4,0(r3)
+ cmpdi 0,r4,0
+ beq 1f
+ /* Save FP state to last_task_used_math's THREAD struct */
+ addi r4,r4,THREAD
+ SAVE_32FPRS(0, r4)
+ mffs fr0
+ stfd fr0,THREAD_FPSCR(r4)
+ /* Disable FP for last_task_used_math */
+ ld r5,PT_REGS(r4)
+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r6,MSR_FP|MSR_FE0|MSR_FE1
+ andc r4,r4,r6
+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+ /* enable use of FP after return */
+ ld r4,PACACURRENT(r13)
+ addi r5,r4,THREAD /* Get THREAD */
+ ld r4,THREAD_FPEXC_MODE(r5)
+ ori r12,r12,MSR_FP
+ or r12,r12,r4
+ std r12,_MSR(r1)
+ lfd fr0,THREAD_FPSCR(r5)
+ mtfsf 0xff,fr0
+ REST_32FPRS(0, r5)
+#ifndef CONFIG_SMP
+ /* Update last_task_used_math to 'current' */
+ subi r4,r5,THREAD /* Back to 'current' */
+ std r4,0(r3)
+#endif /* CONFIG_SMP */
+ /* restore registers and return */
+ b fast_exception_return
+
.align 7
.globl altivec_unavailable_common
altivec_unavailable_common:
@@ -921,6 +928,80 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
bl .altivec_unavailable_exception
b .ret_from_except
+#ifdef CONFIG_ALTIVEC
+/*
+ * load_up_altivec(unused, unused, tsk)
+ * Disable VMX for the task which had it previously,
+ * and save its vector registers in its thread_struct.
+ * Enables the VMX for use in the kernel on return.
+ * On SMP we know the VMX is free, since we give it up every
+ * switch (ie, no lazy save of the vector registers).
+ * On entry: r13 == 'current' && last_task_used_altivec != 'current'
+ */
+_STATIC(load_up_altivec)
+ mfmsr r5 /* grab the current MSR */
+ oris r5,r5,MSR_VEC@h
+ mtmsrd r5 /* enable use of VMX now */
+ isync
+
+/*
+ * For SMP, we don't do lazy VMX switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another. Instead we call giveup_altvec in switch_to.
+ * VRSAVE isn't dealt with here, that is done in the normal context
+ * switch code. Note that we could rely on vrsave value to eventually
+ * avoid saving all of the VREGs here...
+ */
+#ifndef CONFIG_SMP
+ ld r3,last_task_used_altivec@got(r2)
+ ld r4,0(r3)
+ cmpdi 0,r4,0
+ beq 1f
+ /* Save VMX state to last_task_used_altivec's THREAD struct */
+ addi r4,r4,THREAD
+ SAVE_32VRS(0,r5,r4)
+ mfvscr vr0
+ li r10,THREAD_VSCR
+ stvx vr0,r10,r4
+ /* Disable VMX for last_task_used_altivec */
+ ld r5,PT_REGS(r4)
+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ lis r6,MSR_VEC@h
+ andc r4,r4,r6
+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+ /* Hack: if we get an altivec unavailable trap with VRSAVE
+ * set to all zeros, we assume this is a broken application
+ * that fails to set it properly, and thus we switch it to
+ * all 1's
+ */
+ mfspr r4,SPRN_VRSAVE
+ cmpdi 0,r4,0
+ bne+ 1f
+ li r4,-1
+ mtspr SPRN_VRSAVE,r4
+1:
+ /* enable use of VMX after return */
+ ld r4,PACACURRENT(r13)
+ addi r5,r4,THREAD /* Get THREAD */
+ oris r12,r12,MSR_VEC@h
+ std r12,_MSR(r1)
+ li r4,1
+ li r10,THREAD_VSCR
+ stw r4,THREAD_USED_VR(r5)
+ lvx vr0,r10,r5
+ mtvscr vr0
+ REST_32VRS(0,r4,r5)
+#ifndef CONFIG_SMP
+ /* Update last_task_used_math to 'current' */
+ subi r4,r5,THREAD /* Back to 'current' */
+ std r4,0(r3)
+#endif /* CONFIG_SMP */
+ /* restore registers and return */
+ b fast_exception_return
+#endif /* CONFIG_ALTIVEC */
+
/*
* Hash table stuff
*/
@@ -1167,6 +1248,42 @@ unrecov_slb:
bl .unrecoverable_exception
b 1b
+/*
+ * Space for CPU0's segment table.
+ *
+ * On iSeries, the hypervisor must fill in at least one entry before
+ * we get control (with relocate on). The address is give to the hv
+ * as a page number (see xLparMap in LparData.c), so this must be at a
+ * fixed address (the linker can't compute (u64)&initial_stab >>
+ * PAGE_SHIFT).
+ */
+ . = STAB0_PHYS_ADDR /* 0x6000 */
+ .globl initial_stab
+initial_stab:
+ .space 4096
+
+/*
+ * Data area reserved for FWNMI option.
+ * This address (0x7000) is fixed by the RPA.
+ */
+ .= 0x7000
+ .globl fwnmi_data_area
+fwnmi_data_area:
+
+ /* 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.
@@ -1200,7 +1317,7 @@ _GLOBAL(pSeries_secondary_smp_init)
b .kexec_wait /* next kernel might do better */
2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */
- /* From now on, r24 is expected to be logica cpuid */
+ /* From now on, r24 is expected to be logical cpuid */
mr r24,r5
3: HMT_LOW
lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
@@ -1213,10 +1330,8 @@ _GLOBAL(pSeries_secondary_smp_init)
cmpwi 0,r23,0
#ifdef CONFIG_SMP
-#ifdef SECONDARY_PROCESSORS
bne .__secondary_start
#endif
-#endif
b 3b /* Loop until told to go */
#ifdef CONFIG_PPC_ISERIES
@@ -1430,228 +1545,6 @@ _GLOBAL(copy_and_flush)
.align 8
copy_to_here:
-/*
- * load_up_fpu(unused, unused, tsk)
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- * On SMP we know the fpu is free, since we give it up every
- * switch (ie, no lazy save of the FP registers).
- * On entry: r13 == 'current' && last_task_used_math != 'current'
- */
-_STATIC(load_up_fpu)
- mfmsr r5 /* grab the current MSR */
- ori r5,r5,MSR_FP
- mtmsrd r5 /* enable use of fpu now */
- isync
-/*
- * For SMP, we don't do lazy FPU switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_fpu in switch_to.
- *
- */
-#ifndef CONFIG_SMP
- ld r3,last_task_used_math@got(r2)
- ld r4,0(r3)
- cmpdi 0,r4,0
- beq 1f
- /* Save FP state to last_task_used_math's THREAD struct */
- addi r4,r4,THREAD
- SAVE_32FPRS(0, r4)
- mffs fr0
- stfd fr0,THREAD_FPSCR(r4)
- /* Disable FP for last_task_used_math */
- ld r5,PT_REGS(r4)
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r6,MSR_FP|MSR_FE0|MSR_FE1
- andc r4,r4,r6
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
- /* enable use of FP after return */
- ld r4,PACACURRENT(r13)
- addi r5,r4,THREAD /* Get THREAD */
- ld r4,THREAD_FPEXC_MODE(r5)
- ori r12,r12,MSR_FP
- or r12,r12,r4
- std r12,_MSR(r1)
- lfd fr0,THREAD_FPSCR(r5)
- mtfsf 0xff,fr0
- REST_32FPRS(0, r5)
-#ifndef CONFIG_SMP
- /* Update last_task_used_math to 'current' */
- subi r4,r5,THREAD /* Back to 'current' */
- std r4,0(r3)
-#endif /* CONFIG_SMP */
- /* restore registers and return */
- b fast_exception_return
-
-/*
- * disable_kernel_fp()
- * Disable the FPU.
- */
-_GLOBAL(disable_kernel_fp)
- mfmsr r3
- rldicl r0,r3,(63-MSR_FP_LG),1
- rldicl r3,r0,(MSR_FP_LG+1),0
- mtmsrd r3 /* disable use of fpu now */
- isync
- blr
-
-/*
- * giveup_fpu(tsk)
- * Disable FP for the task given as the argument,
- * and save the floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- */
-_GLOBAL(giveup_fpu)
- mfmsr r5
- ori r5,r5,MSR_FP
- mtmsrd r5 /* enable use of fpu now */
- isync
- cmpdi 0,r3,0
- beqlr- /* if no previous owner, done */
- addi r3,r3,THREAD /* want THREAD of task */
- ld r5,PT_REGS(r3)
- cmpdi 0,r5,0
- SAVE_32FPRS(0, r3)
- mffs fr0
- stfd fr0,THREAD_FPSCR(r3)
- beq 1f
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r3,MSR_FP|MSR_FE0|MSR_FE1
- andc r4,r4,r3 /* disable FP for previous task */
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
- li r5,0
- ld r4,last_task_used_math@got(r2)
- std r5,0(r4)
-#endif /* CONFIG_SMP */
- blr
-
-
-#ifdef CONFIG_ALTIVEC
-
-/*
- * load_up_altivec(unused, unused, tsk)
- * Disable VMX for the task which had it previously,
- * and save its vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- * On SMP we know the VMX is free, since we give it up every
- * switch (ie, no lazy save of the vector registers).
- * On entry: r13 == 'current' && last_task_used_altivec != 'current'
- */
-_STATIC(load_up_altivec)
- mfmsr r5 /* grab the current MSR */
- oris r5,r5,MSR_VEC@h
- mtmsrd r5 /* enable use of VMX now */
- isync
-
-/*
- * For SMP, we don't do lazy VMX switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_altvec in switch_to.
- * VRSAVE isn't dealt with here, that is done in the normal context
- * switch code. Note that we could rely on vrsave value to eventually
- * avoid saving all of the VREGs here...
- */
-#ifndef CONFIG_SMP
- ld r3,last_task_used_altivec@got(r2)
- ld r4,0(r3)
- cmpdi 0,r4,0
- beq 1f
- /* Save VMX state to last_task_used_altivec's THREAD struct */
- addi r4,r4,THREAD
- SAVE_32VRS(0,r5,r4)
- mfvscr vr0
- li r10,THREAD_VSCR
- stvx vr0,r10,r4
- /* Disable VMX for last_task_used_altivec */
- ld r5,PT_REGS(r4)
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r6,MSR_VEC@h
- andc r4,r4,r6
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
- /* Hack: if we get an altivec unavailable trap with VRSAVE
- * set to all zeros, we assume this is a broken application
- * that fails to set it properly, and thus we switch it to
- * all 1's
- */
- mfspr r4,SPRN_VRSAVE
- cmpdi 0,r4,0
- bne+ 1f
- li r4,-1
- mtspr SPRN_VRSAVE,r4
-1:
- /* enable use of VMX after return */
- ld r4,PACACURRENT(r13)
- addi r5,r4,THREAD /* Get THREAD */
- oris r12,r12,MSR_VEC@h
- std r12,_MSR(r1)
- li r4,1
- li r10,THREAD_VSCR
- stw r4,THREAD_USED_VR(r5)
- lvx vr0,r10,r5
- mtvscr vr0
- REST_32VRS(0,r4,r5)
-#ifndef CONFIG_SMP
- /* Update last_task_used_math to 'current' */
- subi r4,r5,THREAD /* Back to 'current' */
- std r4,0(r3)
-#endif /* CONFIG_SMP */
- /* restore registers and return */
- b fast_exception_return
-
-/*
- * disable_kernel_altivec()
- * Disable the VMX.
- */
-_GLOBAL(disable_kernel_altivec)
- mfmsr r3
- rldicl r0,r3,(63-MSR_VEC_LG),1
- rldicl r3,r0,(MSR_VEC_LG+1),0
- mtmsrd r3 /* disable use of VMX now */
- isync
- blr
-
-/*
- * giveup_altivec(tsk)
- * Disable VMX for the task given as the argument,
- * and save the vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- */
-_GLOBAL(giveup_altivec)
- mfmsr r5
- oris r5,r5,MSR_VEC@h
- mtmsrd r5 /* enable use of VMX now */
- isync
- cmpdi 0,r3,0
- beqlr- /* if no previous owner, done */
- addi r3,r3,THREAD /* want THREAD of task */
- ld r5,PT_REGS(r3)
- cmpdi 0,r5,0
- SAVE_32VRS(0,r4,r3)
- mfvscr vr0
- li r4,THREAD_VSCR
- stvx vr0,r4,r3
- beq 1f
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r3,MSR_VEC@h
- andc r4,r4,r3 /* disable FP for previous task */
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
- li r5,0
- ld r4,last_task_used_altivec@got(r2)
- std r5,0(r4)
-#endif /* CONFIG_SMP */
- blr
-
-#endif /* CONFIG_ALTIVEC */
-
#ifdef CONFIG_SMP
#ifdef CONFIG_PPC_PMAC
/*
@@ -2002,9 +1895,6 @@ _STATIC(start_here_common)
bl .start_kernel
-_GLOBAL(__setup_cpu_power3)
- blr
-
_GLOBAL(hmt_init)
#ifdef CONFIG_HMT
LOADADDR(r5, hmt_thread_data)
@@ -2095,20 +1985,19 @@ _GLOBAL(smp_release_cpus)
/*
* We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
+ * This stuff goes at the beginning of the bss, which is page-aligned.
*/
- .data
+ .section ".bss"
+
.align 12
- .globl sdata
-sdata:
+
.globl empty_zero_page
empty_zero_page:
- .space 4096
+ .space PAGE_SIZE
.globl swapper_pg_dir
swapper_pg_dir:
- .space 4096
+ .space PAGE_SIZE
/*
* This space gets a copy of optional info passed to us by the bootstrap
diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c
index b0250ae4a72..2192055a90a 100644
--- a/arch/ppc64/kernel/iSeries_htab.c
+++ b/arch/ppc64/kernel/iSeries_htab.c
@@ -41,6 +41,7 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long prpn, unsigned long vflags,
unsigned long rflags)
{
+ unsigned long arpn;
long slot;
hpte_t lhpte;
int secondary = 0;
@@ -70,8 +71,10 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
slot &= 0x7fffffffffffffff;
}
+ arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT;
+
lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
- lhpte.r = (physRpn_to_absRpn(prpn) << HPTE_R_RPN_SHIFT) | rflags;
+ lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
/* Now fill in the actual HPTE */
HvCallHpt_addValidate(slot, secondary, &lhpte);
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
index a649edbb23b..3ffefbbc662 100644
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -39,6 +39,7 @@
#include <asm/cputable.h>
#include <asm/sections.h>
#include <asm/iommu.h>
+#include <asm/firmware.h>
#include <asm/time.h>
#include "iSeries_setup.h"
@@ -314,6 +315,8 @@ static void __init iSeries_init_early(void)
DBG(" -> iSeries_init_early()\n");
+ ppc64_firmware_features = FW_FEATURE_ISERIES;
+
ppcdbg_initialize();
#if defined(CONFIG_BLK_DEV_INITRD)
@@ -412,6 +415,22 @@ static void __init iSeries_init_early(void)
DBG(" <- iSeries_init_early()\n");
}
+struct mschunks_map mschunks_map = {
+ /* XXX We don't use these, but Piranha might need them. */
+ .chunk_size = MSCHUNKS_CHUNK_SIZE,
+ .chunk_shift = MSCHUNKS_CHUNK_SHIFT,
+ .chunk_mask = MSCHUNKS_OFFSET_MASK,
+};
+EXPORT_SYMBOL(mschunks_map);
+
+void mschunks_alloc(unsigned long num_chunks)
+{
+ klimit = _ALIGN(klimit, sizeof(u32));
+ mschunks_map.mapping = (u32 *)klimit;
+ klimit += num_chunks * sizeof(u32);
+ mschunks_map.num_chunks = num_chunks;
+}
+
/*
* The iSeries may have very large memories ( > 128 GB ) and a partition
* may get memory in "chunks" that may be anywhere in the 2**52 real
@@ -449,7 +468,7 @@ static void __init build_iSeries_Memory_Map(void)
/* Chunk size on iSeries is 256K bytes */
totalChunks = (u32)HvLpConfig_getMsChunks();
- klimit = msChunks_alloc(klimit, totalChunks, 1UL << 18);
+ mschunks_alloc(totalChunks);
/*
* Get absolute address of our load area
@@ -486,7 +505,7 @@ static void __init build_iSeries_Memory_Map(void)
printk("Load area size %dK\n", loadAreaSize * 256);
for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
- msChunks.abs[nextPhysChunk] =
+ mschunks_map.mapping[nextPhysChunk] =
loadAreaFirstChunk + nextPhysChunk;
/*
@@ -495,7 +514,7 @@ static void __init build_iSeries_Memory_Map(void)
*/
hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
hptSizePages = (u32)HvCallHpt_getHptPages();
- hptSizeChunks = hptSizePages >> (msChunks.chunk_shift - PAGE_SHIFT);
+ hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT);
hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
printk("HPT absolute addr = %016lx, size = %dK\n",
@@ -552,7 +571,8 @@ static void __init build_iSeries_Memory_Map(void)
(absChunk > hptLastChunk)) &&
((absChunk < loadAreaFirstChunk) ||
(absChunk > loadAreaLastChunk))) {
- msChunks.abs[nextPhysChunk] = absChunk;
+ mschunks_map.mapping[nextPhysChunk] =
+ absChunk;
++nextPhysChunk;
}
}
@@ -944,6 +964,8 @@ void __init iSeries_early_setup(void)
ppc_md.calibrate_decr = iSeries_calibrate_decr;
ppc_md.progress = iSeries_progress;
+ /* XXX Implement enable_pmcs for iSeries */
+
if (get_paca()->lppaca.shared_proc) {
ppc_md.idle_loop = iseries_shared_idle;
printk(KERN_INFO "Using shared processor idle loop\n");
diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c
new file mode 100644
index 00000000000..6b754b0c834
--- /dev/null
+++ b/arch/ppc64/kernel/iSeries_vio.c
@@ -0,0 +1,155 @@
+/*
+ * IBM PowerPC iSeries Virtual I/O Infrastructure Support.
+ *
+ * Copyright (c) 2005 Stephen Rothwell, IBM 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/vio.h>
+#include <asm/iommu.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/iSeries/vio.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/iSeries/HvCallXm.h>
+
+struct device *iSeries_vio_dev = &vio_bus_device.dev;
+EXPORT_SYMBOL(iSeries_vio_dev);
+
+static struct iommu_table veth_iommu_table;
+static struct iommu_table vio_iommu_table;
+
+static void __init iommu_vio_init(void)
+{
+ struct iommu_table *t;
+ struct iommu_table_cb cb;
+ unsigned long cbp;
+ unsigned long itc_entries;
+
+ cb.itc_busno = 255; /* Bus 255 is the virtual bus */
+ cb.itc_virtbus = 0xff; /* Ask for virtual bus */
+
+ cbp = virt_to_abs(&cb);
+ HvCallXm_getTceTableParms(cbp);
+
+ itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
+ veth_iommu_table.it_size = itc_entries / 2;
+ veth_iommu_table.it_busno = cb.itc_busno;
+ veth_iommu_table.it_offset = cb.itc_offset;
+ veth_iommu_table.it_index = cb.itc_index;
+ veth_iommu_table.it_type = TCE_VB;
+ veth_iommu_table.it_blocksize = 1;
+
+ t = iommu_init_table(&veth_iommu_table);
+
+ if (!t)
+ printk("Virtual Bus VETH TCE table failed.\n");
+
+ vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size;
+ vio_iommu_table.it_busno = cb.itc_busno;
+ vio_iommu_table.it_offset = cb.itc_offset +
+ veth_iommu_table.it_size;
+ vio_iommu_table.it_index = cb.itc_index;
+ vio_iommu_table.it_type = TCE_VB;
+ vio_iommu_table.it_blocksize = 1;
+
+ t = iommu_init_table(&vio_iommu_table);
+
+ if (!t)
+ printk("Virtual Bus VIO TCE table failed.\n");
+}
+
+/**
+ * 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,
+ uint32_t unit_num)
+{
+ struct vio_dev *viodev;
+
+ /* allocate a vio_dev for this device */
+ viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
+ if (!viodev)
+ return NULL;
+ memset(viodev, 0, sizeof(struct vio_dev));
+
+ snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
+
+ 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)
+{
+ HvLpIndexMap vlan_map;
+ struct vio_dev *viodev;
+ int i;
+
+ /* there is only one of each of these */
+ vio_register_device_iseries("viocons", 0);
+ vio_register_device_iseries("vscsi", 0);
+
+ vlan_map = HvLpConfig_getVirtualLanIndexMap();
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+ if ((vlan_map & (0x8000 >> i)) == 0)
+ continue;
+ viodev = vio_register_device_iseries("vlan", i);
+ /* veth is special and has it own iommu_table */
+ viodev->iommu_table = &veth_iommu_table;
+ }
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
+ vio_register_device_iseries("viodasd", i);
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
+ vio_register_device_iseries("viocd", i);
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
+ vio_register_device_iseries("viotape", i);
+}
+
+/**
+ * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
+ * vio_device_id
+ */
+static int vio_match_device_iseries(const struct vio_device_id *id,
+ const struct vio_dev *dev)
+{
+ 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
+ */
+static int __init vio_bus_init_iseries(void)
+{
+ int err;
+
+ err = vio_bus_init(&vio_bus_ops_iseries);
+ if (err == 0) {
+ iommu_vio_init();
+ vio_bus_device.iommu_table = &vio_iommu_table;
+ iSeries_vio_dev = &vio_bus_device.dev;
+ probe_bus_iseries();
+ }
+ return err;
+}
+
+__initcall(vio_bus_init_iseries);
diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c
index d6c6bd03d2a..5adaca2ddc9 100644
--- a/arch/ppc64/kernel/lmb.c
+++ b/arch/ppc64/kernel/lmb.c
@@ -28,33 +28,28 @@ void lmb_dump_all(void)
{
#ifdef DEBUG
unsigned long i;
- struct lmb *_lmb = &lmb;
udbg_printf("lmb_dump_all:\n");
udbg_printf(" memory.cnt = 0x%lx\n",
- _lmb->memory.cnt);
+ lmb.memory.cnt);
udbg_printf(" memory.size = 0x%lx\n",
- _lmb->memory.size);
- for (i=0; i < _lmb->memory.cnt ;i++) {
+ lmb.memory.size);
+ for (i=0; i < lmb.memory.cnt ;i++) {
udbg_printf(" memory.region[0x%x].base = 0x%lx\n",
- i, _lmb->memory.region[i].base);
- udbg_printf(" .physbase = 0x%lx\n",
- _lmb->memory.region[i].physbase);
+ i, lmb.memory.region[i].base);
udbg_printf(" .size = 0x%lx\n",
- _lmb->memory.region[i].size);
+ lmb.memory.region[i].size);
}
udbg_printf("\n reserved.cnt = 0x%lx\n",
- _lmb->reserved.cnt);
+ lmb.reserved.cnt);
udbg_printf(" reserved.size = 0x%lx\n",
- _lmb->reserved.size);
- for (i=0; i < _lmb->reserved.cnt ;i++) {
+ lmb.reserved.size);
+ for (i=0; i < lmb.reserved.cnt ;i++) {
udbg_printf(" reserved.region[0x%x].base = 0x%lx\n",
- i, _lmb->reserved.region[i].base);
- udbg_printf(" .physbase = 0x%lx\n",
- _lmb->reserved.region[i].physbase);
+ i, lmb.reserved.region[i].base);
udbg_printf(" .size = 0x%lx\n",
- _lmb->reserved.region[i].size);
+ lmb.reserved.region[i].size);
}
#endif /* DEBUG */
}
@@ -98,7 +93,6 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
rgn->region[r1].size += rgn->region[r2].size;
for (i=r2; i < rgn->cnt-1; i++) {
rgn->region[i].base = rgn->region[i+1].base;
- rgn->region[i].physbase = rgn->region[i+1].physbase;
rgn->region[i].size = rgn->region[i+1].size;
}
rgn->cnt--;
@@ -108,49 +102,29 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2)
void __init
lmb_init(void)
{
- struct lmb *_lmb = &lmb;
-
/* Create a dummy zero size LMB which will get coalesced away later.
* This simplifies the lmb_add() code below...
*/
- _lmb->memory.region[0].base = 0;
- _lmb->memory.region[0].size = 0;
- _lmb->memory.cnt = 1;
+ lmb.memory.region[0].base = 0;
+ lmb.memory.region[0].size = 0;
+ lmb.memory.cnt = 1;
/* Ditto. */
- _lmb->reserved.region[0].base = 0;
- _lmb->reserved.region[0].size = 0;
- _lmb->reserved.cnt = 1;
+ lmb.reserved.region[0].base = 0;
+ lmb.reserved.region[0].size = 0;
+ lmb.reserved.cnt = 1;
}
/* This routine called with relocation disabled. */
void __init
lmb_analyze(void)
{
- unsigned long i;
- unsigned long mem_size = 0;
- unsigned long size_mask = 0;
- struct lmb *_lmb = &lmb;
-#ifdef CONFIG_MSCHUNKS
- unsigned long physbase = 0;
-#endif
-
- for (i=0; i < _lmb->memory.cnt; i++) {
- unsigned long lmb_size;
-
- lmb_size = _lmb->memory.region[i].size;
-
-#ifdef CONFIG_MSCHUNKS
- _lmb->memory.region[i].physbase = physbase;
- physbase += lmb_size;
-#else
- _lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
-#endif
- mem_size += lmb_size;
- size_mask |= lmb_size;
- }
+ int i;
+
+ lmb.memory.size = 0;
- _lmb->memory.size = mem_size;
+ for (i = 0; i < lmb.memory.cnt; i++)
+ lmb.memory.size += lmb.memory.region[i].size;
}
/* This routine called with relocation disabled. */
@@ -168,7 +142,6 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
if ( adjacent > 0 ) {
rgn->region[i].base -= size;
- rgn->region[i].physbase -= size;
rgn->region[i].size += size;
coalesced++;
break;
@@ -195,11 +168,9 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
for (i=rgn->cnt-1; i >= 0; i--) {
if (base < rgn->region[i].base) {
rgn->region[i+1].base = rgn->region[i].base;
- rgn->region[i+1].physbase = rgn->region[i].physbase;
rgn->region[i+1].size = rgn->region[i].size;
} else {
rgn->region[i+1].base = base;
- rgn->region[i+1].physbase = lmb_abs_to_phys(base);
rgn->region[i+1].size = size;
break;
}
@@ -213,12 +184,11 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size)
long __init
lmb_add(unsigned long base, unsigned long size)
{
- struct lmb *_lmb = &lmb;
- struct lmb_region *_rgn = &(_lmb->memory);
+ struct lmb_region *_rgn = &(lmb.memory);
/* On pSeries LPAR systems, the first LMB is our RMO region. */
if ( base == 0 )
- _lmb->rmo_size = size;
+ lmb.rmo_size = size;
return lmb_add_region(_rgn, base, size);
@@ -227,8 +197,7 @@ lmb_add(unsigned long base, unsigned long size)
long __init
lmb_reserve(unsigned long base, unsigned long size)
{
- struct lmb *_lmb = &lmb;
- struct lmb_region *_rgn = &(_lmb->reserved);
+ struct lmb_region *_rgn = &(lmb.reserved);
return lmb_add_region(_rgn, base, size);
}
@@ -260,13 +229,10 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
{
long i, j;
unsigned long base = 0;
- struct lmb *_lmb = &lmb;
- struct lmb_region *_mem = &(_lmb->memory);
- struct lmb_region *_rsv = &(_lmb->reserved);
- for (i=_mem->cnt-1; i >= 0; i--) {
- unsigned long lmbbase = _mem->region[i].base;
- unsigned long lmbsize = _mem->region[i].size;
+ for (i=lmb.memory.cnt-1; i >= 0; i--) {
+ unsigned long lmbbase = lmb.memory.region[i].base;
+ unsigned long lmbsize = lmb.memory.region[i].size;
if ( max_addr == LMB_ALLOC_ANYWHERE )
base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
@@ -276,8 +242,8 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
continue;
while ( (lmbbase <= base) &&
- ((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
- base = _ALIGN_DOWN(_rsv->region[j].base-size, align);
+ ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) {
+ base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align);
}
if ( (base != 0) && (lmbbase <= base) )
@@ -287,62 +253,24 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
if ( i < 0 )
return 0;
- lmb_add_region(_rsv, base, size);
+ lmb_add_region(&lmb.reserved, base, size);
return base;
}
+/* You must call lmb_analyze() before this. */
unsigned long __init
lmb_phys_mem_size(void)
{
- struct lmb *_lmb = &lmb;
-#ifdef CONFIG_MSCHUNKS
- return _lmb->memory.size;
-#else
- struct lmb_region *_mem = &(_lmb->memory);
- unsigned long total = 0;
- int i;
-
- /* add all physical memory to the bootmem map */
- for (i=0; i < _mem->cnt; i++)
- total += _mem->region[i].size;
- return total;
-#endif /* CONFIG_MSCHUNKS */
+ return lmb.memory.size;
}
unsigned long __init
lmb_end_of_DRAM(void)
{
- struct lmb *_lmb = &lmb;
- struct lmb_region *_mem = &(_lmb->memory);
- int idx = _mem->cnt - 1;
-
-#ifdef CONFIG_MSCHUNKS
- return (_mem->region[idx].physbase + _mem->region[idx].size);
-#else
- return (_mem->region[idx].base + _mem->region[idx].size);
-#endif /* CONFIG_MSCHUNKS */
-
- return 0;
-}
-
-unsigned long __init
-lmb_abs_to_phys(unsigned long aa)
-{
- unsigned long i, pa = aa;
- struct lmb *_lmb = &lmb;
- struct lmb_region *_mem = &(_lmb->memory);
-
- for (i=0; i < _mem->cnt; i++) {
- unsigned long lmbbase = _mem->region[i].base;
- unsigned long lmbsize = _mem->region[i].size;
- if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) {
- pa = _mem->region[i].physbase + (aa - lmbbase);
- break;
- }
- }
+ int idx = lmb.memory.cnt - 1;
- return pa;
+ return (lmb.memory.region[idx].base + lmb.memory.region[idx].size);
}
/*
@@ -353,20 +281,19 @@ void __init lmb_enforce_memory_limit(void)
{
extern unsigned long memory_limit;
unsigned long i, limit;
- struct lmb_region *mem = &(lmb.memory);
if (! memory_limit)
return;
limit = memory_limit;
- for (i = 0; i < mem->cnt; i++) {
- if (limit > mem->region[i].size) {
- limit -= mem->region[i].size;
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ if (limit > lmb.memory.region[i].size) {
+ limit -= lmb.memory.region[i].size;
continue;
}
- mem->region[i].size = limit;
- mem->cnt = i + 1;
+ lmb.memory.region[i].size = limit;
+ lmb.memory.cnt = i + 1;
break;
}
}
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c
index 02e96627fa6..edad361a8db 100644
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/ppc64/kernel/lparcfg.c
@@ -29,7 +29,7 @@
#include <asm/iSeries/HvLpConfig.h>
#include <asm/lppaca.h>
#include <asm/hvcall.h>
-#include <asm/cputable.h>
+#include <asm/firmware.h>
#include <asm/rtas.h>
#include <asm/system.h>
#include <asm/time.h>
@@ -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
@@ -377,7 +378,7 @@ static int lparcfg_data(struct seq_file *m, void *v)
partition_active_processors = lparcfg_count_active_processors();
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
unsigned long h_entitled, h_unallocated;
unsigned long h_aggregation, h_resource;
unsigned long pool_idle_time, pool_procs;
@@ -571,7 +572,7 @@ int __init lparcfg_init(void)
mode_t mode = S_IRUSR;
/* Allow writing if we have FW_FEATURE_SPLPAR */
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
lparcfg_fops.write = lparcfg_write;
mode |= S_IWUSR;
}
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index a05b50b738e..474df0a862b 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -680,6 +680,104 @@ _GLOBAL(kernel_thread)
ld r30,-16(r1)
blr
+/*
+ * disable_kernel_fp()
+ * Disable the FPU.
+ */
+_GLOBAL(disable_kernel_fp)
+ mfmsr r3
+ rldicl r0,r3,(63-MSR_FP_LG),1
+ rldicl r3,r0,(MSR_FP_LG+1),0
+ mtmsrd r3 /* disable use of fpu now */
+ isync
+ blr
+
+/*
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ */
+_GLOBAL(giveup_fpu)
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ mtmsrd r5 /* enable use of fpu now */
+ isync
+ cmpdi 0,r3,0
+ beqlr- /* if no previous owner, done */
+ addi r3,r3,THREAD /* want THREAD of task */
+ ld r5,PT_REGS(r3)
+ cmpdi 0,r5,0
+ SAVE_32FPRS(0, r3)
+ mffs fr0
+ stfd fr0,THREAD_FPSCR(r3)
+ beq 1f
+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r3,MSR_FP|MSR_FE0|MSR_FE1
+ andc r4,r4,r3 /* disable FP for previous task */
+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+ li r5,0
+ ld r4,last_task_used_math@got(r2)
+ std r5,0(r4)
+#endif /* CONFIG_SMP */
+ blr
+
+#ifdef CONFIG_ALTIVEC
+
+#if 0 /* this has no callers for now */
+/*
+ * disable_kernel_altivec()
+ * Disable the VMX.
+ */
+_GLOBAL(disable_kernel_altivec)
+ mfmsr r3
+ rldicl r0,r3,(63-MSR_VEC_LG),1
+ rldicl r3,r0,(MSR_VEC_LG+1),0
+ mtmsrd r3 /* disable use of VMX now */
+ isync
+ blr
+#endif /* 0 */
+
+/*
+ * giveup_altivec(tsk)
+ * Disable VMX for the task given as the argument,
+ * and save the vector registers in its thread_struct.
+ * Enables the VMX for use in the kernel on return.
+ */
+_GLOBAL(giveup_altivec)
+ mfmsr r5
+ oris r5,r5,MSR_VEC@h
+ mtmsrd r5 /* enable use of VMX now */
+ isync
+ cmpdi 0,r3,0
+ beqlr- /* if no previous owner, done */
+ addi r3,r3,THREAD /* want THREAD of task */
+ ld r5,PT_REGS(r3)
+ cmpdi 0,r5,0
+ SAVE_32VRS(0,r4,r3)
+ mfvscr vr0
+ li r4,THREAD_VSCR
+ stvx vr0,r4,r3
+ beq 1f
+ ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ lis r3,MSR_VEC@h
+ andc r4,r4,r3 /* disable FP for previous task */
+ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+ li r5,0
+ ld r4,last_task_used_altivec@got(r2)
+ std r5,0(r4)
+#endif /* CONFIG_SMP */
+ blr
+
+#endif /* CONFIG_ALTIVEC */
+
+_GLOBAL(__setup_cpu_power3)
+ blr
+
/* kexec_wait(phys_cpu)
*
* wait for the flag to change, indicating this kernel is going away but
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_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c
index 69130522a87..9d5e1e7fc38 100644
--- a/arch/ppc64/kernel/pSeries_iommu.c
+++ b/arch/ppc64/kernel/pSeries_iommu.c
@@ -45,6 +45,7 @@
#include <asm/plpar_wrappers.h>
#include <asm/pSeries_reconfig.h>
#include <asm/systemcfg.h>
+#include <asm/firmware.h>
#include "pci.h"
#define DBG(fmt...)
@@ -546,7 +547,7 @@ void iommu_init_early_pSeries(void)
}
if (systemcfg->platform & PLATFORM_LPAR) {
- if (cur_cpu_spec->firmware_features & FW_FEATURE_MULTITCE) {
+ if (firmware_has_feature(FW_FEATURE_MULTITCE)) {
ppc_md.tce_build = tce_buildmulti_pSeriesLP;
ppc_md.tce_free = tce_freemulti_pSeriesLP;
} else {
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
index 74dd144dcce..0a3ddc9227c 100644
--- a/arch/ppc64/kernel/pSeries_lpar.c
+++ b/arch/ppc64/kernel/pSeries_lpar.c
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(plpar_hcall_4out);
EXPORT_SYMBOL(plpar_hcall_norets);
EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
-extern void fw_feature_init(void);
extern void pSeries_find_serial_port(void);
@@ -279,7 +278,6 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
unsigned long va, unsigned long prpn,
unsigned long vflags, unsigned long rflags)
{
- unsigned long arpn = physRpn_to_absRpn(prpn);
unsigned long lpar_rc;
unsigned long flags;
unsigned long slot;
@@ -290,7 +288,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
if (vflags & HPTE_V_LARGE)
hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT);
- hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
+ hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;
/* Now fill in the actual HPTE */
/* Set CEC cookie to 0 */
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
index 5bec956e44a..f0f0630cf07 100644
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -60,7 +60,8 @@
#include <asm/nvram.h>
#include <asm/plpar_wrappers.h>
#include <asm/xics.h>
-#include <asm/cputable.h>
+#include <asm/firmware.h>
+#include <asm/pmc.h>
#include "i8259.h"
#include "mpic.h"
@@ -187,6 +188,21 @@ static void __init pSeries_setup_mpic(void)
" MPIC ");
}
+static void pseries_lpar_enable_pmcs(void)
+{
+ unsigned long set, reset;
+
+ power4_enable_pmcs();
+
+ set = 1UL << 63;
+ reset = 0;
+ plpar_hcall_norets(H_PERFMON, set, reset);
+
+ /* instruct hypervisor to maintain PMCs */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
+ get_paca()->lppaca.pmcregs_in_use = 1;
+}
+
static void __init pSeries_setup_arch(void)
{
/* Fixup ppc_md depending on the type of interrupt controller */
@@ -231,11 +247,9 @@ static void __init pSeries_setup_arch(void)
pSeries_nvram_init();
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
- vpa_init(boot_cpuid);
-
/* Choose an idle loop */
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ vpa_init(boot_cpuid);
if (get_paca()->lppaca.shared_proc) {
printk(KERN_INFO "Using shared processor idle loop\n");
ppc_md.idle_loop = pseries_shared_idle;
@@ -247,6 +261,11 @@ static void __init pSeries_setup_arch(void)
printk(KERN_INFO "Using default idle loop\n");
ppc_md.idle_loop = default_idle;
}
+
+ if (systemcfg->platform & PLATFORM_LPAR)
+ ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
+ else
+ ppc_md.enable_pmcs = power4_enable_pmcs;
}
static int __init pSeries_init_panel(void)
@@ -260,11 +279,11 @@ static int __init pSeries_init_panel(void)
arch_initcall(pSeries_init_panel);
-/* Build up the firmware_features bitmask field
+/* Build up the ppc64_firmware_features bitmask field
* using contents of device-tree/ibm,hypertas-functions.
* Ultimately this functionality may be moved into prom.c prom_init().
*/
-void __init fw_feature_init(void)
+static void __init fw_feature_init(void)
{
struct device_node * dn;
char * hypertas;
@@ -272,7 +291,7 @@ void __init fw_feature_init(void)
DBG(" -> fw_feature_init()\n");
- cur_cpu_spec->firmware_features = 0;
+ ppc64_firmware_features = 0;
dn = of_find_node_by_path("/rtas");
if (dn == NULL) {
printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");
@@ -288,7 +307,7 @@ void __init fw_feature_init(void)
if ((firmware_features_table[i].name) &&
(strcmp(firmware_features_table[i].name,hypertas))==0) {
/* we have a match */
- cur_cpu_spec->firmware_features |=
+ ppc64_firmware_features |=
(firmware_features_table[i].val);
break;
}
@@ -302,7 +321,7 @@ void __init fw_feature_init(void)
of_node_put(dn);
no_rtas:
printk(KERN_INFO "firmware_features = 0x%lx\n",
- cur_cpu_spec->firmware_features);
+ ppc64_firmware_features);
DBG(" <- fw_feature_init()\n");
}
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c
index 62c55a12356..79c7f322366 100644
--- a/arch/ppc64/kernel/pSeries_smp.c
+++ b/arch/ppc64/kernel/pSeries_smp.c
@@ -41,6 +41,7 @@
#include <asm/machdep.h>
#include <asm/xics.h>
#include <asm/cputable.h>
+#include <asm/firmware.h>
#include <asm/system.h>
#include <asm/rtas.h>
#include <asm/plpar_wrappers.h>
@@ -326,7 +327,7 @@ static void __devinit smp_xics_setup_cpu(int cpu)
if (cpu != boot_cpuid)
xics_setup_cpu();
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
vpa_init(cpu);
cpu_clear(cpu, of_spin_map);
diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c
new file mode 100644
index 00000000000..e0ae06f58f8
--- /dev/null
+++ b/arch/ppc64/kernel/pSeries_vio.c
@@ -0,0 +1,273 @@
+/*
+ * IBM PowerPC pSeries Virtual I/O Infrastructure Support.
+ *
+ * Copyright (c) 2003-2005 IBM Corp.
+ * Dave Engebretsen engebret@us.ibm.com
+ * Santiago Leon santil@us.ibm.com
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ * Stephen Rothwell
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kobject.h>
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+#include <asm/hvcall.h>
+
+extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+
+static void probe_bus_pseries(void)
+{
+ struct device_node *node_vroot, *of_node;
+
+ node_vroot = find_devices("vdevice");
+ if ((node_vroot == NULL) || (node_vroot->child == NULL))
+ /* this machine doesn't do virtual IO, and that's ok */
+ return;
+
+ /*
+ * Create struct vio_devices for each virtual device in the device tree.
+ * Drivers will associate with them later.
+ */
+ for (of_node = node_vroot->child; of_node != NULL;
+ of_node = of_node->sibling) {
+ printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
+ vio_register_device_node(of_node);
+ }
+}
+
+/**
+ * vio_match_device_pseries: - Tell if a pSeries VIO device matches a
+ * vio_device_id
+ */
+static int vio_match_device_pseries(const struct vio_device_id *id,
+ const struct vio_dev *dev)
+{
+ return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&
+ device_is_compatible(dev->dev.platform_data, id->compat);
+}
+
+static void vio_release_device_pseries(struct device *dev)
+{
+ /* XXX free TCE table */
+ of_node_put(dev->platform_data);
+}
+
+static ssize_t viodev_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct device_node *of_node = dev->platform_data;
+
+ return sprintf(buf, "%s\n", of_node->full_name);
+}
+DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
+
+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
+ */
+static int __init vio_bus_init_pseries(void)
+{
+ int err;
+
+ err = vio_bus_init(&vio_bus_ops_pseries);
+ if (err == 0)
+ probe_bus_pseries();
+ return err;
+}
+
+__initcall(vio_bus_init_pseries);
+
+/**
+ * vio_build_iommu_table: - gets the dma information from OF and
+ * builds the TCE tree.
+ * @dev: the virtual device.
+ *
+ * Returns a pointer to the built tce tree, or NULL if it can't
+ * find property.
+*/
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
+{
+ unsigned int *dma_window;
+ struct iommu_table *newTceTable;
+ unsigned long offset;
+ int dma_window_property_size;
+
+ dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
+ if(!dma_window) {
+ return NULL;
+ }
+
+ newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
+
+ /* There should be some code to extract the phys-encoded offset
+ using prom_n_addr_cells(). However, according to a comment
+ on earlier versions, it's always zero, so we don't bother */
+ offset = dma_window[1] >> PAGE_SHIFT;
+
+ /* TCE table size - measured in tce entries */
+ newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;
+ /* offset for VIO should always be 0 */
+ newTceTable->it_offset = offset;
+ newTceTable->it_busno = 0;
+ newTceTable->it_index = (unsigned long)dma_window[0];
+ newTceTable->it_type = TCE_VB;
+
+ return iommu_init_table(newTceTable);
+}
+
+/**
+ * vio_register_device_node: - Register a new vio device.
+ * @of_node: The OF node for this device.
+ *
+ * Creates and initializes a vio_dev structure from the data in
+ * of_node (dev.platform_data) and adds it to the list of virtual devices.
+ * Returns a pointer to the created vio_dev or NULL if node has
+ * NULL device_type or compatible fields.
+ */
+struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+{
+ struct vio_dev *viodev;
+ unsigned int *unit_address;
+ unsigned int *irq_p;
+
+ /* we need the 'device_type' property, in order to match with drivers */
+ if ((NULL == of_node->type)) {
+ printk(KERN_WARNING
+ "%s: node %s missing 'device_type'\n", __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
+ }
+
+ unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
+ if (!unit_address) {
+ printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
+ of_node->name ? of_node->name : "<unknown>");
+ return NULL;
+ }
+
+ /* allocate a vio_dev for this node */
+ viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
+ if (!viodev) {
+ return NULL;
+ }
+ memset(viodev, 0, sizeof(struct vio_dev));
+
+ viodev->dev.platform_data = of_node_get(of_node);
+
+ viodev->irq = NO_IRQ;
+ irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
+ if (irq_p) {
+ int virq = virt_irq_create_mapping(*irq_p);
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR "Unable to allocate interrupt "
+ "number for %s\n", of_node->full_name);
+ } else
+ viodev->irq = irq_offset_up(virq);
+ }
+
+ 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(viodev) == NULL) {
+ /* XXX free TCE table */
+ kfree(viodev);
+ return NULL;
+ }
+ device_create_file(&viodev->dev, &dev_attr_devspec);
+
+ return viodev;
+}
+EXPORT_SYMBOL(vio_register_device_node);
+
+/**
+ * vio_get_attribute: - get attribute for virtual device
+ * @vdev: The vio device to get property.
+ * @which: The property/attribute to be extracted.
+ * @length: Pointer to length of returned data size (unused if NULL).
+ *
+ * Calls prom.c's get_property() to return the value of the
+ * attribute specified by the preprocessor constant @which
+*/
+const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
+{
+ return get_property(vdev->dev.platform_data, (char*)which, length);
+}
+EXPORT_SYMBOL(vio_get_attribute);
+
+/* vio_find_name() - internal because only vio.c knows how we formatted the
+ * kobject name
+ * XXX once vio_bus_type.devices is actually used as a kset in
+ * drivers/base/bus.c, this function should be removed in favor of
+ * "device_find(kobj_name, &vio_bus_type)"
+ */
+static struct vio_dev *vio_find_name(const char *kobj_name)
+{
+ struct kobject *found;
+
+ found = kset_find_obj(&devices_subsys.kset, kobj_name);
+ if (!found)
+ return NULL;
+
+ return to_vio_dev(container_of(found, struct device, kobj));
+}
+
+/**
+ * vio_find_node - find an already-registered vio_dev
+ * @vnode: device_node of the virtual device we're looking for
+ */
+struct vio_dev *vio_find_node(struct device_node *vnode)
+{
+ uint32_t *unit_address;
+ char kobj_name[BUS_ID_SIZE];
+
+ /* construct the kobject name from the device node */
+ unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
+ if (!unit_address)
+ return NULL;
+ snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
+
+ return vio_find_name(kobj_name);
+}
+EXPORT_SYMBOL(vio_find_node);
+
+int vio_enable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
+ if (rc != H_Success)
+ printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_enable_interrupts);
+
+int vio_disable_interrupts(struct vio_dev *dev)
+{
+ int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
+ if (rc != H_Success)
+ printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
+ return rc;
+}
+EXPORT_SYMBOL(vio_disable_interrupts);
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
index 6316188737b..6182a2cd90a 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -78,7 +78,7 @@ extern unsigned long __toc_start;
#define BOOTCPU_PACA_INIT(number) \
{ \
- PACA_INIT_COMMON(number, 1, 0, STAB0_VIRT_ADDR) \
+ PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \
PACA_INIT_ISERIES(number) \
}
@@ -90,7 +90,7 @@ extern unsigned long __toc_start;
#define BOOTCPU_PACA_INIT(number) \
{ \
- PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR) \
+ PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \
}
#endif
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
index e40877fa67c..8ff86a766cd 100644
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -71,6 +71,7 @@
#include <asm/of_device.h>
#include <asm/lmb.h>
#include <asm/smu.h>
+#include <asm/pmc.h>
#include "pmac.h"
#include "mpic.h"
@@ -511,4 +512,5 @@ struct machdep_calls __initdata pmac_md = {
.progress = pmac_progress,
.check_legacy_ioport = pmac_check_legacy_ioport,
.idle_loop = native_idle,
+ .enable_pmcs = power4_enable_pmcs,
};
diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c
index 67be773f9c0..cdfec7438d0 100644
--- a/arch/ppc64/kernel/pmc.c
+++ b/arch/ppc64/kernel/pmc.c
@@ -65,3 +65,24 @@ void release_pmc_hardware(void)
spin_unlock(&pmc_owner_lock);
}
EXPORT_SYMBOL_GPL(release_pmc_hardware);
+
+void power4_enable_pmcs(void)
+{
+ unsigned long hid0;
+
+ hid0 = mfspr(HID0);
+ hid0 |= 1UL << (63 - 20);
+
+ /* POWER4 requires the following sequence */
+ asm volatile(
+ "sync\n"
+ "mtspr %1, %0\n"
+ "mfspr %0, %1\n"
+ "mfspr %0, %1\n"
+ "mfspr %0, %1\n"
+ "mfspr %0, %1\n"
+ "mfspr %0, %1\n"
+ "mfspr %0, %1\n"
+ "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):
+ "memory");
+}
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
index f7cae05e40f..7a7e027653a 100644
--- a/arch/ppc64/kernel/process.c
+++ b/arch/ppc64/kernel/process.c
@@ -50,6 +50,7 @@
#include <asm/machdep.h>
#include <asm/iSeries/HvCallHpt.h>
#include <asm/cputable.h>
+#include <asm/firmware.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
#include <asm/time.h>
@@ -202,11 +203,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
new_thread = &new->thread;
old_thread = &current->thread;
-/* Collect purr utilization data per process and per processor wise */
-/* purr is nothing but processor time base */
-
-#if defined(CONFIG_PPC_PSERIES)
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ /* Collect purr utilization data per process and per processor
+ * wise purr is nothing but processor time base
+ */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
long unsigned start_tb, current_tb;
start_tb = old_thread->start_tb;
@@ -214,8 +214,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
old_thread->accum_tb += (current_tb - start_tb);
new_thread->start_tb = current_tb;
}
-#endif
-
local_irq_save(flags);
last = _switch(old_thread, new_thread);
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 5aca01ddd81..b2184882679 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -625,8 +625,8 @@ void __init finish_device_tree(void)
static inline char *find_flat_dt_string(u32 offset)
{
- return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings
- + offset;
+ return ((char *)initial_boot_params) +
+ initial_boot_params->off_dt_strings + offset;
}
/**
@@ -635,26 +635,33 @@ static inline char *find_flat_dt_string(u32 offset)
* unflatten the tree
*/
static int __init scan_flat_dt(int (*it)(unsigned long node,
- const char *full_path, void *data),
+ const char *uname, int depth,
+ void *data),
void *data)
{
unsigned long p = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
int rc = 0;
+ int depth = -1;
do {
u32 tag = *((u32 *)p);
char *pathp;
p += 4;
- if (tag == OF_DT_END_NODE)
+ if (tag == OF_DT_END_NODE) {
+ depth --;
+ continue;
+ }
+ if (tag == OF_DT_NOP)
continue;
if (tag == OF_DT_END)
break;
if (tag == OF_DT_PROP) {
u32 sz = *((u32 *)p);
p += 8;
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
p += sz;
p = _ALIGN(p, 4);
continue;
@@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node,
" device tree !\n", tag);
return -EINVAL;
}
+ depth++;
pathp = (char *)p;
p = _ALIGN(p + strlen(pathp) + 1, 4);
- rc = it(p, pathp, data);
+ if ((*pathp) == '/') {
+ char *lp, *np;
+ for (lp = NULL, np = pathp; *np; np++)
+ if ((*np) == '/')
+ lp = np+1;
+ if (lp != NULL)
+ pathp = lp;
+ }
+ rc = it(p, pathp, depth, data);
if (rc != 0)
break;
} while(1);
@@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
const char *nstr;
p += 4;
+ if (tag == OF_DT_NOP)
+ continue;
if (tag != OF_DT_PROP)
return NULL;
sz = *((u32 *)p);
noff = *((u32 *)(p + 4));
p += 8;
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ if (initial_boot_params->version < 0x10)
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
nstr = find_flat_dt_string(noff);
if (nstr == NULL) {
- printk(KERN_WARNING "Can't find property index name !\n");
+ printk(KERN_WARNING "Can't find property index"
+ " name !\n");
return NULL;
}
if (strcmp(name, nstr) == 0) {
@@ -713,7 +733,7 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name,
}
static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
- unsigned long align)
+ unsigned long align)
{
void *res;
@@ -727,13 +747,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
static unsigned long __init unflatten_dt_node(unsigned long mem,
unsigned long *p,
struct device_node *dad,
- struct device_node ***allnextpp)
+ struct device_node ***allnextpp,
+ unsigned long fpsize)
{
struct device_node *np;
struct property *pp, **prev_pp = NULL;
char *pathp;
u32 tag;
- unsigned int l;
+ unsigned int l, allocl;
+ int has_name = 0;
+ int new_format = 0;
tag = *((u32 *)(*p));
if (tag != OF_DT_BEGIN_NODE) {
@@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
}
*p += 4;
pathp = (char *)*p;
- l = strlen(pathp) + 1;
+ l = allocl = strlen(pathp) + 1;
*p = _ALIGN(*p + l, 4);
- np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l,
+ /* version 0x10 has a more compact unit name here instead of the full
+ * path. we accumulate the full path size using "fpsize", we'll rebuild
+ * it later. We detect this because the first character of the name is
+ * not '/'.
+ */
+ if ((*pathp) != '/') {
+ new_format = 1;
+ if (fpsize == 0) {
+ /* root node: special case. fpsize accounts for path
+ * plus terminating zero. root node only has '/', so
+ * fpsize should be 2, but we want to avoid the first
+ * level nodes to have two '/' so we use fpsize 1 here
+ */
+ fpsize = 1;
+ allocl = 2;
+ } else {
+ /* account for '/' and path size minus terminal 0
+ * already in 'l'
+ */
+ fpsize += l;
+ allocl = fpsize;
+ }
+ }
+
+
+ np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));
if (allnextpp) {
memset(np, 0, sizeof(*np));
np->full_name = ((char*)np) + sizeof(struct device_node);
- memcpy(np->full_name, pathp, l);
+ if (new_format) {
+ char *p = np->full_name;
+ /* rebuild full path for new format */
+ if (dad && dad->parent) {
+ strcpy(p, dad->full_name);
+#ifdef DEBUG
+ if ((strlen(p) + l + 1) != allocl) {
+ DBG("%s: p: %d, l: %d, a: %d\n",
+ pathp, strlen(p), l, allocl);
+ }
+#endif
+ p += strlen(p);
+ }
+ *(p++) = '/';
+ memcpy(p, pathp, l);
+ } else
+ memcpy(np->full_name, pathp, l);
prev_pp = &np->properties;
**allnextpp = np;
*allnextpp = &np->allnext;
if (dad != NULL) {
np->parent = dad;
- /* we temporarily use the `next' field as `last_child'. */
+ /* we temporarily use the next field as `last_child'*/
if (dad->next == 0)
dad->child = np;
else
@@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
char *pname;
tag = *((u32 *)(*p));
+ if (tag == OF_DT_NOP) {
+ *p += 4;
+ continue;
+ }
if (tag != OF_DT_PROP)
break;
*p += 4;
sz = *((u32 *)(*p));
noff = *((u32 *)((*p) + 4));
- *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4);
+ *p += 8;
+ if (initial_boot_params->version < 0x10)
+ *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
pname = find_flat_dt_string(noff);
if (pname == NULL) {
printk("Can't find property name in list !\n");
break;
}
+ if (strcmp(pname, "name") == 0)
+ has_name = 1;
l = strlen(pname) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
@@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
}
*p = _ALIGN((*p) + sz, 4);
}
+ /* with version 0x10 we may not have the name property, recreate
+ * it here from the unit name if absent
+ */
+ if (!has_name) {
+ char *p = pathp, *ps = pathp, *pa = NULL;
+ int sz;
+
+ while (*p) {
+ if ((*p) == '@')
+ pa = p;
+ if ((*p) == '/')
+ ps = p + 1;
+ p++;
+ }
+ if (pa < ps)
+ pa = p;
+ sz = (pa - ps) + 1;
+ pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+ __alignof__(struct property));
+ if (allnextpp) {
+ pp->name = "name";
+ pp->length = sz;
+ pp->value = (unsigned char *)(pp + 1);
+ *prev_pp = pp;
+ prev_pp = &pp->next;
+ memcpy(pp->value, ps, sz - 1);
+ ((char *)pp->value)[sz - 1] = 0;
+ DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+ }
+ }
if (allnextpp) {
*prev_pp = NULL;
np->name = get_property(np, "name", NULL);
@@ -812,11 +914,11 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
np->type = "<NULL>";
}
while (tag == OF_DT_BEGIN_NODE) {
- mem = unflatten_dt_node(mem, p, np, allnextpp);
+ mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
tag = *((u32 *)(*p));
}
if (tag != OF_DT_END_NODE) {
- printk("Weird tag at start of node: %x\n", tag);
+ printk("Weird tag at end of node: %x\n", tag);
return mem;
}
*p += 4;
@@ -842,21 +944,32 @@ void __init unflatten_device_tree(void)
/* First pass, scan for size */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- size = unflatten_dt_node(0, &start, NULL, NULL);
+ size = unflatten_dt_node(0, &start, NULL, NULL, 0);
+ size = (size | 3) + 1;
DBG(" size is %lx, allocating...\n", size);
/* Allocate memory for the expanded device tree */
- mem = (unsigned long)abs_to_virt(lmb_alloc(size,
- __alignof__(struct device_node)));
+ mem = lmb_alloc(size + 4, __alignof__(struct device_node));
+ if (!mem) {
+ DBG("Couldn't allocate memory with lmb_alloc()!\n");
+ panic("Couldn't allocate memory with lmb_alloc()!\n");
+ }
+ mem = (unsigned long)abs_to_virt(mem);
+
+ ((u32 *)mem)[size / 4] = 0xdeadbeef;
+
DBG(" unflattening...\n", mem);
/* Second pass, do actual unflattening */
start = ((unsigned long)initial_boot_params) +
initial_boot_params->off_dt_struct;
- unflatten_dt_node(mem, &start, NULL, &allnextp);
+ unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
if (*((u32 *)start) != OF_DT_END)
- printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
+ printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
+ if (((u32 *)mem)[size / 4] != 0xdeadbeef)
+ printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
+ ((u32 *)mem)[size / 4] );
*allnextp = NULL;
/* Get pointer to OF "/chosen" node for use everywhere */
@@ -880,7 +993,7 @@ void __init unflatten_device_tree(void)
static int __init early_init_dt_scan_cpus(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
char *type = get_flat_dt_prop(node, "device_type", NULL);
u32 *prop;
@@ -947,13 +1060,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
}
static int __init early_init_dt_scan_chosen(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
u32 *prop;
u64 *prop64;
extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end;
- if (strcmp(full_path, "/chosen") != 0)
+ DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+ if (depth != 1 || strcmp(uname, "chosen") != 0)
return 0;
/* get platform type */
@@ -1003,18 +1118,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
}
static int __init early_init_dt_scan_root(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
u32 *prop;
- if (strcmp(full_path, "/") != 0)
+ if (depth != 0)
return 0;
prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
dt_root_size_cells = (prop == NULL) ? 1 : *prop;
-
+ DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
+
prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+ DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
/* break now */
return 1;
@@ -1042,7 +1159,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
static int __init early_init_dt_scan_memory(unsigned long node,
- const char *full_path, void *data)
+ const char *uname, int depth, void *data)
{
char *type = get_flat_dt_prop(node, "device_type", NULL);
cell_t *reg, *endp;
@@ -1058,7 +1175,9 @@ static int __init early_init_dt_scan_memory(unsigned long node,
endp = reg + (l / sizeof(cell_t));
- DBG("memory scan node %s ...\n", full_path);
+ DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
+ uname, l, reg[0], reg[1], reg[2], reg[3]);
+
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
unsigned long base, size;
@@ -1469,10 +1588,11 @@ struct device_node *of_find_node_by_path(const char *path)
struct device_node *np = allnodes;
read_lock(&devtree_lock);
- for (; np != 0; np = np->allnext)
+ for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
&& of_node_get(np))
break;
+ }
read_unlock(&devtree_lock);
return np;
}
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index dbbe6c79d8d..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));
@@ -1534,7 +1537,8 @@ static unsigned long __init dt_find_string(char *str)
*/
#define MAX_PROPERTY_NAME 64
-static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+static void __init scan_dt_build_strings(phandle node,
+ unsigned long *mem_start,
unsigned long *mem_end)
{
unsigned long offset = reloc_offset();
@@ -1547,16 +1551,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* get and store all property names */
prev_name = RELOC("");
for (;;) {
- int rc;
-
/* 64 is max len of name including nul. */
namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
- rc = call_prom("nextprop", 3, 1, node, prev_name, namep);
- if (rc != 1) {
+ if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
/* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep;
break;
}
+
+ /* skip "name" */
+ if (strcmp(namep, RELOC("name")) == 0) {
+ *mem_start = (unsigned long)namep;
+ prev_name = RELOC("name");
+ continue;
+ }
+ /* get/create string entry */
soff = dt_find_string(namep);
if (soff != 0) {
*mem_start = (unsigned long)namep;
@@ -1571,7 +1580,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* do all our children */
child = call_prom("child", 1, 1, node);
- while (child != (phandle)0) {
+ while (child != 0) {
scan_dt_build_strings(child, mem_start, mem_end);
child = call_prom("peer", 1, 1, child);
}
@@ -1580,16 +1589,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end)
{
- int l, align;
phandle child;
- char *namep, *prev_name, *sstart, *p, *ep;
+ char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
unsigned long soff;
unsigned char *valp;
unsigned long offset = reloc_offset();
- char pname[MAX_PROPERTY_NAME];
- char *path;
-
- path = RELOC(prom_scratch);
+ static char pname[MAX_PROPERTY_NAME];
+ int l;
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
@@ -1599,23 +1605,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
namep, *mem_end - *mem_start);
if (l >= 0) {
/* Didn't fit? Get more room. */
- if (l+1 > *mem_end - *mem_start) {
+ if ((l+1) > (*mem_end - *mem_start)) {
namep = make_room(mem_start, mem_end, l+1, 1);
call_prom("package-to-path", 3, 1, node, namep, l);
}
namep[l] = '\0';
+
/* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties
*/
for (p = namep, ep = namep + l; p < ep; p++)
if (*p == '\0') {
memmove(p, p+1, ep - p);
- ep--; l--;
+ ep--; l--; p--;
}
- *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+
+ /* now try to extract the unit name in that mess */
+ for (p = namep, lp = NULL; *p; p++)
+ if (*p == '/')
+ lp = p + 1;
+ if (lp != NULL)
+ memmove(namep, lp, strlen(lp) + 1);
+ *mem_start = _ALIGN(((unsigned long) namep) +
+ strlen(namep) + 1, 4);
}
/* get it again for debugging */
+ path = RELOC(prom_scratch);
memset(path, 0, PROM_SCRATCH_SIZE);
call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
@@ -1623,23 +1639,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start);
for (;;) {
- int rc;
-
- rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
- if (rc != 1)
+ if (call_prom("nextprop", 3, 1, node, prev_name,
+ RELOC(pname)) != 1)
break;
+ /* skip "name" */
+ if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+ prev_name = RELOC("name");
+ continue;
+ }
+
/* find string offset */
- soff = dt_find_string(pname);
+ soff = dt_find_string(RELOC(pname));
if (soff == 0) {
- prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
- pname, path);
+ prom_printf("WARNING: Can't find string index for"
+ " <%s>, node %s\n", RELOC(pname), path);
break;
}
prev_name = sstart + soff;
/* get length */
- l = call_prom("getproplen", 2, 1, node, pname);
+ l = call_prom("getproplen", 2, 1, node, RELOC(pname));
/* sanity checks */
if (l == PROM_ERROR)
@@ -1648,7 +1668,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prom_printf("WARNING: ignoring large property ");
/* It seems OF doesn't null-terminate the path :-( */
prom_printf("[%s] ", path);
- prom_printf("%s length 0x%x\n", pname, l);
+ prom_printf("%s length 0x%x\n", RELOC(pname), l);
continue;
}
@@ -1658,17 +1678,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
dt_push_token(soff, mem_start, mem_end);
/* push property content */
- align = (l >= 8) ? 8 : 4;
- valp = make_room(mem_start, mem_end, l, align);
- call_prom("getprop", 4, 1, node, pname, valp, l);
+ valp = make_room(mem_start, mem_end, l, 4);
+ call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
*mem_start = _ALIGN(*mem_start, 4);
}
/* Add a "linux,phandle" property. */
soff = dt_find_string(RELOC("linux,phandle"));
if (soff == 0)
- prom_printf("WARNING: Can't find string index for <linux-phandle>"
- " node %s\n", path);
+ prom_printf("WARNING: Can't find string index for"
+ " <linux-phandle> node %s\n", path);
else {
dt_push_token(OF_DT_PROP, mem_start, mem_end);
dt_push_token(4, mem_start, mem_end);
@@ -1679,7 +1698,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
/* do all our children */
child = call_prom("child", 1, 1, node);
- while (child != (phandle)0) {
+ while (child != 0) {
scan_dt_build_struct(child, mem_start, mem_end);
child = call_prom("peer", 1, 1, child);
}
@@ -1718,7 +1737,8 @@ static void __init flatten_device_tree(void)
/* Build header and make room for mem rsv map */
mem_start = _ALIGN(mem_start, 4);
- hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4);
+ hdr = make_room(&mem_start, &mem_end,
+ sizeof(struct boot_param_header), 4);
RELOC(dt_header_start) = (unsigned long)hdr;
rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
@@ -1731,11 +1751,11 @@ static void __init flatten_device_tree(void)
namep = make_room(&mem_start, &mem_end, 16, 1);
strcpy(namep, RELOC("linux,phandle"));
mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = mem_start;
/* Build string array */
prom_printf("Building dt strings...\n");
scan_dt_build_strings(root, &mem_start, &mem_end);
+ RELOC(dt_string_end) = mem_start;
/* Build structure */
mem_start = PAGE_ALIGN(mem_start);
@@ -1750,9 +1770,11 @@ static void __init flatten_device_tree(void)
hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
+ hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
hdr->version = OF_DT_VERSION;
- hdr->last_comp_version = 1;
+ /* Version 16 is not backward compatible */
+ hdr->last_comp_version = 0x10;
/* Reserve the whole thing and copy the reserve map in, we
* also bump mem_reserve_cnt to cause further reservations to
@@ -1808,6 +1830,9 @@ static void __init fixup_device_tree(void)
/* does it need fixup ? */
if (prom_getproplen(i2c, "interrupts") > 0)
return;
+
+ prom_printf("fixing up bogus interrupts for u3 i2c...\n");
+
/* interrupt on this revision of u3 is number 0 and level */
interrupts[0] = 0;
interrupts[1] = 1;
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c
index 1048817befb..1dccadaddd1 100644
--- a/arch/ppc64/kernel/rtas_pci.c
+++ b/arch/ppc64/kernel/rtas_pci.c
@@ -58,6 +58,21 @@ static int config_access_valid(struct device_node *dn, int where)
return 0;
}
+static int of_device_available(struct device_node * dn)
+{
+ char * status;
+
+ status = get_property(dn, "status", NULL);
+
+ if (!status)
+ return 1;
+
+ if (!strcmp(status, "okay"))
+ return 1;
+
+ return 0;
+}
+
static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
{
int returnval = -1;
@@ -103,7 +118,7 @@ static int rtas_pci_read_config(struct pci_bus *bus,
/* Search only direct children of the bus */
for (dn = busdn->child; dn; dn = dn->sibling)
- if (dn->devfn == devfn)
+ if (dn->devfn == devfn && of_device_available(dn))
return rtas_read_config(dn, where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
@@ -146,7 +161,7 @@ static int rtas_pci_write_config(struct pci_bus *bus,
/* Search only direct children of the bus */
for (dn = busdn->child; dn; dn = dn->sibling)
- if (dn->devfn == devfn)
+ if (dn->devfn == devfn && of_device_available(dn))
return rtas_write_config(dn, where, size, val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index e9c24d2dbd9..ee3b20de2e7 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -536,15 +536,19 @@ static void __init check_for_initrd(void)
DBG(" -> check_for_initrd()\n");
- prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL);
- if (prop != NULL) {
- initrd_start = (unsigned long)__va(*prop);
- prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL);
+ if (of_chosen) {
+ prop = (u64 *)get_property(of_chosen,
+ "linux,initrd-start", NULL);
if (prop != NULL) {
- initrd_end = (unsigned long)__va(*prop);
- initrd_below_start_ok = 1;
- } else
- initrd_start = 0;
+ initrd_start = (unsigned long)__va(*prop);
+ prop = (u64 *)get_property(of_chosen,
+ "linux,initrd-end", NULL);
+ if (prop != NULL) {
+ initrd_end = (unsigned long)__va(*prop);
+ initrd_below_start_ok = 1;
+ } else
+ initrd_start = 0;
+ }
}
/* If we were passed an initrd, set the ROOT_DEV properly if the values
@@ -627,7 +631,7 @@ void __init setup_system(void)
* Initialize xmon
*/
#ifdef CONFIG_XMON_DEFAULT
- xmon_init();
+ xmon_init(1);
#endif
/*
* Register early console
@@ -1343,11 +1347,13 @@ static int __init early_xmon(char *p)
/* ensure xmon is enabled */
if (p) {
if (strncmp(p, "on", 2) == 0)
- xmon_init();
+ xmon_init(1);
+ if (strncmp(p, "off", 3) == 0)
+ xmon_init(0);
if (strncmp(p, "early", 5) != 0)
return 0;
}
- xmon_init();
+ xmon_init(1);
debugger(NULL);
return 0;
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
index 02b8ac4e016..f311ee7c007 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -13,6 +13,7 @@
#include <asm/current.h>
#include <asm/processor.h>
#include <asm/cputable.h>
+#include <asm/firmware.h>
#include <asm/hvcall.h>
#include <asm/prom.h>
#include <asm/systemcfg.h>
@@ -100,6 +101,8 @@ static int __init setup_smt_snooze_delay(char *str)
}
__setup("smt-snooze-delay=", setup_smt_snooze_delay);
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
/*
* Enabling PMCs will slow partition context switch times so we only do
* it the first time we write to the PMCs.
@@ -109,65 +112,15 @@ static DEFINE_PER_CPU(char, pmcs_enabled);
void ppc64_enable_pmcs(void)
{
- unsigned long hid0;
-#ifdef CONFIG_PPC_PSERIES
- unsigned long set, reset;
-#endif /* CONFIG_PPC_PSERIES */
-
/* Only need to enable them once */
if (__get_cpu_var(pmcs_enabled))
return;
__get_cpu_var(pmcs_enabled) = 1;
- switch (systemcfg->platform) {
- case PLATFORM_PSERIES:
- case PLATFORM_POWERMAC:
- hid0 = mfspr(HID0);
- hid0 |= 1UL << (63 - 20);
-
- /* POWER4 requires the following sequence */
- asm volatile(
- "sync\n"
- "mtspr %1, %0\n"
- "mfspr %0, %1\n"
- "mfspr %0, %1\n"
- "mfspr %0, %1\n"
- "mfspr %0, %1\n"
- "mfspr %0, %1\n"
- "mfspr %0, %1\n"
- "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0):
- "memory");
- break;
-
-#ifdef CONFIG_PPC_PSERIES
- case PLATFORM_PSERIES_LPAR:
- set = 1UL << 63;
- reset = 0;
- plpar_hcall_norets(H_PERFMON, set, reset);
- break;
-#endif /* CONFIG_PPC_PSERIES */
-
- default:
- break;
- }
-
-#ifdef CONFIG_PPC_PSERIES
- /* instruct hypervisor to maintain PMCs */
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
- get_paca()->lppaca.pmcregs_in_use = 1;
-#endif /* CONFIG_PPC_PSERIES */
+ if (ppc_md.enable_pmcs)
+ ppc_md.enable_pmcs();
}
-
-#else
-
-/* PMC stuff */
-void ppc64_enable_pmcs(void)
-{
- /* XXX Implement for iseries */
-}
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
EXPORT_SYMBOL(ppc64_enable_pmcs);
/* XXX convert to rusty's on_one_cpu */
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
index 909462e1ade..1696e1b05bb 100644
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -67,6 +67,7 @@
#include <asm/prom.h>
#include <asm/sections.h>
#include <asm/systemcfg.h>
+#include <asm/firmware.h>
u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
@@ -370,13 +371,11 @@ int timer_interrupt(struct pt_regs * regs)
process_hvlpevents(regs);
#endif
-/* collect purr register values often, for accurate calculations */
-#if defined(CONFIG_PPC_PSERIES)
- if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ /* collect purr register values often, for accurate calculations */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
cu->current_tb = mfspr(SPRN_PURR);
}
-#endif
irq_exit();
diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c
index 0c0ba71ac0e..c90e1dd875c 100644
--- a/arch/ppc64/kernel/vio.c
+++ b/arch/ppc64/kernel/vio.c
@@ -1,10 +1,11 @@
/*
* IBM PowerPC Virtual I/O Infrastructure Support.
*
- * Copyright (c) 2003 IBM Corp.
+ * Copyright (c) 2003-2005 IBM Corp.
* Dave Engebretsen engebret@us.ibm.com
* Santiago Leon santil@us.ibm.com
* Hollis Blanchard <hollisb@us.ibm.com>
+ * Stephen Rothwell
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,61 +15,30 @@
#include <linux/init.h>
#include <linux/console.h>
-#include <linux/version.h>
#include <linux/module.h>
-#include <linux/kobject.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
-#include <asm/rtas.h>
#include <asm/iommu.h>
#include <asm/dma.h>
-#include <asm/ppcdebug.h>
#include <asm/vio.h>
-#include <asm/hvcall.h>
-#include <asm/iSeries/vio.h>
-#include <asm/iSeries/HvTypes.h>
-#include <asm/iSeries/HvCallXm.h>
-#include <asm/iSeries/HvLpConfig.h>
-
-#define DBGENTER() pr_debug("%s entered\n", __FUNCTION__)
-
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
static const struct vio_device_id *vio_match_device(
const struct vio_device_id *, const struct vio_dev *);
-#ifdef CONFIG_PPC_PSERIES
-static struct iommu_table *vio_build_iommu_table(struct vio_dev *);
-static int vio_num_address_cells;
-#endif
-#ifdef CONFIG_PPC_ISERIES
-static struct iommu_table veth_iommu_table;
-static struct iommu_table vio_iommu_table;
-#endif
-static struct vio_dev vio_bus_device = { /* fake "parent" device */
+struct vio_dev vio_bus_device = { /* fake "parent" device */
.name = vio_bus_device.dev.bus_id,
.type = "",
-#ifdef CONFIG_PPC_ISERIES
- .iommu_table = &vio_iommu_table,
-#endif
.dev.bus_id = "vio",
.dev.bus = &vio_bus_type,
};
-#ifdef CONFIG_PPC_ISERIES
-static struct vio_dev *__init vio_register_device_iseries(char *type,
- uint32_t unit_num);
-
-struct device *iSeries_vio_dev = &vio_bus_device.dev;
-EXPORT_SYMBOL(iSeries_vio_dev);
-
-#define device_is_compatible(a, b) 1
+static struct vio_bus_ops vio_bus_ops;
-#endif
-
-/* 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);
@@ -76,15 +46,12 @@ static int vio_bus_probe(struct device *dev)
const struct vio_device_id *id;
int error = -ENODEV;
- DBGENTER();
-
if (!viodrv->probe)
return error;
id = vio_match_device(viodrv->id_table, viodev);
- if (id) {
+ if (id)
error = viodrv->probe(viodev, id);
- }
return error;
}
@@ -95,11 +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);
- DBGENTER();
-
- if (viodrv->remove) {
+ if (viodrv->remove)
return viodrv->remove(viodev);
- }
/* driver can't remove */
return 1;
@@ -135,193 +99,72 @@ 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)
{
- DBGENTER();
-
- while (ids->type) {
- if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
- device_is_compatible(dev->dev.platform_data, ids->compat))
+ while (ids->type[0] != '\0') {
+ if (vio_bus_ops.match(ids, dev))
return ids;
ids++;
}
return NULL;
}
-#ifdef CONFIG_PPC_ISERIES
-void __init iommu_vio_init(void)
-{
- struct iommu_table *t;
- struct iommu_table_cb cb;
- unsigned long cbp;
- unsigned long itc_entries;
-
- cb.itc_busno = 255; /* Bus 255 is the virtual bus */
- cb.itc_virtbus = 0xff; /* Ask for virtual bus */
-
- cbp = virt_to_abs(&cb);
- HvCallXm_getTceTableParms(cbp);
-
- itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
- veth_iommu_table.it_size = itc_entries / 2;
- veth_iommu_table.it_busno = cb.itc_busno;
- veth_iommu_table.it_offset = cb.itc_offset;
- veth_iommu_table.it_index = cb.itc_index;
- veth_iommu_table.it_type = TCE_VB;
- veth_iommu_table.it_blocksize = 1;
-
- t = iommu_init_table(&veth_iommu_table);
-
- if (!t)
- printk("Virtual Bus VETH TCE table failed.\n");
-
- vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size;
- vio_iommu_table.it_busno = cb.itc_busno;
- vio_iommu_table.it_offset = cb.itc_offset +
- veth_iommu_table.it_size;
- vio_iommu_table.it_index = cb.itc_index;
- vio_iommu_table.it_type = TCE_VB;
- vio_iommu_table.it_blocksize = 1;
-
- t = iommu_init_table(&vio_iommu_table);
-
- if (!t)
- printk("Virtual Bus VIO TCE table failed.\n");
-}
-#endif
-
-#ifdef CONFIG_PPC_PSERIES
-static void probe_bus_pseries(void)
-{
- struct device_node *node_vroot, *of_node;
-
- node_vroot = find_devices("vdevice");
- if ((node_vroot == NULL) || (node_vroot->child == NULL))
- /* this machine doesn't do virtual IO, and that's ok */
- return;
-
- vio_num_address_cells = prom_n_addr_cells(node_vroot->child);
-
- /*
- * Create struct vio_devices for each virtual device in the device tree.
- * Drivers will associate with them later.
- */
- for (of_node = node_vroot->child; of_node != NULL;
- of_node = of_node->sibling) {
- printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
- vio_register_device_node(of_node);
- }
-}
-#endif
-
-#ifdef CONFIG_PPC_ISERIES
-static void probe_bus_iseries(void)
-{
- HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap();
- struct vio_dev *viodev;
- int i;
-
- /* there is only one of each of these */
- vio_register_device_iseries("viocons", 0);
- vio_register_device_iseries("vscsi", 0);
-
- vlan_map = HvLpConfig_getVirtualLanIndexMap();
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- if ((vlan_map & (0x8000 >> i)) == 0)
- continue;
- viodev = vio_register_device_iseries("vlan", i);
- /* veth is special and has it own iommu_table */
- viodev->iommu_table = &veth_iommu_table;
- }
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
- vio_register_device_iseries("viodasd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
- vio_register_device_iseries("viocd", i);
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
- vio_register_device_iseries("viotape", i);
-}
-#endif
-
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
-static int __init vio_bus_init(void)
+int __init vio_bus_init(struct vio_bus_ops *ops)
{
int err;
+ vio_bus_ops = *ops;
+
err = bus_register(&vio_bus_type);
if (err) {
printk(KERN_ERR "failed to register VIO bus\n");
return err;
}
- /* the fake parent of all vio devices, just to give us a nice directory */
+ /*
+ * The fake parent of all vio devices, just to give us
+ * a nice directory
+ */
err = device_register(&vio_bus_device.dev);
if (err) {
- printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__,
- err);
+ printk(KERN_WARNING "%s: device_register returned %i\n",
+ __FUNCTION__, err);
return err;
}
-#ifdef CONFIG_PPC_PSERIES
- probe_bus_pseries();
-#endif
-#ifdef CONFIG_PPC_ISERIES
- probe_bus_iseries();
-#endif
-
return 0;
}
-__initcall(vio_bus_init);
-
/* vio_dev refcount hit 0 */
static void __devinit vio_dev_release(struct device *dev)
{
- DBGENTER();
-
-#ifdef CONFIG_PPC_PSERIES
- /* XXX free TCE table */
- of_node_put(dev->platform_data);
-#endif
+ if (vio_bus_ops.release_device)
+ vio_bus_ops.release_device(dev);
kfree(to_vio_dev(dev));
}
-#ifdef CONFIG_PPC_PSERIES
-static ssize_t viodev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct device_node *of_node = dev->platform_data;
-
- return sprintf(buf, "%s\n", of_node->full_name);
-}
-DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
-#endif
-
-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);
-static 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)
{
- DBGENTER();
-
- 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;
@@ -338,222 +181,15 @@ static struct vio_dev * __devinit vio_register_device_common(
return viodev;
}
-#ifdef CONFIG_PPC_PSERIES
-/**
- * vio_register_device_node: - Register a new vio device.
- * @of_node: The OF node for this device.
- *
- * Creates and initializes a vio_dev structure from the data in
- * of_node (dev.platform_data) and adds it to the list of virtual devices.
- * Returns a pointer to the created vio_dev or NULL if node has
- * NULL device_type or compatible fields.
- */
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
-{
- struct vio_dev *viodev;
- unsigned int *unit_address;
- unsigned int *irq_p;
-
- DBGENTER();
-
- /* we need the 'device_type' property, in order to match with drivers */
- if ((NULL == of_node->type)) {
- printk(KERN_WARNING
- "%s: node %s missing 'device_type'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
- if (!unit_address) {
- printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
- }
-
- /* allocate a vio_dev for this node */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev) {
- return NULL;
- }
- memset(viodev, 0, sizeof(struct vio_dev));
-
- viodev->dev.platform_data = of_node_get(of_node);
-
- viodev->irq = NO_IRQ;
- irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
- if (irq_p) {
- int virq = virt_irq_create_mapping(*irq_p);
- if (virq == NO_IRQ) {
- printk(KERN_ERR "Unable to allocate interrupt "
- "number for %s\n", of_node->full_name);
- } else
- viodev->irq = irq_offset_up(virq);
- }
-
- snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
-
- /* 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) {
- /* XXX free TCE table */
- kfree(viodev);
- return NULL;
- }
- device_create_file(&viodev->dev, &dev_attr_devspec);
-
- return viodev;
-}
-EXPORT_SYMBOL(vio_register_device_node);
-#endif
-
-#ifdef CONFIG_PPC_ISERIES
-/**
- * vio_register_device: - Register a new vio device.
- * @voidev: The device to register.
- */
-static struct vio_dev *__init vio_register_device_iseries(char *type,
- uint32_t unit_num)
-{
- struct vio_dev *viodev;
-
- DBGENTER();
-
- /* allocate a vio_dev for this node */
- viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (!viodev)
- return NULL;
- memset(viodev, 0, sizeof(struct vio_dev));
-
- 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);
-}
-#endif
-
void __devinit vio_unregister_device(struct vio_dev *viodev)
{
- DBGENTER();
-#ifdef CONFIG_PPC_PSERIES
- device_remove_file(&viodev->dev, &dev_attr_devspec);
-#endif
+ if (vio_bus_ops.unregister_device)
+ vio_bus_ops.unregister_device(viodev);
device_remove_file(&viodev->dev, &dev_attr_name);
device_unregister(&viodev->dev);
}
EXPORT_SYMBOL(vio_unregister_device);
-#ifdef CONFIG_PPC_PSERIES
-/**
- * vio_get_attribute: - get attribute for virtual device
- * @vdev: The vio device to get property.
- * @which: The property/attribute to be extracted.
- * @length: Pointer to length of returned data size (unused if NULL).
- *
- * Calls prom.c's get_property() to return the value of the
- * attribute specified by the preprocessor constant @which
-*/
-const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
-{
- return get_property(vdev->dev.platform_data, (char*)which, length);
-}
-EXPORT_SYMBOL(vio_get_attribute);
-
-/* vio_find_name() - internal because only vio.c knows how we formatted the
- * kobject name
- * XXX once vio_bus_type.devices is actually used as a kset in
- * drivers/base/bus.c, this function should be removed in favor of
- * "device_find(kobj_name, &vio_bus_type)"
- */
-static struct vio_dev *vio_find_name(const char *kobj_name)
-{
- struct kobject *found;
-
- found = kset_find_obj(&devices_subsys.kset, kobj_name);
- if (!found)
- return NULL;
-
- return to_vio_dev(container_of(found, struct device, kobj));
-}
-
-/**
- * vio_find_node - find an already-registered vio_dev
- * @vnode: device_node of the virtual device we're looking for
- */
-struct vio_dev *vio_find_node(struct device_node *vnode)
-{
- uint32_t *unit_address;
- char kobj_name[BUS_ID_SIZE];
-
- /* construct the kobject name from the device node */
- unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
- if (!unit_address)
- return NULL;
- snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
-
- return vio_find_name(kobj_name);
-}
-EXPORT_SYMBOL(vio_find_node);
-
-/**
- * vio_build_iommu_table: - gets the dma information from OF and builds the TCE tree.
- * @dev: the virtual device.
- *
- * Returns a pointer to the built tce tree, or NULL if it can't
- * find property.
-*/
-static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
-{
- unsigned int *dma_window;
- struct iommu_table *newTceTable;
- unsigned long offset;
- int dma_window_property_size;
-
- dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
- if(!dma_window) {
- return NULL;
- }
-
- newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
- /* There should be some code to extract the phys-encoded offset
- using prom_n_addr_cells(). However, according to a comment
- on earlier versions, it's always zero, so we don't bother */
- offset = dma_window[1] >> PAGE_SHIFT;
-
- /* TCE table size - measured in tce entries */
- newTceTable->it_size = dma_window[4] >> PAGE_SHIFT;
- /* offset for VIO should always be 0 */
- newTceTable->it_offset = offset;
- newTceTable->it_busno = 0;
- newTceTable->it_index = (unsigned long)dma_window[0];
- newTceTable->it_type = TCE_VB;
-
- return iommu_init_table(newTceTable);
-}
-
-int vio_enable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
- if (rc != H_Success) {
- printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
- }
- return rc;
-}
-EXPORT_SYMBOL(vio_enable_interrupts);
-
-int vio_disable_interrupts(struct vio_dev *dev)
-{
- int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
- if (rc != H_Success) {
- printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
- }
- return rc;
-}
-EXPORT_SYMBOL(vio_disable_interrupts);
-#endif
-
static dma_addr_t vio_map_single(struct device *dev, void *vaddr,
size_t size, enum dma_data_direction direction)
{
@@ -615,18 +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;
-
- DBGENTER();
- 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 = {
diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S
index fbff24827ae..35eb49e1b89 100644
--- a/arch/ppc64/mm/hash_low.S
+++ b/arch/ppc64/mm/hash_low.S
@@ -129,12 +129,10 @@ _GLOBAL(__hash_page)
* code rather than call a C function...)
*/
BEGIN_FTR_SECTION
-BEGIN_FTR_SECTION
mr r4,r30
mr r5,r7
bl .hash_page_do_lazy_icache
-END_FTR_SECTION_IFSET(CPU_FTR_NOEXECUTE)
-END_FTR_SECTION_IFCLR(CPU_FTR_COHERENT_ICACHE)
+END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
/* At this point, r3 contains new PP bits, save them in
* place of "access" in the param area (sic)
diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c
index a6abd3a979b..7626bb59954 100644
--- a/arch/ppc64/mm/hash_native.c
+++ b/arch/ppc64/mm/hash_native.c
@@ -51,7 +51,6 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long prpn, unsigned long vflags,
unsigned long rflags)
{
- unsigned long arpn = physRpn_to_absRpn(prpn);
hpte_t *hptep = htab_address + hpte_group;
unsigned long hpte_v, hpte_r;
int i;
@@ -74,7 +73,7 @@ long native_hpte_insert(unsigned long hpte_group, unsigned long va,
hpte_v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
if (vflags & HPTE_V_LARGE)
va &= ~(1UL << HPTE_V_AVPN_SHIFT);
- hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
+ hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags;
hptep->r = hpte_r;
/* Guarantee the second dword is visible before the valid bit */
diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
index 623b5d130c3..09475c8edf7 100644
--- a/arch/ppc64/mm/hash_utils.c
+++ b/arch/ppc64/mm/hash_utils.c
@@ -210,7 +210,7 @@ void __init htab_initialize(void)
/* create bolted the linear mapping in the hash table */
for (i=0; i < lmb.memory.cnt; i++) {
- base = lmb.memory.region[i].physbase + KERNELBASE;
+ base = lmb.memory.region[i].base + KERNELBASE;
size = lmb.memory.region[i].size;
DBG("creating mapping for region: %lx : %lx\n", base, size);
@@ -302,7 +302,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
int local = 0;
cpumask_t tmp;
- if ((ea & ~REGION_MASK) > EADDR_MASK)
+ if ((ea & ~REGION_MASK) >= PGTABLE_RANGE)
return 1;
switch (REGION_ID(ea)) {
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
index f9524602818..e7833c80eb6 100644
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -27,124 +27,94 @@
#include <linux/sysctl.h>
-#define HUGEPGDIR_SHIFT (HPAGE_SHIFT + PAGE_SHIFT - 3)
-#define HUGEPGDIR_SIZE (1UL << HUGEPGDIR_SHIFT)
-#define HUGEPGDIR_MASK (~(HUGEPGDIR_SIZE-1))
+#define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT)
+#define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT)
-#define HUGEPTE_INDEX_SIZE 9
-#define HUGEPGD_INDEX_SIZE 10
-
-#define PTRS_PER_HUGEPTE (1 << HUGEPTE_INDEX_SIZE)
-#define PTRS_PER_HUGEPGD (1 << HUGEPGD_INDEX_SIZE)
-
-static inline int hugepgd_index(unsigned long addr)
-{
- return (addr & ~REGION_MASK) >> HUGEPGDIR_SHIFT;
-}
-
-static pud_t *hugepgd_offset(struct mm_struct *mm, unsigned long addr)
+/* Modelled after find_linux_pte() */
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
- int index;
+ pgd_t *pg;
+ pud_t *pu;
+ pmd_t *pm;
+ pte_t *pt;
- if (! mm->context.huge_pgdir)
- return NULL;
+ BUG_ON(! in_hugepage_area(mm->context, addr));
+ addr &= HPAGE_MASK;
+
+ pg = pgd_offset(mm, addr);
+ if (!pgd_none(*pg)) {
+ pu = pud_offset(pg, addr);
+ if (!pud_none(*pu)) {
+ pm = pmd_offset(pu, addr);
+ pt = (pte_t *)pm;
+ BUG_ON(!pmd_none(*pm)
+ && !(pte_present(*pt) && pte_huge(*pt)));
+ return pt;
+ }
+ }
- index = hugepgd_index(addr);
- BUG_ON(index >= PTRS_PER_HUGEPGD);
- return (pud_t *)(mm->context.huge_pgdir + index);
+ return NULL;
}
-static inline pte_t *hugepte_offset(pud_t *dir, unsigned long addr)
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
- int index;
-
- if (pud_none(*dir))
- return NULL;
+ pgd_t *pg;
+ pud_t *pu;
+ pmd_t *pm;
+ pte_t *pt;
- index = (addr >> HPAGE_SHIFT) % PTRS_PER_HUGEPTE;
- return (pte_t *)pud_page(*dir) + index;
-}
-
-static pud_t *hugepgd_alloc(struct mm_struct *mm, unsigned long addr)
-{
BUG_ON(! in_hugepage_area(mm->context, addr));
- if (! mm->context.huge_pgdir) {
- pgd_t *new;
- spin_unlock(&mm->page_table_lock);
- /* Don't use pgd_alloc(), because we want __GFP_REPEAT */
- new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);
- BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));
- spin_lock(&mm->page_table_lock);
+ addr &= HPAGE_MASK;
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (mm->context.huge_pgdir)
- pgd_free(new);
- else
- mm->context.huge_pgdir = new;
- }
- return hugepgd_offset(mm, addr);
-}
+ pg = pgd_offset(mm, addr);
+ pu = pud_alloc(mm, pg, addr);
-static pte_t *hugepte_alloc(struct mm_struct *mm, pud_t *dir, unsigned long addr)
-{
- if (! pud_present(*dir)) {
- pte_t *new;
-
- spin_unlock(&mm->page_table_lock);
- new = kmem_cache_alloc(zero_cache, GFP_KERNEL | __GFP_REPEAT);
- BUG_ON(memcmp(new, empty_zero_page, PAGE_SIZE));
- spin_lock(&mm->page_table_lock);
- /*
- * Because we dropped the lock, we should re-check the
- * entry, as somebody else could have populated it..
- */
- if (pud_present(*dir)) {
- if (new)
- kmem_cache_free(zero_cache, new);
- } else {
- struct page *ptepage;
-
- if (! new)
- return NULL;
- ptepage = virt_to_page(new);
- ptepage->mapping = (void *) mm;
- ptepage->index = addr & HUGEPGDIR_MASK;
- pud_populate(mm, dir, new);
+ if (pu) {
+ pm = pmd_alloc(mm, pu, addr);
+ if (pm) {
+ pt = (pte_t *)pm;
+ BUG_ON(!pmd_none(*pm)
+ && !(pte_present(*pt) && pte_huge(*pt)));
+ return pt;
}
}
- return hugepte_offset(dir, addr);
+ return NULL;
}
-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
-{
- pud_t *pud;
+#define HUGEPTE_BATCH_SIZE (HPAGE_SIZE / PMD_SIZE)
- BUG_ON(! in_hugepage_area(mm->context, addr));
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ int i;
- pud = hugepgd_offset(mm, addr);
- if (! pud)
- return NULL;
+ if (pte_present(*ptep)) {
+ pte_clear(mm, addr, ptep);
+ flush_tlb_pending();
+ }
- return hugepte_offset(pud, addr);
+ for (i = 0; i < HUGEPTE_BATCH_SIZE; i++) {
+ *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+ ptep++;
+ }
}
-pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
{
- pud_t *pud;
+ unsigned long old = pte_update(ptep, ~0UL);
+ int i;
- BUG_ON(! in_hugepage_area(mm->context, addr));
+ if (old & _PAGE_HASHPTE)
+ hpte_update(mm, addr, old, 0);
- pud = hugepgd_alloc(mm, addr);
- if (! pud)
- return NULL;
+ for (i = 1; i < HUGEPTE_BATCH_SIZE; i++)
+ ptep[i] = __pte(0);
- return hugepte_alloc(mm, pud, addr);
+ return __pte(old);
}
/*
@@ -162,15 +132,17 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
return 0;
}
-static void flush_segments(void *parm)
+static void flush_low_segments(void *parm)
{
- u16 segs = (unsigned long) parm;
+ u16 areas = (unsigned long) parm;
unsigned long i;
asm volatile("isync" : : : "memory");
- for (i = 0; i < 16; i++) {
- if (! (segs & (1U << i)))
+ BUILD_BUG_ON((sizeof(areas)*8) != NUM_LOW_AREAS);
+
+ for (i = 0; i < NUM_LOW_AREAS; i++) {
+ if (! (areas & (1U << i)))
continue;
asm volatile("slbie %0" : : "r" (i << SID_SHIFT));
}
@@ -178,13 +150,33 @@ static void flush_segments(void *parm)
asm volatile("isync" : : : "memory");
}
-static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg)
+static void flush_high_segments(void *parm)
{
- unsigned long start = seg << SID_SHIFT;
- unsigned long end = (seg+1) << SID_SHIFT;
+ u16 areas = (unsigned long) parm;
+ unsigned long i, j;
+
+ asm volatile("isync" : : : "memory");
+
+ BUILD_BUG_ON((sizeof(areas)*8) != NUM_HIGH_AREAS);
+
+ for (i = 0; i < NUM_HIGH_AREAS; i++) {
+ if (! (areas & (1U << i)))
+ continue;
+ for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
+ asm volatile("slbie %0"
+ :: "r" ((i << HTLB_AREA_SHIFT) + (j << SID_SHIFT)));
+ }
+
+ asm volatile("isync" : : : "memory");
+}
+
+static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
+{
+ unsigned long start = area << SID_SHIFT;
+ unsigned long end = (area+1) << SID_SHIFT;
struct vm_area_struct *vma;
- BUG_ON(seg >= 16);
+ BUG_ON(area >= NUM_LOW_AREAS);
/* Check no VMAs are in the region */
vma = find_vma(mm, start);
@@ -194,20 +186,39 @@ static int prepare_low_seg_for_htlb(struct mm_struct *mm, unsigned long seg)
return 0;
}
-static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs)
+static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
+{
+ unsigned long start = area << HTLB_AREA_SHIFT;
+ unsigned long end = (area+1) << HTLB_AREA_SHIFT;
+ struct vm_area_struct *vma;
+
+ BUG_ON(area >= NUM_HIGH_AREAS);
+
+ /* Check no VMAs are in the region */
+ vma = find_vma(mm, start);
+ if (vma && (vma->vm_start < end))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
{
unsigned long i;
- newsegs &= ~(mm->context.htlb_segs);
- if (! newsegs)
+ BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
+ BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
+
+ newareas &= ~(mm->context.low_htlb_areas);
+ if (! newareas)
return 0; /* The segments we want are already open */
- for (i = 0; i < 16; i++)
- if ((1 << i) & newsegs)
- if (prepare_low_seg_for_htlb(mm, i) != 0)
+ for (i = 0; i < NUM_LOW_AREAS; i++)
+ if ((1 << i) & newareas)
+ if (prepare_low_area_for_htlb(mm, i) != 0)
return -EBUSY;
- mm->context.htlb_segs |= newsegs;
+ mm->context.low_htlb_areas |= newareas;
/* update the paca copy of the context struct */
get_paca()->context = mm->context;
@@ -215,29 +226,63 @@ static int open_low_hpage_segs(struct mm_struct *mm, u16 newsegs)
/* the context change must make it to memory before the flush,
* so that further SLB misses do the right thing. */
mb();
- on_each_cpu(flush_segments, (void *)(unsigned long)newsegs, 0, 1);
+ on_each_cpu(flush_low_segments, (void *)(unsigned long)newareas, 0, 1);
+
+ return 0;
+}
+
+static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
+{
+ unsigned long i;
+
+ BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
+ BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
+ != NUM_HIGH_AREAS);
+
+ newareas &= ~(mm->context.high_htlb_areas);
+ if (! newareas)
+ return 0; /* The areas we want are already open */
+
+ for (i = 0; i < NUM_HIGH_AREAS; i++)
+ if ((1 << i) & newareas)
+ if (prepare_high_area_for_htlb(mm, i) != 0)
+ return -EBUSY;
+
+ mm->context.high_htlb_areas |= newareas;
+
+ /* update the paca copy of the context struct */
+ get_paca()->context = mm->context;
+
+ /* the context change must make it to memory before the flush,
+ * so that further SLB misses do the right thing. */
+ mb();
+ on_each_cpu(flush_high_segments, (void *)(unsigned long)newareas, 0, 1);
return 0;
}
int prepare_hugepage_range(unsigned long addr, unsigned long len)
{
- if (within_hugepage_high_range(addr, len))
- return 0;
- else if ((addr < 0x100000000UL) && ((addr+len) < 0x100000000UL)) {
- int err;
- /* Yes, we need both tests, in case addr+len overflows
- * 64-bit arithmetic */
- err = open_low_hpage_segs(current->mm,
+ int err;
+
+ if ( (addr+len) < addr )
+ return -EINVAL;
+
+ if ((addr + len) < 0x100000000UL)
+ err = open_low_hpage_areas(current->mm,
LOW_ESID_MASK(addr, len));
- if (err)
- printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
- " failed (segs: 0x%04hx)\n", addr, len,
- LOW_ESID_MASK(addr, len));
+ else
+ err = open_high_hpage_areas(current->mm,
+ HTLB_AREA_MASK(addr, len));
+ if (err) {
+ printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
+ " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
+ addr, len,
+ LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
return err;
}
- return -EINVAL;
+ return 0;
}
struct page *
@@ -309,8 +354,8 @@ full_search:
vma = find_vma(mm, addr);
continue;
}
- if (touches_hugepage_high_range(addr, len)) {
- addr = TASK_HPAGE_END;
+ if (touches_hugepage_high_range(mm, addr, len)) {
+ addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
vma = find_vma(mm, addr);
continue;
}
@@ -389,8 +434,9 @@ hugepage_recheck:
if (touches_hugepage_low_range(mm, addr, len)) {
addr = (addr & ((~0) << SID_SHIFT)) - len;
goto hugepage_recheck;
- } else if (touches_hugepage_high_range(addr, len)) {
- addr = TASK_HPAGE_BASE - len;
+ } else if (touches_hugepage_high_range(mm, addr, len)) {
+ addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
+ goto hugepage_recheck;
}
/*
@@ -481,23 +527,28 @@ static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
return -ENOMEM;
}
-static unsigned long htlb_get_high_area(unsigned long len)
+static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
{
- unsigned long addr = TASK_HPAGE_BASE;
+ unsigned long addr = 0x100000000UL;
struct vm_area_struct *vma;
vma = find_vma(current->mm, addr);
- for (vma = find_vma(current->mm, addr);
- addr + len <= TASK_HPAGE_END;
- vma = vma->vm_next) {
+ while (addr + len <= TASK_SIZE_USER64) {
BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
- BUG_ON(! within_hugepage_high_range(addr, len));
+
+ if (! __within_hugepage_high_range(addr, len, areamask)) {
+ addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
+ vma = find_vma(current->mm, addr);
+ continue;
+ }
if (!vma || (addr + len) <= vma->vm_start)
return addr;
addr = ALIGN(vma->vm_end, HPAGE_SIZE);
- /* Because we're in a hugepage region, this alignment
- * should not skip us over any VMAs */
+ /* Depending on segmask this might not be a confirmed
+ * hugepage region, so the ALIGN could have skipped
+ * some VMAs */
+ vma = find_vma(current->mm, addr);
}
return -ENOMEM;
@@ -507,6 +558,9 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
unsigned long len, unsigned long pgoff,
unsigned long flags)
{
+ int lastshift;
+ u16 areamask, curareas;
+
if (len & ~HPAGE_MASK)
return -EINVAL;
@@ -514,67 +568,49 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
return -EINVAL;
if (test_thread_flag(TIF_32BIT)) {
- int lastshift = 0;
- u16 segmask, cursegs = current->mm->context.htlb_segs;
+ curareas = current->mm->context.low_htlb_areas;
/* First see if we can do the mapping in the existing
- * low hpage segments */
- addr = htlb_get_low_area(len, cursegs);
+ * low areas */
+ addr = htlb_get_low_area(len, curareas);
if (addr != -ENOMEM)
return addr;
- for (segmask = LOW_ESID_MASK(0x100000000UL-len, len);
- ! lastshift; segmask >>=1) {
- if (segmask & 1)
+ lastshift = 0;
+ for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
+ ! lastshift; areamask >>=1) {
+ if (areamask & 1)
lastshift = 1;
- addr = htlb_get_low_area(len, cursegs | segmask);
+ addr = htlb_get_low_area(len, curareas | areamask);
if ((addr != -ENOMEM)
- && open_low_hpage_segs(current->mm, segmask) == 0)
+ && open_low_hpage_areas(current->mm, areamask) == 0)
return addr;
}
- printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
- " enough segments\n");
- return -ENOMEM;
} else {
- return htlb_get_high_area(len);
- }
-}
-
-void hugetlb_mm_free_pgd(struct mm_struct *mm)
-{
- int i;
- pgd_t *pgdir;
-
- spin_lock(&mm->page_table_lock);
-
- pgdir = mm->context.huge_pgdir;
- if (! pgdir)
- goto out;
-
- mm->context.huge_pgdir = NULL;
+ curareas = current->mm->context.high_htlb_areas;
- /* cleanup any hugepte pages leftover */
- for (i = 0; i < PTRS_PER_HUGEPGD; i++) {
- pud_t *pud = (pud_t *)(pgdir + i);
-
- if (! pud_none(*pud)) {
- pte_t *pte = (pte_t *)pud_page(*pud);
- struct page *ptepage = virt_to_page(pte);
+ /* First see if we can do the mapping in the existing
+ * high areas */
+ addr = htlb_get_high_area(len, curareas);
+ if (addr != -ENOMEM)
+ return addr;
- ptepage->mapping = NULL;
+ lastshift = 0;
+ for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
+ ! lastshift; areamask >>=1) {
+ if (areamask & 1)
+ lastshift = 1;
- BUG_ON(memcmp(pte, empty_zero_page, PAGE_SIZE));
- kmem_cache_free(zero_cache, pte);
+ addr = htlb_get_high_area(len, curareas | areamask);
+ if ((addr != -ENOMEM)
+ && open_high_hpage_areas(current->mm, areamask) == 0)
+ return addr;
}
- pud_clear(pud);
}
-
- BUG_ON(memcmp(pgdir, empty_zero_page, PAGE_SIZE));
- kmem_cache_free(zero_cache, pgdir);
-
- out:
- spin_unlock(&mm->page_table_lock);
+ printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
+ " enough areas\n");
+ return -ENOMEM;
}
int hash_huge_page(struct mm_struct *mm, unsigned long access,
diff --git a/arch/ppc64/mm/imalloc.c b/arch/ppc64/mm/imalloc.c
index b6e75b891ac..c65b87b9275 100644
--- a/arch/ppc64/mm/imalloc.c
+++ b/arch/ppc64/mm/imalloc.c
@@ -31,7 +31,7 @@ static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
break;
if ((unsigned long)tmp->addr >= ioremap_bot)
addr = tmp->size + (unsigned long) tmp->addr;
- if (addr > IMALLOC_END-size)
+ if (addr >= IMALLOC_END-size)
return 1;
}
*im_addr = addr;
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index e58a24d4287..c02dc9809ca 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -42,7 +42,6 @@
#include <asm/pgalloc.h>
#include <asm/page.h>
-#include <asm/abs_addr.h>
#include <asm/prom.h>
#include <asm/lmb.h>
#include <asm/rtas.h>
@@ -66,6 +65,14 @@
#include <asm/vdso.h>
#include <asm/imalloc.h>
+#if PGTABLE_RANGE > USER_VSID_RANGE
+#warning Limited user VSID range means pagetable space is wasted
+#endif
+
+#if (TASK_SIZE_USER64 < PGTABLE_RANGE) && (TASK_SIZE_USER64 < USER_VSID_RANGE)
+#warning TASK_SIZE is smaller than it needs to be.
+#endif
+
int mem_init_done;
unsigned long ioremap_bot = IMALLOC_BASE;
static unsigned long phbs_io_bot = PHBS_IO_BASE;
@@ -159,7 +166,6 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
ptep = pte_alloc_kernel(&init_mm, pmdp, ea);
if (!ptep)
return -ENOMEM;
- pa = abs_to_phys(pa);
set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
__pgprot(flags)));
spin_unlock(&init_mm.page_table_lock);
@@ -226,7 +232,7 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size,
* Before that, we map using addresses going
* up from ioremap_bot. imalloc will use
* the addresses from ioremap_bot through
- * IMALLOC_END (0xE000001fffffffff)
+ * IMALLOC_END
*
*/
pa = addr & PAGE_MASK;
@@ -417,12 +423,6 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
int index;
int err;
-#ifdef CONFIG_HUGETLB_PAGE
- /* We leave htlb_segs as it was, but for a fork, we need to
- * clear the huge_pgdir. */
- mm->context.huge_pgdir = NULL;
-#endif
-
again:
if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
return -ENOMEM;
@@ -453,8 +453,6 @@ void destroy_context(struct mm_struct *mm)
spin_unlock(&mmu_context_lock);
mm->context.id = NO_CONTEXT;
-
- hugetlb_mm_free_pgd(mm);
}
/*
@@ -484,9 +482,9 @@ void __init mm_init_ppc64(void)
for (i = 1; i < lmb.memory.cnt; i++) {
unsigned long base, prevbase, prevsize;
- prevbase = lmb.memory.region[i-1].physbase;
+ prevbase = lmb.memory.region[i-1].base;
prevsize = lmb.memory.region[i-1].size;
- base = lmb.memory.region[i].physbase;
+ base = lmb.memory.region[i].base;
if (base > (prevbase + prevsize)) {
io_hole_start = prevbase + prevsize;
io_hole_size = base - (prevbase + prevsize);
@@ -513,11 +511,8 @@ int page_is_ram(unsigned long pfn)
for (i=0; i < lmb.memory.cnt; i++) {
unsigned long base;
-#ifdef CONFIG_MSCHUNKS
- base = lmb.memory.region[i].physbase;
-#else
base = lmb.memory.region[i].base;
-#endif
+
if ((paddr >= base) &&
(paddr < (base + lmb.memory.region[i].size))) {
return 1;
@@ -547,7 +542,7 @@ void __init do_init_bootmem(void)
*/
bootmap_pages = bootmem_bootmap_pages(total_pages);
- start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
+ start = lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
BUG_ON(!start);
boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
@@ -558,25 +553,25 @@ void __init do_init_bootmem(void)
* present.
*/
for (i=0; i < lmb.memory.cnt; i++) {
- unsigned long physbase, size;
+ unsigned long base, size;
unsigned long start_pfn, end_pfn;
- physbase = lmb.memory.region[i].physbase;
+ base = lmb.memory.region[i].base;
size = lmb.memory.region[i].size;
- start_pfn = physbase >> PAGE_SHIFT;
+ start_pfn = base >> PAGE_SHIFT;
end_pfn = start_pfn + (size >> PAGE_SHIFT);
memory_present(0, start_pfn, end_pfn);
- free_bootmem(physbase, size);
+ free_bootmem(base, size);
}
/* reserve the sections we're already using */
for (i=0; i < lmb.reserved.cnt; i++) {
- unsigned long physbase = lmb.reserved.region[i].physbase;
+ unsigned long base = lmb.reserved.region[i].base;
unsigned long size = lmb.reserved.region[i].size;
- reserve_bootmem(physbase, size);
+ reserve_bootmem(base, size);
}
}
@@ -615,10 +610,10 @@ static int __init setup_kcore(void)
int i;
for (i=0; i < lmb.memory.cnt; i++) {
- unsigned long physbase, size;
+ unsigned long base, size;
struct kcore_list *kcore_mem;
- physbase = lmb.memory.region[i].physbase;
+ base = lmb.memory.region[i].base;
size = lmb.memory.region[i].size;
/* GFP_ATOMIC to avoid might_sleep warnings during boot */
@@ -626,7 +621,7 @@ static int __init setup_kcore(void)
if (!kcore_mem)
panic("mem_init: kmalloc failed\n");
- kclist_add(kcore_mem, __va(physbase), size);
+ kclist_add(kcore_mem, __va(base), size);
}
kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);
@@ -686,9 +681,6 @@ void __init mem_init(void)
mem_init_done = 1;
-#ifdef CONFIG_PPC_ISERIES
- iommu_vio_init();
-#endif
/* Initialize the vDSO */
vdso_init();
}
@@ -833,23 +825,43 @@ void __iomem * reserve_phb_iospace(unsigned long size)
return virt_addr;
}
-kmem_cache_t *zero_cache;
-
-static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+static void zero_ctor(void *addr, kmem_cache_t *cache, unsigned long flags)
{
- memset(pte, 0, PAGE_SIZE);
+ memset(addr, 0, kmem_cache_size(cache));
}
+static const int pgtable_cache_size[2] = {
+ PTE_TABLE_SIZE, PMD_TABLE_SIZE
+};
+static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
+ "pgd_pte_cache", "pud_pmd_cache",
+};
+
+kmem_cache_t *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)];
+
void pgtable_cache_init(void)
{
- zero_cache = kmem_cache_create("zero",
- PAGE_SIZE,
- 0,
- SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
- zero_ctor,
- NULL);
- if (!zero_cache)
- panic("pgtable_cache_init(): could not create zero_cache!\n");
+ int i;
+
+ BUILD_BUG_ON(PTE_TABLE_SIZE != pgtable_cache_size[PTE_CACHE_NUM]);
+ BUILD_BUG_ON(PMD_TABLE_SIZE != pgtable_cache_size[PMD_CACHE_NUM]);
+ BUILD_BUG_ON(PUD_TABLE_SIZE != pgtable_cache_size[PUD_CACHE_NUM]);
+ BUILD_BUG_ON(PGD_TABLE_SIZE != pgtable_cache_size[PGD_CACHE_NUM]);
+
+ for (i = 0; i < ARRAY_SIZE(pgtable_cache_size); i++) {
+ int size = pgtable_cache_size[i];
+ const char *name = pgtable_cache_name[i];
+
+ pgtable_cache[i] = kmem_cache_create(name,
+ size, size,
+ SLAB_HWCACHE_ALIGN
+ | SLAB_MUST_HWCACHE_ALIGN,
+ zero_ctor,
+ NULL);
+ if (! pgtable_cache[i])
+ panic("pgtable_cache_init(): could not create %s!\n",
+ name);
+ }
}
pgprot_t phys_mem_access_prot(struct file *file, unsigned long addr,
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index 0b191f2de01..c3116f0d788 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -671,7 +671,7 @@ new_range:
* Mark reserved regions on this node
*/
for (i = 0; i < lmb.reserved.cnt; i++) {
- unsigned long physbase = lmb.reserved.region[i].physbase;
+ unsigned long physbase = lmb.reserved.region[i].base;
unsigned long size = lmb.reserved.region[i].size;
if (pa_to_nid(physbase) != nid &&
diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S
index 8379d678f70..698d6b9ed6d 100644
--- a/arch/ppc64/mm/slb_low.S
+++ b/arch/ppc64/mm/slb_low.S
@@ -89,32 +89,29 @@ END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
b 9f
0: /* user address: proto-VSID = context<<15 | ESID */
- li r11,SLB_VSID_USER
-
- srdi. r9,r3,13
+ srdi. r9,r3,USER_ESID_BITS
bne- 8f /* invalid ea bits set */
#ifdef CONFIG_HUGETLB_PAGE
BEGIN_FTR_SECTION
- /* check against the hugepage ranges */
- cmpldi r3,(TASK_HPAGE_END>>SID_SHIFT)
- bge 6f /* >= TASK_HPAGE_END */
- cmpldi r3,(TASK_HPAGE_BASE>>SID_SHIFT)
- bge 5f /* TASK_HPAGE_BASE..TASK_HPAGE_END */
- cmpldi r3,16
- bge 6f /* 4GB..TASK_HPAGE_BASE */
-
- lhz r9,PACAHTLBSEGS(r13)
- srd r9,r9,r3
- andi. r9,r9,1
- beq 6f
-
-5: /* this is a hugepage user address */
- li r11,(SLB_VSID_USER|SLB_VSID_L)
+ lhz r9,PACAHIGHHTLBAREAS(r13)
+ srdi r11,r3,(HTLB_AREA_SHIFT-SID_SHIFT)
+ srd r9,r9,r11
+ lhz r11,PACALOWHTLBAREAS(r13)
+ srd r11,r11,r3
+ or r9,r9,r11
+END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
+#endif /* CONFIG_HUGETLB_PAGE */
+
+ li r11,SLB_VSID_USER
+
+#ifdef CONFIG_HUGETLB_PAGE
+BEGIN_FTR_SECTION
+ rldimi r11,r9,8,55 /* shift masked bit into SLB_VSID_L */
END_FTR_SECTION_IFSET(CPU_FTR_16M_PAGE)
#endif /* CONFIG_HUGETLB_PAGE */
-6: ld r9,PACACONTEXTID(r13)
+ ld r9,PACACONTEXTID(r13)
rldimi r3,r9,USER_ESID_BITS,0
9: /* r3 = protovsid, r11 = flags, r10 = esid_data, cr7 = <>KERNELBASE */
diff --git a/arch/ppc64/mm/tlb.c b/arch/ppc64/mm/tlb.c
index 26f0172c452..d8a6593a13f 100644
--- a/arch/ppc64/mm/tlb.c
+++ b/arch/ppc64/mm/tlb.c
@@ -41,7 +41,58 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
unsigned long pte_freelist_forced_free;
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
+struct pte_freelist_batch
+{
+ struct rcu_head rcu;
+ unsigned int index;
+ pgtable_free_t tables[0];
+};
+
+DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
+unsigned long pte_freelist_forced_free;
+
+#define PTE_FREELIST_SIZE \
+ ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
+ / sizeof(pgtable_free_t))
+
+#ifdef CONFIG_SMP
+static void pte_free_smp_sync(void *arg)
+{
+ /* Do nothing, just ensure we sync with all CPUs */
+}
+#endif
+
+/* This is only called when we are critically out of memory
+ * (and fail to get a page in pte_free_tlb).
+ */
+static void pgtable_free_now(pgtable_free_t pgf)
+{
+ pte_freelist_forced_free++;
+
+ smp_call_function(pte_free_smp_sync, NULL, 0, 1);
+
+ pgtable_free(pgf);
+}
+
+static void pte_free_rcu_callback(struct rcu_head *head)
+{
+ struct pte_freelist_batch *batch =
+ container_of(head, struct pte_freelist_batch, rcu);
+ unsigned int i;
+
+ for (i = 0; i < batch->index; i++)
+ pgtable_free(batch->tables[i]);
+
+ free_page((unsigned long)batch);
+}
+
+static void pte_free_submit(struct pte_freelist_batch *batch)
+{
+ INIT_RCU_HEAD(&batch->rcu);
+ call_rcu(&batch->rcu, pte_free_rcu_callback);
+}
+
+void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
{
/* This is safe as we are holding page_table_lock */
cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
@@ -49,19 +100,19 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
if (atomic_read(&tlb->mm->mm_users) < 2 ||
cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
- pte_free(ptepage);
+ pgtable_free(pgf);
return;
}
if (*batchp == NULL) {
*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
if (*batchp == NULL) {
- pte_free_now(ptepage);
+ pgtable_free_now(pgf);
return;
}
(*batchp)->index = 0;
}
- (*batchp)->pages[(*batchp)->index++] = ptepage;
+ (*batchp)->tables[(*batchp)->index++] = pgf;
if ((*batchp)->index == PTE_FREELIST_SIZE) {
pte_free_submit(*batchp);
*batchp = NULL;
@@ -132,42 +183,6 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
put_cpu();
}
-#ifdef CONFIG_SMP
-static void pte_free_smp_sync(void *arg)
-{
- /* Do nothing, just ensure we sync with all CPUs */
-}
-#endif
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-void pte_free_now(struct page *ptepage)
-{
- pte_freelist_forced_free++;
-
- smp_call_function(pte_free_smp_sync, NULL, 0, 1);
-
- pte_free(ptepage);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
- struct pte_freelist_batch *batch =
- container_of(head, struct pte_freelist_batch, rcu);
- unsigned int i;
-
- for (i = 0; i < batch->index; i++)
- pte_free(batch->pages[i]);
- free_page((unsigned long)batch);
-}
-
-void pte_free_submit(struct pte_freelist_batch *batch)
-{
- INIT_RCU_HEAD(&batch->rcu);
- call_rcu(&batch->rcu, pte_free_rcu_callback);
-}
-
void pte_free_finish(void)
{
/* This is safe as we are holding page_table_lock */
diff --git a/arch/ppc64/oprofile/common.c b/arch/ppc64/oprofile/common.c
index b28bfda23d9..4acd1a42493 100644
--- a/arch/ppc64/oprofile/common.c
+++ b/arch/ppc64/oprofile/common.c
@@ -153,6 +153,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case PV_970:
case PV_970FX:
+ case PV_970MP:
model = &op_model_power4;
model->num_counters = 8;
ops->cpu_type = "ppc64/970";
diff --git a/arch/ppc64/xmon/start.c b/arch/ppc64/xmon/start.c
index a9265bcc79b..f86b584acd7 100644
--- a/arch/ppc64/xmon/start.c
+++ b/arch/ppc64/xmon/start.c
@@ -27,7 +27,7 @@ static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
struct tty_struct *tty)
{
/* ensure xmon is enabled */
- xmon_init();
+ xmon_init(1);
debugger(pt_regs);
}
diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
index 05539439e6b..45908b10acd 100644
--- a/arch/ppc64/xmon/xmon.c
+++ b/arch/ppc64/xmon/xmon.c
@@ -2496,15 +2496,25 @@ static void dump_stab(void)
}
}
-void xmon_init(void)
-{
- __debugger = xmon;
- __debugger_ipi = xmon_ipi;
- __debugger_bpt = xmon_bpt;
- __debugger_sstep = xmon_sstep;
- __debugger_iabr_match = xmon_iabr_match;
- __debugger_dabr_match = xmon_dabr_match;
- __debugger_fault_handler = xmon_fault_handler;
+void xmon_init(int enable)
+{
+ if (enable) {
+ __debugger = xmon;
+ __debugger_ipi = xmon_ipi;
+ __debugger_bpt = xmon_bpt;
+ __debugger_sstep = xmon_sstep;
+ __debugger_iabr_match = xmon_iabr_match;
+ __debugger_dabr_match = xmon_dabr_match;
+ __debugger_fault_handler = xmon_fault_handler;
+ } else {
+ __debugger = NULL;
+ __debugger_ipi = NULL;
+ __debugger_bpt = NULL;
+ __debugger_sstep = NULL;
+ __debugger_iabr_match = NULL;
+ __debugger_dabr_match = NULL;
+ __debugger_fault_handler = NULL;
+ }
}
void dump_segments(void)
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 55352ed85e8..53c192a4982 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -32,7 +32,6 @@
#include <linux/spinlock.h>
#include <linux/root_dev.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index fd8005a3e6b..591547af4c6 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <asm/oplib.h>
-#include <asm/segment.h>
#include <asm/timer.h>
#include <asm/mostek.h>
#include <asm/system.h>
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 6486cbf2efe..3b759aefc17 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -32,7 +32,6 @@
#include <linux/profile.h>
#include <asm/oplib.h>
-#include <asm/segment.h>
#include <asm/timer.h>
#include <asm/mostek.h>
#include <asm/system.h>
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 37f4107bae6..2bbd53f3caf 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/memreg.h>
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index ec2e05028a1..c03babaa049 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -25,7 +25,6 @@
#include <linux/bootmem.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/vac-ops.h>
#include <asm/page.h>
#include <asm/pgtable.h>
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 88332f00094..cecdc0a7521 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -21,6 +21,7 @@
#include <asm/visasm.h>
#include <asm/estate.h>
#include <asm/auxio.h>
+#include <asm/sfafsr.h>
#define curptr g6
@@ -690,14 +691,159 @@ netbsd_syscall:
retl
nop
- /* These next few routines must be sure to clear the
- * SFSR FaultValid bit so that the fast tlb data protection
- * handler does not flush the wrong context and lock up the
- * box.
+ /* We need to carefully read the error status, ACK
+ * the errors, prevent recursive traps, and pass the
+ * information on to C code for logging.
+ *
+ * We pass the AFAR in as-is, and we encode the status
+ * information as described in asm-sparc64/sfafsr.h
+ */
+ .globl __spitfire_access_error
+__spitfire_access_error:
+ /* Disable ESTATE error reporting so that we do not
+ * take recursive traps and RED state the processor.
+ */
+ stxa %g0, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ mov UDBE_UE, %g1
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+
+ /* __spitfire_cee_trap branches here with AFSR in %g4 and
+ * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the
+ * ESTATE Error Enable register.
+ */
+__spitfire_cee_trap_continue:
+ ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR
+
+ rdpr %tt, %g3
+ and %g3, 0x1ff, %g3 ! Paranoia
+ sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3
+ or %g4, %g3, %g4
+ rdpr %tl, %g3
+ cmp %g3, 1
+ mov 1, %g3
+ bleu %xcc, 1f
+ sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3
+
+ or %g4, %g3, %g4
+
+ /* Read in the UDB error register state, clearing the
+ * sticky error bits as-needed. We only clear them if
+ * the UE bit is set. Likewise, __spitfire_cee_trap
+ * below will only do so if the CE bit is set.
+ *
+ * NOTE: UltraSparc-I/II have high and low UDB error
+ * registers, corresponding to the two UDB units
+ * present on those chips. UltraSparc-IIi only
+ * has a single UDB, called "SDB" in the manual.
+ * For IIi the upper UDB register always reads
+ * as zero so for our purposes things will just
+ * work with the checks below.
*/
- .globl __do_data_access_exception
- .globl __do_data_access_exception_tl1
-__do_data_access_exception_tl1:
+1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBH_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ stxa %g3, [%g0] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: mov 0x18, %g3
+ ldxa [%g3] ASI_UDBL_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBL_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ mov 0x18, %g7
+ stxa %g3, [%g7] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: /* Ok, now that we've latched the error state,
+ * clear the sticky bits in the AFSR.
+ */
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ rdpr %tl, %g2
+ cmp %g2, 1
+ rdpr %pil, %g2
+ bleu,pt %xcc, 1f
+ wrpr %g0, 15, %pil
+
+ ba,pt %xcc, etraptl1
+ rd %pc, %g7
+
+ ba,pt %xcc, 2f
+ nop
+
+1: ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+
+2: mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_access_error
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+ /* This is the trap handler entry point for ECC correctable
+ * errors. They are corrected, but we listen for the trap
+ * so that the event can be logged.
+ *
+ * Disrupting errors are either:
+ * 1) single-bit ECC errors during UDB reads to system
+ * memory
+ * 2) data parity errors during write-back events
+ *
+ * As far as I can make out from the manual, the CEE trap
+ * is only for correctable errors during memory read
+ * accesses by the front-end of the processor.
+ *
+ * The code below is only for trap level 1 CEE events,
+ * as it is the only situation where we can safely record
+ * and log. For trap level >1 we just clear the CE bit
+ * in the AFSR and return.
+ *
+ * This is just like __spiftire_access_error above, but it
+ * specifically handles correctable errors. If an
+ * uncorrectable error is indicated in the AFSR we
+ * will branch directly above to __spitfire_access_error
+ * to handle it instead. Uncorrectable therefore takes
+ * priority over correctable, and the error logging
+ * C code will notice this case by inspecting the
+ * trap type.
+ */
+ .globl __spitfire_cee_trap
+__spitfire_cee_trap:
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+ mov 1, %g3
+ sllx %g3, SFAFSR_UE_SHIFT, %g3
+ andcc %g4, %g3, %g0 ! Check for UE
+ bne,pn %xcc, __spitfire_access_error
+ nop
+
+ /* Ok, in this case we only have a correctable error.
+ * Indicate we only wish to capture that state in register
+ * %g1, and we only disable CE error reporting unlike UE
+ * handling which disables all errors.
+ */
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3
+ andn %g3, ESTATE_ERR_CE, %g3
+ stxa %g3, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */
+ ba,pt %xcc, __spitfire_cee_trap_continue
+ mov UDBE_CE, %g1
+
+ .globl __spitfire_data_access_exception
+ .globl __spitfire_data_access_exception_tl1
+__spitfire_data_access_exception_tl1:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
@@ -706,9 +852,25 @@ __do_data_access_exception_tl1:
ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
membar #Sync
+ rdpr %tt, %g3
+ cmp %g3, 0x80 ! first win spill/fill trap
+ blu,pn %xcc, 1f
+ cmp %g3, 0xff ! last win spill/fill trap
+ bgu,pn %xcc, 1f
+ nop
ba,pt %xcc, winfix_dax
rdpr %tpc, %g3
-__do_data_access_exception:
+1: sethi %hi(109f), %g7
+ ba,pt %xcc, etraptl1
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_data_access_exception_tl1
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+__spitfire_data_access_exception:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
@@ -722,20 +884,19 @@ __do_data_access_exception:
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
- .globl __do_instruction_access_exception
- .globl __do_instruction_access_exception_tl1
-__do_instruction_access_exception_tl1:
+ .globl __spitfire_insn_access_exception
+ .globl __spitfire_insn_access_exception_tl1
+__spitfire_insn_access_exception_tl1:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
membar #Sync
sethi %hi(109f), %g7
@@ -743,18 +904,17 @@ __do_instruction_access_exception_tl1:
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call instruction_access_exception_tl1
+ call spitfire_insn_access_exception_tl1
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
-__do_instruction_access_exception:
+__spitfire_insn_access_exception:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
membar #Sync
sethi %hi(109f), %g7
@@ -762,102 +922,11 @@ __do_instruction_access_exception:
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call instruction_access_exception
+ call spitfire_insn_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
- /* This is the trap handler entry point for ECC correctable
- * errors. They are corrected, but we listen for the trap
- * so that the event can be logged.
- *
- * Disrupting errors are either:
- * 1) single-bit ECC errors during UDB reads to system
- * memory
- * 2) data parity errors during write-back events
- *
- * As far as I can make out from the manual, the CEE trap
- * is only for correctable errors during memory read
- * accesses by the front-end of the processor.
- *
- * The code below is only for trap level 1 CEE events,
- * as it is the only situation where we can safely record
- * and log. For trap level >1 we just clear the CE bit
- * in the AFSR and return.
- */
-
- /* Our trap handling infrastructure allows us to preserve
- * two 64-bit values during etrap for arguments to
- * subsequent C code. Therefore we encode the information
- * as follows:
- *
- * value 1) Full 64-bits of AFAR
- * value 2) Low 33-bits of AFSR, then bits 33-->42
- * are UDBL error status and bits 43-->52
- * are UDBH error status
- */
- .align 64
- .globl cee_trap
-cee_trap:
- ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR
- ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR
- sllx %g1, 31, %g1 ! Clear reserved bits
- srlx %g1, 31, %g1 ! in AFSR
-
- /* NOTE: UltraSparc-I/II have high and low UDB error
- * registers, corresponding to the two UDB units
- * present on those chips. UltraSparc-IIi only
- * has a single UDB, called "SDB" in the manual.
- * For IIi the upper UDB register always reads
- * as zero so for our purposes things will just
- * work with the checks below.
- */
- ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status
- andcc %g3, (1 << 8), %g4 ! Check CE bit
- sllx %g3, (64 - 10), %g3 ! Clear reserved bits
- srlx %g3, (64 - 10), %g3 ! in UDB-Low error status
-
- sllx %g3, (33 + 0), %g3 ! Shift up to encoding area
- or %g1, %g3, %g1 ! Or it in
- be,pn %xcc, 1f ! Branch if CE bit was clear
- nop
- stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL
- membar #Sync ! Synchronize ASI stores
-1: mov 0x18, %g5 ! Addr of UDB-High error status
- ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it
-
- andcc %g3, (1 << 8), %g4 ! Check CE bit
- sllx %g3, (64 - 10), %g3 ! Clear reserved bits
- srlx %g3, (64 - 10), %g3 ! in UDB-High error status
- sllx %g3, (33 + 10), %g3 ! Shift up to encoding area
- or %g1, %g3, %g1 ! Or it in
- be,pn %xcc, 1f ! Branch if CE bit was clear
- nop
- nop
-
- stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH
- membar #Sync ! Synchronize ASI stores
-1: mov 1, %g5 ! AFSR CE bit is
- sllx %g5, 20, %g5 ! bit 20
- stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR
- membar #Sync ! Synchronize ASI stores
- sllx %g2, (64 - 41), %g2 ! Clear reserved bits
- srlx %g2, (64 - 41), %g2 ! in latched AFAR
-
- andn %g2, 0x0f, %g2 ! Finish resv bit clearing
- mov %g1, %g4 ! Move AFSR+UDB* into save reg
- mov %g2, %g5 ! Move AFAR into save reg
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
- mov %l4, %o0
-
- mov %l5, %o1
- call cee_log
- add %sp, PTREGS_OFF, %o2
- ba,a,pt %xcc, rtrap_irq
-
/* Capture I/D/E-cache state into per-cpu error scoreboard.
*
* %g1: (TL>=0) ? 1 : 0
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 2803bc7c2c7..425c60cfea1 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -466,7 +466,7 @@ do_flush_sync:
if (!limit)
break;
udelay(1);
- membar("#LoadLoad");
+ rmb();
}
if (!limit)
printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout "
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 07424b07593..66255434128 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -103,7 +103,7 @@ void cpu_idle(void)
* other cpus see our increasing idleness for the buddy
* redistribution algorithm. -DaveM
*/
- membar("#StoreStore | #StoreLoad");
+ membar_storeload_storestore();
}
}
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 89f5e019f24..e09ddf92765 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -147,7 +147,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
if (!limit)
break;
udelay(1);
- membar("#LoadLoad");
+ rmb();
}
if (!limit)
printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout "
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index b7e6a91952b..fbdfed3798d 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -33,7 +33,6 @@
#include <linux/cpu.h>
#include <linux/initrd.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index b1ed23091fb..aecccd0df1d 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -877,11 +877,12 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
unsigned long page = (unsigned long)
page_address(pte_page(*ptep));
- __asm__ __volatile__(
- " membar #StoreStore\n"
- " flush %0 + %1"
- : : "r" (page), "r" (address & (PAGE_SIZE - 1))
- : "memory");
+ wmb();
+ __asm__ __volatile__("flush %0 + %1"
+ : /* no outputs */
+ : "r" (page),
+ "r" (address & (PAGE_SIZE - 1))
+ : "memory");
}
pte_unmap(ptep);
preempt_enable();
@@ -1292,11 +1293,12 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
unsigned long page = (unsigned long)
page_address(pte_page(*ptep));
- __asm__ __volatile__(
- " membar #StoreStore\n"
- " flush %0 + %1"
- : : "r" (page), "r" (address & (PAGE_SIZE - 1))
- : "memory");
+ wmb();
+ __asm__ __volatile__("flush %0 + %1"
+ : /* no outputs */
+ : "r" (page),
+ "r" (address & (PAGE_SIZE - 1))
+ : "memory");
}
pte_unmap(ptep);
preempt_enable();
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index b9b42491e11..b4fc6a5462b 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -144,7 +144,7 @@ void __init smp_callin(void)
current->active_mm = &init_mm;
while (!cpu_isset(cpuid, smp_commenced_mask))
- membar("#LoadLoad");
+ rmb();
cpu_set(cpuid, cpu_online_map);
}
@@ -184,11 +184,11 @@ static inline long get_delta (long *rt, long *master)
for (i = 0; i < NUM_ITERS; i++) {
t0 = tick_ops->get_tick();
go[MASTER] = 1;
- membar("#StoreLoad");
+ membar_storeload();
while (!(tm = go[SLAVE]))
- membar("#LoadLoad");
+ rmb();
go[SLAVE] = 0;
- membar("#StoreStore");
+ wmb();
t1 = tick_ops->get_tick();
if (t1 - t0 < best_t1 - best_t0)
@@ -221,7 +221,7 @@ void smp_synchronize_tick_client(void)
go[MASTER] = 1;
while (go[MASTER])
- membar("#LoadLoad");
+ rmb();
local_irq_save(flags);
{
@@ -273,21 +273,21 @@ static void smp_synchronize_one_tick(int cpu)
/* wait for client to be ready */
while (!go[MASTER])
- membar("#LoadLoad");
+ rmb();
/* now let the client proceed into his loop */
go[MASTER] = 0;
- membar("#StoreLoad");
+ membar_storeload();
spin_lock_irqsave(&itc_sync_lock, flags);
{
for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
while (!go[MASTER])
- membar("#LoadLoad");
+ rmb();
go[MASTER] = 0;
- membar("#StoreStore");
+ wmb();
go[SLAVE] = tick_ops->get_tick();
- membar("#StoreLoad");
+ membar_storeload();
}
}
spin_unlock_irqrestore(&itc_sync_lock, flags);
@@ -927,11 +927,11 @@ void smp_capture(void)
smp_processor_id());
#endif
penguins_are_doing_time = 1;
- membar("#StoreStore | #LoadStore");
+ membar_storestore_loadstore();
atomic_inc(&smp_capture_registry);
smp_cross_call(&xcall_capture, 0, 0, 0);
while (atomic_read(&smp_capture_registry) != ncpus)
- membar("#LoadLoad");
+ rmb();
#ifdef CAPTURE_DEBUG
printk("done\n");
#endif
@@ -947,7 +947,7 @@ void smp_release(void)
smp_processor_id());
#endif
penguins_are_doing_time = 0;
- membar("#StoreStore | #StoreLoad");
+ membar_storeload_storestore();
atomic_dec(&smp_capture_registry);
}
}
@@ -970,9 +970,9 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
save_alternate_globals(global_save);
prom_world(1);
atomic_inc(&smp_capture_registry);
- membar("#StoreLoad | #StoreStore");
+ membar_storeload_storestore();
while (penguins_are_doing_time)
- membar("#LoadLoad");
+ rmb();
restore_alternate_globals(global_save);
atomic_dec(&smp_capture_registry);
prom_world(0);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 9202d925a9c..a3ea697f1ad 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -99,17 +99,6 @@ extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs);
-#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
-extern void _do_spin_lock (spinlock_t *lock, char *str);
-extern void _do_spin_unlock (spinlock_t *lock);
-extern int _spin_trylock (spinlock_t *lock);
-extern void _do_read_lock(rwlock_t *rw, char *str);
-extern void _do_read_unlock(rwlock_t *rw, char *str);
-extern void _do_write_lock(rwlock_t *rw, char *str);
-extern void _do_write_unlock(rwlock_t *rw);
-extern int _do_write_trylock(rwlock_t *rw, char *str);
-#endif
-
extern unsigned long phys_base;
extern unsigned long pfn_base;
@@ -152,18 +141,6 @@ EXPORT_SYMBOL(_mcount);
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(phys_cpu_present_map);
-/* Spinlock debugging library, optional. */
-#ifdef CONFIG_DEBUG_SPINLOCK
-EXPORT_SYMBOL(_do_spin_lock);
-EXPORT_SYMBOL(_do_spin_unlock);
-EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_do_read_lock);
-EXPORT_SYMBOL(_do_read_unlock);
-EXPORT_SYMBOL(_do_write_lock);
-EXPORT_SYMBOL(_do_write_unlock);
-EXPORT_SYMBOL(_do_write_trylock);
-#endif
-
EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */
@@ -429,3 +406,12 @@ EXPORT_SYMBOL(xor_vis_4);
EXPORT_SYMBOL(xor_vis_5);
EXPORT_SYMBOL(prom_palette);
+
+/* memory barriers */
+EXPORT_SYMBOL(mb);
+EXPORT_SYMBOL(rmb);
+EXPORT_SYMBOL(wmb);
+EXPORT_SYMBOL(membar_storeload);
+EXPORT_SYMBOL(membar_storeload_storestore);
+EXPORT_SYMBOL(membar_storeload_loadload);
+EXPORT_SYMBOL(membar_storestore_loadstore);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 0c9e54b2f0c..b280b2ef674 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -33,6 +33,7 @@
#include <asm/dcu.h>
#include <asm/estate.h>
#include <asm/chafsr.h>
+#include <asm/sfafsr.h>
#include <asm/psrcompat.h>
#include <asm/processor.h>
#include <asm/timer.h>
@@ -143,8 +144,7 @@ void do_BUG(const char *file, int line)
}
#endif
-void instruction_access_exception(struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
siginfo_t info;
@@ -153,8 +153,8 @@ void instruction_access_exception(struct pt_regs *regs,
return;
if (regs->tstate & TSTATE_PRIV) {
- printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
- sfsr, sfar);
+ printk("spitfire_insn_access_exception: SFSR[%016lx] "
+ "SFAR[%016lx], going.\n", sfsr, sfar);
die_if_kernel("Iax", regs);
}
if (test_thread_flag(TIF_32BIT)) {
@@ -169,19 +169,17 @@ void instruction_access_exception(struct pt_regs *regs,
force_sig_info(SIGSEGV, &info, current);
}
-void instruction_access_exception_tl1(struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
0, 0x8, SIGTRAP) == NOTIFY_STOP)
return;
dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
- instruction_access_exception(regs, sfsr, sfar);
+ spitfire_insn_access_exception(regs, sfsr, sfar);
}
-void data_access_exception(struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
siginfo_t info;
@@ -207,8 +205,8 @@ void data_access_exception(struct pt_regs *regs,
return;
}
/* Shit... */
- printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
- sfsr, sfar);
+ printk("spitfire_data_access_exception: SFSR[%016lx] "
+ "SFAR[%016lx], going.\n", sfsr, sfar);
die_if_kernel("Dax", regs);
}
@@ -220,6 +218,16 @@ void data_access_exception(struct pt_regs *regs,
force_sig_info(SIGSEGV, &info, current);
}
+void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
+{
+ if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
+ 0, 0x30, SIGTRAP) == NOTIFY_STOP)
+ return;
+
+ dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+ spitfire_data_access_exception(regs, sfsr, sfar);
+}
+
#ifdef CONFIG_PCI
/* This is really pathetic... */
extern volatile int pci_poke_in_progress;
@@ -253,54 +261,13 @@ static void spitfire_clean_and_reenable_l1_caches(void)
: "memory");
}
-void do_iae(struct pt_regs *regs)
+static void spitfire_enable_estate_errors(void)
{
- siginfo_t info;
-
- spitfire_clean_and_reenable_l1_caches();
-
- if (notify_die(DIE_TRAP, "instruction access exception", regs,
- 0, 0x8, SIGTRAP) == NOTIFY_STOP)
- return;
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_OBJERR;
- info.si_addr = (void *)0;
- info.si_trapno = 0;
- force_sig_info(SIGBUS, &info, current);
-}
-
-void do_dae(struct pt_regs *regs)
-{
- siginfo_t info;
-
-#ifdef CONFIG_PCI
- if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
- spitfire_clean_and_reenable_l1_caches();
-
- pci_poke_faulted = 1;
-
- /* Why the fuck did they have to change this? */
- if (tlb_type == cheetah || tlb_type == cheetah_plus)
- regs->tpc += 4;
-
- regs->tnpc = regs->tpc + 4;
- return;
- }
-#endif
- spitfire_clean_and_reenable_l1_caches();
-
- if (notify_die(DIE_TRAP, "data access exception", regs,
- 0, 0x30, SIGTRAP) == NOTIFY_STOP)
- return;
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_OBJERR;
- info.si_addr = (void *)0;
- info.si_trapno = 0;
- force_sig_info(SIGBUS, &info, current);
+ __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (ESTATE_ERR_ALL),
+ "i" (ASI_ESTATE_ERROR_EN));
}
static char ecc_syndrome_table[] = {
@@ -338,65 +305,15 @@ static char ecc_syndrome_table[] = {
0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
};
-/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
- * in the following format. The AFAR is left as is, with
- * reserved bits cleared, and is a raw 40-bit physical
- * address.
- */
-#define CE_STATUS_UDBH_UE (1UL << (43 + 9))
-#define CE_STATUS_UDBH_CE (1UL << (43 + 8))
-#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)
-#define CE_STATUS_UDBH_SHIFT 43
-#define CE_STATUS_UDBL_UE (1UL << (33 + 9))
-#define CE_STATUS_UDBL_CE (1UL << (33 + 8))
-#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)
-#define CE_STATUS_UDBL_SHIFT 33
-#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)
-#define CE_STATUS_AFSR_ME (1UL << 32)
-#define CE_STATUS_AFSR_PRIV (1UL << 31)
-#define CE_STATUS_AFSR_ISAP (1UL << 30)
-#define CE_STATUS_AFSR_ETP (1UL << 29)
-#define CE_STATUS_AFSR_IVUE (1UL << 28)
-#define CE_STATUS_AFSR_TO (1UL << 27)
-#define CE_STATUS_AFSR_BERR (1UL << 26)
-#define CE_STATUS_AFSR_LDP (1UL << 25)
-#define CE_STATUS_AFSR_CP (1UL << 24)
-#define CE_STATUS_AFSR_WP (1UL << 23)
-#define CE_STATUS_AFSR_EDP (1UL << 22)
-#define CE_STATUS_AFSR_UE (1UL << 21)
-#define CE_STATUS_AFSR_CE (1UL << 20)
-#define CE_STATUS_AFSR_ETS (0xfUL << 16)
-#define CE_STATUS_AFSR_ETS_SHIFT 16
-#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)
-#define CE_STATUS_AFSR_PSYND_SHIFT 0
-
-/* Layout of Ecache TAG Parity Syndrome of AFSR */
-#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */
-#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */
-#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */
-#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */
-
static char *syndrome_unknown = "<Unknown>";
-asmlinkage void cee_log(unsigned long ce_status,
- unsigned long afar,
- struct pt_regs *regs)
+static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit)
{
- char memmod_str[64];
- char *p;
- unsigned short scode, udb_reg;
+ unsigned short scode;
+ char memmod_str[64], *p;
- printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
- "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
- smp_processor_id(),
- (ce_status & CE_STATUS_AFSR_MASK),
- afar,
- ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
- ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
-
- udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
- if (udb_reg & (1 << 8)) {
- scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (udbl & bit) {
+ scode = ecc_syndrome_table[udbl & 0xff];
if (prom_getunumber(scode, afar,
memmod_str, sizeof(memmod_str)) == -1)
p = syndrome_unknown;
@@ -407,9 +324,8 @@ asmlinkage void cee_log(unsigned long ce_status,
smp_processor_id(), scode, p);
}
- udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
- if (udb_reg & (1 << 8)) {
- scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (udbh & bit) {
+ scode = ecc_syndrome_table[udbh & 0xff];
if (prom_getunumber(scode, afar,
memmod_str, sizeof(memmod_str)) == -1)
p = syndrome_unknown;
@@ -419,6 +335,127 @@ asmlinkage void cee_log(unsigned long ce_status,
"Memory Module \"%s\"\n",
smp_processor_id(), scode, p);
}
+
+}
+
+static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs)
+{
+
+ printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
+ "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",
+ smp_processor_id(), afsr, afar, udbl, udbh, tl1);
+
+ spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);
+
+ /* We always log it, even if someone is listening for this
+ * trap.
+ */
+ notify_die(DIE_TRAP, "Correctable ECC Error", regs,
+ 0, TRAP_TYPE_CEE, SIGTRAP);
+
+ /* The Correctable ECC Error trap does not disable I/D caches. So
+ * we only have to restore the ESTATE Error Enable register.
+ */
+ spitfire_enable_estate_errors();
+}
+
+static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs)
+{
+ siginfo_t info;
+
+ printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "
+ "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",
+ smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);
+
+ /* XXX add more human friendly logging of the error status
+ * XXX as is implemented for cheetah
+ */
+
+ spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);
+
+ /* We always log it, even if someone is listening for this
+ * trap.
+ */
+ notify_die(DIE_TRAP, "Uncorrectable Error", regs,
+ 0, tt, SIGTRAP);
+
+ if (regs->tstate & TSTATE_PRIV) {
+ if (tl1)
+ dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+ die_if_kernel("UE", regs);
+ }
+
+ /* XXX need more intelligent processing here, such as is implemented
+ * XXX for cheetah errors, in fact if the E-cache still holds the
+ * XXX line with bad parity this will loop
+ */
+
+ spitfire_clean_and_reenable_l1_caches();
+ spitfire_enable_estate_errors();
+
+ if (test_thread_flag(TIF_32BIT)) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_OBJERR;
+ info.si_addr = (void *)0;
+ info.si_trapno = 0;
+ force_sig_info(SIGBUS, &info, current);
+}
+
+void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar)
+{
+ unsigned long afsr, tt, udbh, udbl;
+ int tl1;
+
+ afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;
+ tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;
+ tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;
+ udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;
+ udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;
+
+#ifdef CONFIG_PCI
+ if (tt == TRAP_TYPE_DAE &&
+ pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
+ spitfire_clean_and_reenable_l1_caches();
+ spitfire_enable_estate_errors();
+
+ pci_poke_faulted = 1;
+ regs->tnpc = regs->tpc + 4;
+ return;
+ }
+#endif
+
+ if (afsr & SFAFSR_UE)
+ spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);
+
+ if (tt == TRAP_TYPE_CEE) {
+ /* Handle the case where we took a CEE trap, but ACK'd
+ * only the UE state in the UDB error registers.
+ */
+ if (afsr & SFAFSR_UE) {
+ if (udbh & UDBE_CE) {
+ __asm__ __volatile__(
+ "stxa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (udbh & UDBE_CE),
+ "r" (0x0), "i" (ASI_UDB_ERROR_W));
+ }
+ if (udbl & UDBE_CE) {
+ __asm__ __volatile__(
+ "stxa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (udbl & UDBE_CE),
+ "r" (0x18), "i" (ASI_UDB_ERROR_W));
+ }
+ }
+
+ spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs);
+ }
}
int cheetah_pcache_forced_on;
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 491bb3681f9..8365bc1f81f 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -18,9 +18,10 @@ sparc64_ttable_tl0:
tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
tl0_iax: membar #Sync
- TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
+ TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception)
tl0_resv009: BTRAP(0x9)
-tl0_iae: TRAP(do_iae)
+tl0_iae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
tl0_ill: membar #Sync
TRAP_7INSNS(do_illegal_instruction)
@@ -36,9 +37,10 @@ tl0_cwin: CLEAN_WINDOW
tl0_div0: TRAP(do_div0)
tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
tl0_resv02f: BTRAP(0x2f)
-tl0_dax: TRAP_NOSAVE(__do_data_access_exception)
+tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception)
tl0_resv031: BTRAP(0x31)
-tl0_dae: TRAP(do_dae)
+tl0_dae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl0_resv033: BTRAP(0x33)
tl0_mna: TRAP_NOSAVE(do_mna)
tl0_lddfmna: TRAP_NOSAVE(do_lddfmna)
@@ -73,7 +75,8 @@ tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
tl0_ivec: TRAP_IVEC
tl0_paw: TRAP(do_paw)
tl0_vaw: TRAP(do_vaw)
-tl0_cee: TRAP_NOSAVE(cee_trap)
+tl0_cee: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_cee_trap)
tl0_iamiss:
#include "itlb_base.S"
tl0_damiss:
@@ -175,9 +178,10 @@ tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8)
sparc64_ttable_tl1:
tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
-tl1_iax: TRAP_NOSAVE(__do_instruction_access_exception_tl1)
+tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1)
tl1_resv009: BTRAPTL1(0x9)
-tl1_iae: TRAPTL1(do_iae_tl1)
+tl1_iae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
tl1_ill: TRAPTL1(do_ill_tl1)
tl1_privop: BTRAPTL1(0x11)
@@ -193,9 +197,10 @@ tl1_cwin: CLEAN_WINDOW
tl1_div0: TRAPTL1(do_div0_tl1)
tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
-tl1_dax: TRAP_NOSAVE(__do_data_access_exception_tl1)
+tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1)
tl1_resv031: BTRAPTL1(0x31)
-tl1_dae: TRAPTL1(do_dae_tl1)
+tl1_dae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl1_resv033: BTRAPTL1(0x33)
tl1_mna: TRAP_NOSAVE(do_mna)
tl1_lddfmna: TRAPTL1(do_lddfmna_tl1)
@@ -219,8 +224,8 @@ tl1_paw: TRAPTL1(do_paw_tl1)
tl1_vaw: TRAPTL1(do_vaw_tl1)
/* The grotty trick to save %g1 into current->thread.cee_stuff
- * is because when we take this trap we could be interrupting trap
- * code already using the trap alternate global registers.
+ * is because when we take this trap we could be interrupting
+ * trap code already using the trap alternate global registers.
*
* We cross our fingers and pray that this store/load does
* not cause yet another CEE trap.
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 11c3e88732e..da9739f0d43 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -349,9 +349,9 @@ int handle_popc(u32 insn, struct pt_regs *regs)
extern void do_fpother(struct pt_regs *regs);
extern void do_privact(struct pt_regs *regs);
-extern void data_access_exception(struct pt_regs *regs,
- unsigned long sfsr,
- unsigned long sfar);
+extern void spitfire_data_access_exception(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
int handle_ldf_stq(u32 insn, struct pt_regs *regs)
{
@@ -394,14 +394,14 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
break;
}
default:
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
if (put_user (first >> 32, (u32 __user *)addr) ||
__put_user ((u32)first, (u32 __user *)(addr + 4)) ||
__put_user (second >> 32, (u32 __user *)(addr + 8)) ||
__put_user ((u32)second, (u32 __user *)(addr + 12))) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
} else {
@@ -414,7 +414,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
do_privact(regs);
return 1;
} else if (asi > ASI_SNFL) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
switch (insn & 0x180000) {
@@ -431,7 +431,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
err |= __get_user (data[i], (u32 __user *)(addr + 4*i));
}
if (err && !(asi & 0x2 /* NF */)) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
if (asi & 0x8) /* Little */ {
@@ -534,7 +534,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
*(u64 *)(f->regs + freg) = value;
current_thread_info()->fpsaved[0] |= flag;
} else {
-daex: data_access_exception(regs, sfsr, sfar);
+daex: spitfire_data_access_exception(regs, sfsr, sfar);
return;
}
advance(regs);
@@ -578,7 +578,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
__put_user ((u32)value, (u32 __user *)(sfar + 4)))
goto daex;
} else {
-daex: data_access_exception(regs, sfsr, sfar);
+daex: spitfire_data_access_exception(regs, sfsr, sfar);
return;
}
advance(regs);
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index dfbc7e0dcf7..99c809a1e5a 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -318,7 +318,7 @@ fill_fixup_dax:
nop
rdpr %pstate, %l1 ! Prepare to change globals.
mov %g4, %o1 ! Setup args for
- mov %g5, %o2 ! final call to data_access_exception.
+ mov %g5, %o2 ! final call to spitfire_data_access_exception.
andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
mov %g6, %o7 ! Stash away current.
@@ -330,7 +330,7 @@ fill_fixup_dax:
mov TSB_REG, %g1
ldxa [%g1] ASI_IMMU, %g5
#endif
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
b,pt %xcc, rtrap
@@ -391,7 +391,7 @@ window_dax_from_user_common:
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 40dbeec7e5d..6201f104098 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -12,7 +12,7 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
copy_in_user.o user_fixup.o memmove.o \
- mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o
+ mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o mb.o
lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o
lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c
index f03344cf784..f5f0b5586f0 100644
--- a/arch/sparc64/lib/debuglocks.c
+++ b/arch/sparc64/lib/debuglocks.c
@@ -12,8 +12,6 @@
#ifdef CONFIG_SMP
-#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
-
static inline void show (char *str, spinlock_t *lock, unsigned long caller)
{
int cpu = smp_processor_id();
@@ -51,20 +49,19 @@ static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
#undef INIT_STUCK
#define INIT_STUCK 100000000
-void _do_spin_lock(spinlock_t *lock, char *str)
+void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int stuck = INIT_STUCK;
int cpu = get_cpu();
int shown = 0;
- GET_CALLER(caller);
again:
__asm__ __volatile__("ldstub [%1], %0"
: "=r" (val)
: "r" (&(lock->lock))
: "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_storeload_storestore();
if (val) {
while (lock->lock) {
if (!--stuck) {
@@ -72,7 +69,7 @@ again:
show(str, lock, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
goto again;
}
@@ -84,17 +81,16 @@ again:
put_cpu();
}
-int _do_spin_trylock(spinlock_t *lock)
+int _do_spin_trylock(spinlock_t *lock, unsigned long caller)
{
- unsigned long val, caller;
+ unsigned long val;
int cpu = get_cpu();
- GET_CALLER(caller);
__asm__ __volatile__("ldstub [%1], %0"
: "=r" (val)
: "r" (&(lock->lock))
: "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_storeload_storestore();
if (!val) {
lock->owner_pc = ((unsigned int)caller);
lock->owner_cpu = cpu;
@@ -111,21 +107,20 @@ void _do_spin_unlock(spinlock_t *lock)
{
lock->owner_pc = 0;
lock->owner_cpu = NO_PROC_ID;
- membar("#StoreStore | #LoadStore");
+ membar_storestore_loadstore();
lock->lock = 0;
current->thread.smp_lock_count--;
}
/* Keep INIT_STUCK the same... */
-void _do_read_lock (rwlock_t *rw, char *str)
+void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int stuck = INIT_STUCK;
int cpu = get_cpu();
int shown = 0;
- GET_CALLER(caller);
wlock_again:
/* Wait for any writer to go away. */
while (((long)(rw->lock)) < 0) {
@@ -134,7 +129,7 @@ wlock_again:
show_read(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
/* Try once to increment the counter. */
__asm__ __volatile__(
@@ -147,7 +142,7 @@ wlock_again:
"2:" : "=r" (val)
: "0" (&(rw->lock))
: "g1", "g7", "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_storeload_storestore();
if (val)
goto wlock_again;
rw->reader_pc[cpu] = ((unsigned int)caller);
@@ -157,15 +152,13 @@ wlock_again:
put_cpu();
}
-void _do_read_unlock (rwlock_t *rw, char *str)
+void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int stuck = INIT_STUCK;
int cpu = get_cpu();
int shown = 0;
- GET_CALLER(caller);
-
/* Drop our identity _first_. */
rw->reader_pc[cpu] = 0;
current->thread.smp_lock_count--;
@@ -193,14 +186,13 @@ runlock_again:
put_cpu();
}
-void _do_write_lock (rwlock_t *rw, char *str)
+void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int stuck = INIT_STUCK;
int cpu = get_cpu();
int shown = 0;
- GET_CALLER(caller);
wlock_again:
/* Spin while there is another writer. */
while (((long)rw->lock) < 0) {
@@ -209,7 +201,7 @@ wlock_again:
show_write(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
/* Try to acuire the write bit. */
@@ -264,7 +256,7 @@ wlock_again:
show_write(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
goto wlock_again;
}
@@ -278,14 +270,12 @@ wlock_again:
put_cpu();
}
-void _do_write_unlock(rwlock_t *rw)
+void _do_write_unlock(rwlock_t *rw, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int stuck = INIT_STUCK;
int shown = 0;
- GET_CALLER(caller);
-
/* Drop our identity _first_ */
rw->writer_pc = 0;
rw->writer_cpu = NO_PROC_ID;
@@ -313,13 +303,11 @@ wlock_again:
}
}
-int _do_write_trylock (rwlock_t *rw, char *str)
+int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller)
{
- unsigned long caller, val;
+ unsigned long val;
int cpu = get_cpu();
- GET_CALLER(caller);
-
/* Try to acuire the write bit. */
__asm__ __volatile__(
" mov 1, %%g3\n"
diff --git a/arch/sparc64/lib/mb.S b/arch/sparc64/lib/mb.S
new file mode 100644
index 00000000000..4004f748619
--- /dev/null
+++ b/arch/sparc64/lib/mb.S
@@ -0,0 +1,73 @@
+/* mb.S: Out of line memory barriers.
+ *
+ * Copyright (C) 2005 David S. Miller (davem@davemloft.net)
+ */
+
+ /* These are here in an effort to more fully work around
+ * Spitfire Errata #51. Essentially, if a memory barrier
+ * occurs soon after a mispredicted branch, the chip can stop
+ * executing instructions until a trap occurs. Therefore, if
+ * interrupts are disabled, the chip can hang forever.
+ *
+ * It used to be believed that the memory barrier had to be
+ * right in the delay slot, but a case has been traced
+ * recently wherein the memory barrier was one instruction
+ * after the branch delay slot and the chip still hung. The
+ * offending sequence was the following in sym_wakeup_done()
+ * of the sym53c8xx_2 driver:
+ *
+ * call sym_ccb_from_dsa, 0
+ * movge %icc, 0, %l0
+ * brz,pn %o0, .LL1303
+ * mov %o0, %l2
+ * membar #LoadLoad
+ *
+ * The branch has to be mispredicted for the bug to occur.
+ * Therefore, we put the memory barrier explicitly into a
+ * "branch always, predicted taken" delay slot to avoid the
+ * problem case.
+ */
+
+ .text
+
+99: retl
+ nop
+
+ .globl mb
+mb: ba,pt %xcc, 99b
+ membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad
+ .size mb, .-mb
+
+ .globl rmb
+rmb: ba,pt %xcc, 99b
+ membar #LoadLoad
+ .size rmb, .-rmb
+
+ .globl wmb
+wmb: ba,pt %xcc, 99b
+ membar #StoreStore
+ .size wmb, .-wmb
+
+ .globl membar_storeload
+membar_storeload:
+ ba,pt %xcc, 99b
+ membar #StoreLoad
+ .size membar_storeload, .-membar_storeload
+
+ .globl membar_storeload_storestore
+membar_storeload_storestore:
+ ba,pt %xcc, 99b
+ membar #StoreLoad | #StoreStore
+ .size membar_storeload_storestore, .-membar_storeload_storestore
+
+ .globl membar_storeload_loadload
+membar_storeload_loadload:
+ ba,pt %xcc, 99b
+ membar #StoreLoad | #LoadLoad
+ .size membar_storeload_loadload, .-membar_storeload_loadload
+
+ .globl membar_storestore_loadstore
+membar_storestore_loadstore:
+ ba,pt %xcc, 99b
+ membar #StoreStore | #LoadStore
+ .size membar_storestore_loadstore, .-membar_storestore_loadstore
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 15b4cfe0755..302efbcba70 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -737,7 +737,8 @@ MODULE_LICENSE("GPL");
extern u32 tl0_solaris[8];
#define update_ttable(x) \
tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \
- __asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3]))
+ wmb(); \
+ __asm__ __volatile__ ("flush %0" : : "r" (&tl0_solaris[3]))
#else
#endif
@@ -761,7 +762,8 @@ int init_module(void)
entry64_personality_patch |=
(offsetof(struct task_struct, personality) +
(sizeof(unsigned long) - 1));
- __asm__ __volatile__("membar #StoreStore; flush %0"
+ wmb();
+ __asm__ __volatile__("flush %0"
: : "r" (&entry64_personality_patch));
return 0;
}
diff --git a/arch/v850/configs/rte-ma1-cb_defconfig b/arch/v850/configs/rte-ma1-cb_defconfig
index 1b5ca3c3a65..1a5beda36e2 100644
--- a/arch/v850/configs/rte-ma1-cb_defconfig
+++ b/arch/v850/configs/rte-ma1-cb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:08:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:54:27 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -44,6 +44,8 @@ CONFIG_ZERO_BSS=y
# CONFIG_V850E_HIGHRES_TIMER is not set
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -111,6 +113,52 @@ CONFIG_BINFMT_FLAT=y
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -158,6 +206,7 @@ CONFIG_MTD_CFI_I2=y
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -232,6 +281,7 @@ CONFIG_IOSCHED_NOOP=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -244,53 +294,8 @@ CONFIG_IOSCHED_NOOP=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
+# Network device support
#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -372,6 +377,8 @@ CONFIG_EEPRO100=y
# CONFIG_FDDI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -472,6 +479,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -479,6 +487,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -524,9 +534,11 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
diff --git a/arch/v850/configs/rte-me2-cb_defconfig b/arch/v850/configs/rte-me2-cb_defconfig
index 44becc06540..15e66647806 100644
--- a/arch/v850/configs/rte-me2-cb_defconfig
+++ b/arch/v850/configs/rte-me2-cb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:30:08 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:47:50 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -41,6 +41,8 @@ CONFIG_ZERO_BSS=y
# CONFIG_V850E_HIGHRES_TIMER is not set
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -56,7 +58,6 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
@@ -104,6 +105,11 @@ CONFIG_BINFMT_FLAT=y
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -151,6 +157,7 @@ CONFIG_MTD_CFI_I2=y
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -218,6 +225,7 @@ CONFIG_IOSCHED_NOOP=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -228,9 +236,8 @@ CONFIG_IOSCHED_NOOP=y
#
#
-# Networking support
+# Network device support
#
-# CONFIG_NET is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
@@ -311,7 +318,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -335,6 +341,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -342,6 +349,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
diff --git a/arch/v850/configs/sim_defconfig b/arch/v850/configs/sim_defconfig
index d73f5f9d838..f31ba7398ad 100644
--- a/arch/v850/configs/sim_defconfig
+++ b/arch/v850/configs/sim_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-uc0
-# Thu Jul 21 11:29:27 2005
+# Linux kernel version: 2.6.13-uc0
+# Fri Sep 2 13:36:43 2005
#
# CONFIG_MMU is not set
# CONFIG_UID16 is not set
@@ -36,6 +36,8 @@ CONFIG_NO_CACHE=y
CONFIG_ZERO_BSS=y
# CONFIG_RESET_GUARD is not set
CONFIG_LARGE_ALLOCS=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
#
# Code maturity level options
@@ -51,7 +53,6 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
@@ -99,6 +100,11 @@ CONFIG_BINFMT_FLAT=y
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
# Generic Driver Options
#
CONFIG_STANDALONE=y
@@ -146,6 +152,7 @@ CONFIG_MTD_CFI_I2=y
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -213,6 +220,7 @@ CONFIG_IOSCHED_NOOP=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -223,9 +231,8 @@ CONFIG_IOSCHED_NOOP=y
#
#
-# Networking support
+# Network device support
#
-# CONFIG_NET is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
@@ -300,7 +307,6 @@ CONFIG_SERIO=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -324,6 +330,7 @@ CONFIG_SERIO=y
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
#
# XFS support
@@ -331,6 +338,8 @@ CONFIG_SERIO=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+# CONFIG_MAGIC_ROM_PTR is not set
+CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c
index c41d72b01b8..abd48409dcc 100644
--- a/arch/v850/kernel/setup.c
+++ b/arch/v850/kernel/setup.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/setup.c -- Arch-dependent initialization functions
*
- * Copyright (C) 2001,02,03 NEC Electronics Corporation
- * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03,05 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03,05 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -98,10 +98,20 @@ void __init trap_init (void)
}
#ifdef CONFIG_MTD
+
+/* From drivers/mtd/devices/slram.c */
+#define SLRAM_BLK_SZ 0x4000
+
/* Set the root filesystem to be the given memory region.
Some parameter may be appended to CMD_LINE. */
void set_mem_root (void *addr, size_t len, char *cmd_line)
{
+ /* Some sort of idiocy in MTD means we must supply a length that's
+ a multiple of SLRAM_BLK_SZ. We just round up the real length,
+ as the file system shouldn't attempt to access anything beyond
+ the end of the image anyway. */
+ len = (((len - 1) + SLRAM_BLK_SZ) / SLRAM_BLK_SZ) * SLRAM_BLK_SZ;
+
/* The only way to pass info to the MTD slram driver is via
the command line. */
if (*cmd_line) {
@@ -284,3 +294,33 @@ init_mem_alloc (unsigned long ram_start, unsigned long ram_len)
free_area_init_node (0, NODE_DATA(0), zones_size,
ADDR_TO_PAGE (PAGE_OFFSET), 0);
}
+
+
+
+/* Taken from m68knommu */
+void show_mem(void)
+{
+ unsigned long i;
+ int free = 0, total = 0, reserved = 0, shared = 0;
+ int cached = 0;
+
+ printk(KERN_INFO "\nMem-info:\n");
+ show_free_areas();
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (!page_count(mem_map+i))
+ free++;
+ else
+ shared += page_count(mem_map+i) - 1;
+ }
+ printk(KERN_INFO "%d pages of RAM\n",total);
+ printk(KERN_INFO "%d free pages\n",free);
+ printk(KERN_INFO "%d reserved pages\n",reserved);
+ printk(KERN_INFO "%d pages shared\n",shared);
+ printk(KERN_INFO "%d pages swap cached\n",cached);
+}