Commit 0dedb5c7 authored by Len Brown's avatar Len Brown

Merge intel.com:/home/lenb/bk/linux-2.6.4

into intel.com:/home/lenb/src/linux-acpi-test-2.6.4
parents 360adfc4 afc2ce80
...@@ -31,6 +31,7 @@ comma = , ...@@ -31,6 +31,7 @@ comma = ,
# Note that GCC does not numerically define an architecture version # Note that GCC does not numerically define an architecture version
# macro, but instead defines a whole series of macros which makes # macro, but instead defines a whole series of macros which makes
# testing for a specific architecture or later rather impossible. # testing for a specific architecture or later rather impossible.
arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 -march=armv5t -Wa,-march=armv6
arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call check_gcc,-march=armv5te,-march=armv4) arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call check_gcc,-march=armv5te,-march=armv4)
arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4
arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3
...@@ -45,6 +46,7 @@ tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi ...@@ -45,6 +46,7 @@ tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110
tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100
tune-$(CONFIG_CPU_XSCALE) :=$(call check_gcc,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale tune-$(CONFIG_CPU_XSCALE) :=$(call check_gcc,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
tune-$(CONFIG_CPU_V6) :=-mtune=strongarm
# Need -Uarm for gcc < 3.x # Need -Uarm for gcc < 3.x
CFLAGS_BOOT :=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm CFLAGS_BOOT :=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm
......
...@@ -585,7 +585,7 @@ __armv3_cache_off: ...@@ -585,7 +585,7 @@ __armv3_cache_off:
* On entry, * On entry,
* r6 = processor ID * r6 = processor ID
* On exit, * On exit,
* r1, r2, r3, r12 corrupted * r1, r2, r3, r11, r12 corrupted
* This routine must preserve: * This routine must preserve:
* r0, r4, r5, r6, r7 * r0, r4, r5, r6, r7
*/ */
...@@ -595,9 +595,25 @@ cache_clean_flush: ...@@ -595,9 +595,25 @@ cache_clean_flush:
b call_cache_fn b call_cache_fn
__armv4_cache_flush: __armv4_cache_flush:
bic r1, pc, #31 mov r2, #64*1024 @ default: 32K dcache size (*2)
add r2, r1, #65536 @ 2x the largest dcache size mov r11, #32 @ default: 32 byte line size
1: ldr r3, [r1], #32 @ s/w flush D cache mrc p15, 0, r3, c0, c0, 1 @ read cache type
teq r3, r6 @ cache ID register present?
beq no_cache_id
mov r1, r3, lsr #18
and r1, r1, #7
mov r2, #1024
mov r2, r2, lsl r1 @ base dcache size *2
tst r3, #1 << 14 @ test M bit
addne r2, r2, r2, lsr #1 @ +1/2 size if M == 1
mov r3, r3, lsr #12
and r3, r3, #3
mov r11, #8
mov r11, r11, lsl r3 @ cache line size in bytes
no_cache_id:
bic r1, pc, #63 @ align to longest cache line
add r2, r1, r2
1: ldr r3, [r1], r11 @ s/w flush D cache
teq r1, r2 teq r1, r2
bne 1b bne 1b
......
...@@ -5,6 +5,6 @@ ...@@ -5,6 +5,6 @@
obj-y += platform.o obj-y += platform.o
obj-$(CONFIG_ARM_AMBA) += amba.o obj-$(CONFIG_ARM_AMBA) += amba.o
obj-$(CONFIG_ICST525) += icst525.o obj-$(CONFIG_ICST525) += icst525.o
obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o
obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o
obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
...@@ -315,16 +315,30 @@ amba_find_device(const char *busid, struct device *parent, unsigned int id, ...@@ -315,16 +315,30 @@ amba_find_device(const char *busid, struct device *parent, unsigned int id,
return data.dev; return data.dev;
} }
/**
* amba_request_regions - request all mem regions associated with device
* @dev: amba_device structure for device
* @name: name, or NULL to use driver name
*/
int amba_request_regions(struct amba_device *dev, const char *name) int amba_request_regions(struct amba_device *dev, const char *name)
{ {
int ret = 0; int ret = 0;
if (!name)
name = dev->dev.driver->name;
if (!request_mem_region(dev->res.start, SZ_4K, name)) if (!request_mem_region(dev->res.start, SZ_4K, name))
ret = -EBUSY; ret = -EBUSY;
return ret; return ret;
} }
/**
* amba_release_regions - release mem regions assoicated with device
* @dev: amba_device structure for device
*
* Release regions claimed by a successful call to amba_request_regions.
*/
void amba_release_regions(struct amba_device *dev) void amba_release_regions(struct amba_device *dev)
{ {
release_mem_region(dev->res.start, SZ_4K); release_mem_region(dev->res.start, SZ_4K);
......
This diff is collapsed.
This diff is collapsed.
...@@ -11,7 +11,6 @@ obj-y := arch.o compat.o dma.o entry-armv.o entry-common.o irq.o \ ...@@ -11,7 +11,6 @@ obj-y := arch.o compat.o dma.o entry-armv.o entry-common.o irq.o \
time.o traps.o time.o traps.o
obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o time-acorn.o obj-$(CONFIG_ARCH_ACORN) += ecard.o time-acorn.o
obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o
obj-$(CONFIG_FOOTBRIDGE) += isa.o obj-$(CONFIG_FOOTBRIDGE) += isa.o
......
...@@ -47,6 +47,10 @@ int main(void) ...@@ -47,6 +47,10 @@ int main(void)
{ {
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
BLANK(); BLANK();
#if __LINUX_ARM_ARCH__ >= 6
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id));
#endif
BLANK();
DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm)); DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));
DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags)); DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags));
BLANK(); BLANK();
......
...@@ -66,6 +66,15 @@ ...@@ -66,6 +66,15 @@
msr cpsr_c, \mode msr cpsr_c, \mode
.endm .endm
#if __LINUX_ARM_ARCH__ >= 6
.macro disable_irq, temp
cpsid i
.endm
.macro enable_irq, temp
cpsie i
.endm
#else
.macro disable_irq, temp .macro disable_irq, temp
set_cpsr_c \temp, #PSR_I_BIT | MODE_SVC set_cpsr_c \temp, #PSR_I_BIT | MODE_SVC
.endm .endm
...@@ -73,6 +82,7 @@ ...@@ -73,6 +82,7 @@
.macro enable_irq, temp .macro enable_irq, temp
set_cpsr_c \temp, #MODE_SVC set_cpsr_c \temp, #MODE_SVC
.endm .endm
#endif
.macro save_user_regs .macro save_user_regs
sub sp, sp, #S_FRAME_SIZE sub sp, sp, #S_FRAME_SIZE
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/kallsyms.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -225,6 +226,34 @@ static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) ...@@ -225,6 +226,34 @@ static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
} }
static void static void
report_bad_irq(unsigned int irq, struct pt_regs *regs, struct irqdesc *desc, int ret)
{
static int count = 100;
struct irqaction *action;
if (!count)
return;
count--;
if (ret != IRQ_HANDLED && ret != IRQ_NONE) {
printk("irq%u: bogus retval mask %x\n", irq, ret);
} else {
printk("irq%u: nobody cared\n", irq);
}
show_regs(regs);
dump_stack();
printk(KERN_ERR "handlers:");
action = desc->action;
do {
printk("\n" KERN_ERR "[<%p>]", action->handler);
print_symbol(" (%s)", (unsigned long)action->handler);
action = action->next;
} while (action);
printk("\n");
}
static int
__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
{ {
unsigned int status; unsigned int status;
...@@ -247,18 +276,7 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) ...@@ -247,18 +276,7 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
spin_lock_irq(&irq_controller_lock); spin_lock_irq(&irq_controller_lock);
if (retval != 1) { return retval;
static int count = 100;
if (count) {
count--;
if (retval) {
printk("irq event %d: bogus retval mask %x\n",
irq, retval);
} else {
printk("irq %d: nobody cared\n", irq);
}
}
}
} }
/* /*
...@@ -276,8 +294,11 @@ do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -276,8 +294,11 @@ do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
kstat_cpu(cpu).irqs[irq]++; kstat_cpu(cpu).irqs[irq]++;
action = desc->action; action = desc->action;
if (action) if (action) {
__do_irq(irq, desc->action, regs); int ret = __do_irq(irq, action, regs);
if (ret != IRQ_HANDLED)
report_bad_irq(irq, regs, desc, ret);
}
} }
/* /*
...@@ -313,6 +334,7 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -313,6 +334,7 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
do { do {
struct irqaction *action; struct irqaction *action;
int ret;
action = desc->action; action = desc->action;
if (!action) if (!action)
...@@ -323,7 +345,9 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -323,7 +345,9 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
desc->chip->unmask(irq); desc->chip->unmask(irq);
} }
__do_irq(irq, action, regs); ret = __do_irq(irq, action, regs);
if (ret != IRQ_HANDLED)
report_bad_irq(irq, regs, desc, ret);
} while (desc->pending && !desc->disable_depth); } while (desc->pending && !desc->disable_depth);
desc->running = 0; desc->running = 0;
...@@ -368,7 +392,10 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -368,7 +392,10 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
*/ */
action = desc->action; action = desc->action;
if (action) { if (action) {
__do_irq(irq, desc->action, regs); int ret = __do_irq(irq, desc->action, regs);
if (ret != IRQ_HANDLED)
report_bad_irq(irq, regs, desc, ret);
if (likely(!desc->disable_depth && if (likely(!desc->disable_depth &&
!check_irq_lock(desc, irq, regs))) !check_irq_lock(desc, irq, regs)))
......
/*
* linux/arch/arm/kernel/suspend.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*
* This is the common support code for suspending an ARM machine.
* pm_do_suspend() is responsible for actually putting the CPU to
* sleep.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sysctl.h>
#include <linux/pm.h>
#include <linux/errno.h>
#include <linux/sched.h>
#ifdef CONFIG_SYSCTL
/*
* We really want this to die. It's a disgusting hack using unallocated
* sysctl numbers. We should be using a real interface.
*/
static int
pm_sysctl_proc_handler(ctl_table *ctl, int write, struct file *filp,
void *buffer, size_t *lenp)
{
int ret = -EIO;
printk("PM: task %s (pid %d) uses deprecated sysctl PM interface\n",
current->comm, current->pid);
if (write)
ret = pm_suspend(PM_SUSPEND_MEM);
return ret;
}
/*
* This came from arch/arm/mach-sa1100/pm.c:
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
* with modifications by Nicolas Pitre and Russell King.
*
* ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
* linux/sysctl.h.
*
* This means our interface here won't survive long - it needs a new
* interface. Quick hack to get this working - use sysctl id 9999.
*/
#warning ACPI broke the kernel, this interface needs to be fixed up.
#define CTL_ACPI 9999
#define ACPI_S1_SLP_TYP 19
static struct ctl_table pm_table[] =
{
{
.ctl_name = ACPI_S1_SLP_TYP,
.procname = "suspend",
.mode = 0200,
.proc_handler = pm_sysctl_proc_handler,
},
{0}
};
static struct ctl_table pm_dir_table[] =
{
{
.ctl_name = CTL_ACPI,
.procname = "pm",
.mode = 0555,
.child = pm_table,
},
{0}
};
/*
* Initialize power interface
*/
static int __init pm_init(void)
{
register_sysctl_table(pm_dir_table, 1);
return 0;
}
fs_initcall(pm_init);
#endif
...@@ -118,21 +118,21 @@ static struct resource io_res[] = { ...@@ -118,21 +118,21 @@ static struct resource io_res[] = {
#define lp2 io_res[2] #define lp2 io_res[2]
static const char *cache_types[16] = { static const char *cache_types[16] = {
"write-through", "VIVT write-through",
"write-back", "VIVT write-back",
"write-back", "VIVT write-back",
"undefined 3", "undefined 3",
"undefined 4", "undefined 4",
"undefined 5", "undefined 5",
"write-back", "VIVT write-back",
"write-back", "VIVT write-back",
"undefined 8", "undefined 8",
"undefined 9", "undefined 9",
"undefined 10", "undefined 10",
"undefined 11", "undefined 11",
"undefined 12", "undefined 12",
"undefined 13", "undefined 13",
"undefined 14", "VIPT write-back",
"undefined 15", "undefined 15",
}; };
...@@ -151,7 +151,7 @@ static const char *cache_clean[16] = { ...@@ -151,7 +151,7 @@ static const char *cache_clean[16] = {
"undefined 11", "undefined 11",
"undefined 12", "undefined 12",
"undefined 13", "undefined 13",
"undefined 14", "cp15 c7 ops",
"undefined 15", "undefined 15",
}; };
...@@ -170,7 +170,7 @@ static const char *cache_lockdown[16] = { ...@@ -170,7 +170,7 @@ static const char *cache_lockdown[16] = {
"undefined 11", "undefined 11",
"undefined 12", "undefined 12",
"undefined 13", "undefined 13",
"undefined 14", "format C",
"undefined 15", "undefined 15",
}; };
...@@ -183,7 +183,7 @@ static const char *proc_arch[] = { ...@@ -183,7 +183,7 @@ static const char *proc_arch[] = {
"5T", "5T",
"5TE", "5TE",
"5TEJ", "5TEJ",
"?(9)", "6TEJ",
"?(10)", "?(10)",
"?(11)", "?(11)",
"?(12)", "?(12)",
......
...@@ -19,10 +19,24 @@ ENTRY(__raw_readsl) ...@@ -19,10 +19,24 @@ ENTRY(__raw_readsl)
ands ip, r1, #3 ands ip, r1, #3
bne 2f bne 2f
1: ldr r3, [r0] subs r2, r2, #4
str r3, [r1], #4 bmi 1001f
subs r2, r2, #1 stmfd sp!, {r4, lr}
bne 1b 1000: ldr r3, [r0, #0]
ldr r4, [r0, #0]
ldr ip, [r0, #0]
ldr lr, [r0, #0]
subs r2, r2, #4
stmia r1!, {r3, r4, ip, lr}
bpl 1000b
ldmfd sp!, {r4, lr}
1001: tst r2, #2
ldrne r3, [r0, #0]
ldrne ip, [r0, #0]
stmneia r1!, {r3, ip}
tst r2, #1
ldrne r3, [r0, #0]
strne r3, [r1, #0]
mov pc, lr mov pc, lr
2: cmp ip, #2 2: cmp ip, #2
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/div64.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -111,6 +112,21 @@ unsigned int cpufreq_get(unsigned int cpu) ...@@ -111,6 +112,21 @@ unsigned int cpufreq_get(unsigned int cpu)
EXPORT_SYMBOL(cpufreq_get); EXPORT_SYMBOL(cpufreq_get);
#endif #endif
/*
* This is the SA11x0 sched_clock implementation. This has
* a resolution of 271ns, and a maximum value of 1165s.
* ( * 1E9 / 3686400 => * 78125 / 288)
*/
unsigned long long sched_clock(void)
{
unsigned long long v;
v = (unsigned long long)OSCR * 78125;
do_div(v, 288);
return v;
}
/* /*
* Default power-off for SA1100 * Default power-off for SA1100
*/ */
...@@ -151,6 +167,36 @@ static struct platform_device sa11x0udc_device = { ...@@ -151,6 +167,36 @@ static struct platform_device sa11x0udc_device = {
.resource = sa11x0udc_resources, .resource = sa11x0udc_resources,
}; };
static struct resource sa11x0uart1_resources[] = {
[0] = {
.start = 0x80010000,
.end = 0x8001ffff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device sa11x0uart1_device = {
.name = "sa11x0-uart",
.id = 1,
.num_resources = ARRAY_SIZE(sa11x0uart1_resources),
.resource = sa11x0uart1_resources,
};
static struct resource sa11x0uart3_resources[] = {
[0] = {
.start = 0x80050000,
.end = 0x8005ffff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device sa11x0uart3_device = {
.name = "sa11x0-uart",
.id = 3,
.num_resources = ARRAY_SIZE(sa11x0uart3_resources),
.resource = sa11x0uart3_resources,
};
static struct resource sa11x0mcp_resources[] = { static struct resource sa11x0mcp_resources[] = {
[0] = { [0] = {
.start = 0x80060000, .start = 0x80060000,
...@@ -218,6 +264,8 @@ static struct platform_device sa11x0pcmcia_device = { ...@@ -218,6 +264,8 @@ static struct platform_device sa11x0pcmcia_device = {
static struct platform_device *sa11x0_devices[] __initdata = { static struct platform_device *sa11x0_devices[] __initdata = {
&sa11x0udc_device, &sa11x0udc_device,
&sa11x0uart1_device,
&sa11x0uart3_device,
&sa11x0mcp_device, &sa11x0mcp_device,
&sa11x0ssp_device, &sa11x0ssp_device,
&sa11x0pcmcia_device, &sa11x0pcmcia_device,
......
...@@ -223,6 +223,17 @@ config CPU_XSCALE ...@@ -223,6 +223,17 @@ config CPU_XSCALE
select CPU_TLB_V4WBI select CPU_TLB_V4WBI
select CPU_MINICACHE select CPU_MINICACHE
# ARMv6
config CPU_V6
bool "Support ARM V6 processor"
depends on ARCH_INTEGRATOR
select CPU_32v6
select CPU_ABRT_EV6
select CPU_CACHE_V6
select CPU_COPY_V6
select CPU_TLB_V6
# Figure out what processor architecture version we should be using.
# This defines the compiler instruction set which depends on the machine type. # This defines the compiler instruction set which depends on the machine type.
config CPU_32v3 config CPU_32v3
bool bool
...@@ -233,6 +244,9 @@ config CPU_32v4 ...@@ -233,6 +244,9 @@ config CPU_32v4
config CPU_32v5 config CPU_32v5
bool bool
config CPU_32v6
bool
# The abort model # The abort model
config CPU_ABRT_EV4 config CPU_ABRT_EV4
bool bool
...@@ -249,6 +263,9 @@ config CPU_ABRT_EV5T ...@@ -249,6 +263,9 @@ config CPU_ABRT_EV5T
config CPU_ABRT_EV5TJ config CPU_ABRT_EV5TJ
bool bool
config CPU_ABRT_EV6
bool
# The cache model # The cache model
config CPU_CACHE_V3 config CPU_CACHE_V3
bool bool
...@@ -262,6 +279,9 @@ config CPU_CACHE_V4WT ...@@ -262,6 +279,9 @@ config CPU_CACHE_V4WT
config CPU_CACHE_V4WB config CPU_CACHE_V4WB
bool bool
config CPU_CACHE_V6
bool
# The copy-page model # The copy-page model
config CPU_COPY_V3 config CPU_COPY_V3
bool bool
...@@ -272,6 +292,9 @@ config CPU_COPY_V4WT ...@@ -272,6 +292,9 @@ config CPU_COPY_V4WT
config CPU_COPY_V4WB config CPU_COPY_V4WB
bool bool
config CPU_COPY_V6
bool
# This selects the TLB model # This selects the TLB model
config CPU_TLB_V3 config CPU_TLB_V3
bool bool
...@@ -306,7 +329,7 @@ comment "Processor Features" ...@@ -306,7 +329,7 @@ comment "Processor Features"
config ARM_THUMB config ARM_THUMB
bool "Support Thumb user binaries" bool "Support Thumb user binaries"
depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_V6
default y default y
help help
Say Y if you want to include kernel support for running user space Say Y if you want to include kernel support for running user space
......
...@@ -15,15 +15,18 @@ obj-$(CONFIG_CPU_ABRT_EV4T) += abort-ev4t.o ...@@ -15,15 +15,18 @@ obj-$(CONFIG_CPU_ABRT_EV4T) += abort-ev4t.o
obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
obj-$(CONFIG_CPU_ABRT_EV5T) += abort-ev5t.o obj-$(CONFIG_CPU_ABRT_EV5T) += abort-ev5t.o
obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o
obj-$(CONFIG_CPU_ABRT_EV6) += abort-ev6.o
obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o
obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o
obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o
obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o
obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o mmu.o
obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
...@@ -33,6 +36,7 @@ obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o ...@@ -33,6 +36,7 @@ obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o
obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o
obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o
obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
...@@ -48,3 +52,4 @@ obj-$(CONFIG_CPU_ARM1026) += proc-arm1026.o ...@@ -48,3 +52,4 @@ obj-$(CONFIG_CPU_ARM1026) += proc-arm1026.o
obj-$(CONFIG_CPU_SA110) += proc-sa110.o obj-$(CONFIG_CPU_SA110) += proc-sa110.o
obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_V6) += proc-v6.o blockops.o
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* Function: v6_early_abort
*
* Params : r2 = address of aborted instruction
* : r3 = saved SPSR
*
* Returns : r0 = address of abort
* : r1 = FSR, bit 11 = write
* : r2-r8 = corrupted
* : r9 = preserved
* : sp = pointer to registers
*
* Purpose : obtain information about current aborted instruction.
*/
.align 5
ENTRY(v6_early_abort)
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
mov pc, lr
...@@ -188,38 +188,33 @@ ENTRY(v4t_late_abort) ...@@ -188,38 +188,33 @@ ENTRY(v4t_late_abort)
.data_thumb_pushpop: .data_thumb_pushpop:
tst r8, #1 << 10 tst r8, #1 << 10
beq .data_unknown beq .data_unknown
mov r7, #0x11 and r6, r8, #0x55 @ hweight8(r8) + R bit
and r6, r8, r7 and r2, r8, #0xaa
and r2, r8, r7, lsl #1
add r6, r6, r2, lsr #1 add r6, r6, r2, lsr #1
and r2, r8, r7, lsl #2 and r2, r6, #0xcc
and r6, r6, #0x33
add r6, r6, r2, lsr #2 add r6, r6, r2, lsr #2
and r2, r8, r7, lsl #3 movs r7, r8, lsr #9 @ C = r8 bit 8 (R bit)
add r6, r6, r2, lsr #3 adc r6, r6, r6, lsr #4 @ high + low nibble + R bit
add r6, r6, r6, lsr #4
and r2, r8, #0x0100 @ catch 'R' bit for push/pop
add r6, r6, r2, lsr #8
and r6, r6, #15 @ number of regs to transfer and r6, r6, #15 @ number of regs to transfer
ldr r7, [sp, #13 << 2] ldr r7, [sp, #13 << 2]
tst r8, #1 << 11 tst r8, #1 << 11
addne r7, r7, r6, lsl #2 @ increment SP if PUSH addeq r7, r7, r6, lsl #2 @ increment SP if PUSH
subeq r7, r7, r6, lsl #2 @ decrement SP if POP subne r7, r7, r6, lsl #2 @ decrement SP if POP
str r7, [sp, #13 << 2] str r7, [sp, #13 << 2]
mov pc, lr mov pc, lr
.data_thumb_ldmstm: .data_thumb_ldmstm:
mov r7, #0x11 and r6, r8, #0x55 @ hweight8(r8)
and r6, r8, r7 and r2, r8, #0xaa
and r2, r8, r7, lsl #1
add r6, r6, r2, lsr #1 add r6, r6, r2, lsr #1
and r2, r8, r7, lsl #2 and r2, r6, #0xcc
and r6, r6, #0x33
add r6, r6, r2, lsr #2 add r6, r6, r2, lsr #2
and r2, r8, r7, lsl #3
add r6, r6, r2, lsr #3
add r6, r6, r6, lsr #4 add r6, r6, r6, lsr #4
and r6, r6, #15 @ number of regs to transfer
and r5, r8, #7 << 8 and r5, r8, #7 << 8
ldr r7, [sp, r5, lsr #6] ldr r7, [sp, r5, lsr #6]
and r6, r6, #15 @ number of regs to transfer
sub r7, r7, r6, lsl #2 @ always decrement sub r7, r7, r6, lsl #2 @ always decrement
str r7, [sp, r5, lsr #6] str r7, [sp, r5, lsr #6]
mov pc, lr mov pc, lr
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <asm/memory.h>
#include <asm/ptrace.h>
#include <asm/cacheflush.h>
#include <asm/traps.h>
extern struct cpu_cache_fns blk_cache_fns;
#define HARVARD_CACHE
/*
* blk_flush_kern_dcache_page(kaddr)
*
* Ensure that the data held in the page kaddr is written back
* to the page in question.
*
* - kaddr - kernel address (guaranteed to be page aligned)
*/
static void __attribute__((naked))
blk_flush_kern_dcache_page(void *kaddr)
{
asm(
"add r1, r0, %0 \n\
1: .word 0xec401f0e @ mcrr p15, 0, r0, r1, c14, 0 @ blocking \n\
mov r0, #0 \n\
mcr p15, 0, r0, c7, c5, 0 \n\
mcr p15, 0, r0, c7, c10, 4 \n\
mov pc, lr"
:
: "I" (PAGE_SIZE));
}
/*
* blk_dma_inv_range(start,end)
*
* Invalidate the data cache within the specified region; we will
* be performing a DMA operation in this region and we want to
* purge old data in the cache.
*
* - start - virtual start address of region
* - end - virtual end address of region
*/
static void __attribute__((naked))
blk_dma_inv_range_unified(unsigned long start, unsigned long end)
{
asm(
"tst r0, %0 \n\
mcrne p15, 0, r0, c7, c11, 1 @ clean unified line \n\
tst r1, %0 \n\
mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line\n\
.word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0 @ blocking \n\
mov r0, #0 \n\
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
mov pc, lr"
:
: "I" (L1_CACHE_BYTES - 1));
}
static void __attribute__((naked))
blk_dma_inv_range_harvard(unsigned long start, unsigned long end)
{
asm(
"tst r0, %0 \n\
mcrne p15, 0, r0, c7, c10, 1 @ clean D line \n\
tst r1, %0 \n\
mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line \n\
.word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0 @ blocking \n\
mov r0, #0 \n\
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
mov pc, lr"
:
: "I" (L1_CACHE_BYTES - 1));
}
/*
* blk_dma_clean_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
*/
static void __attribute__((naked))
blk_dma_clean_range(unsigned long start, unsigned long end)
{
asm(
".word 0xec401f0c @ mcrr p15, 0, r1, r0, c12, 0 @ blocking \n\
mov r0, #0 \n\
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
mov pc, lr");
}
/*
* blk_dma_flush_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
*/
static void __attribute__((naked))
blk_dma_flush_range(unsigned long start, unsigned long end)
{
asm(
".word 0xec401f0e @ mcrr p15, 0, r1, r0, c14, 0 @ blocking \n\
mov pc, lr");
}
static int blockops_trap(struct pt_regs *regs, unsigned int instr)
{
regs->ARM_r4 |= regs->ARM_r2;
regs->ARM_pc += 4;
return 0;
}
static char *func[] = {
"Prefetch data range",
"Clean+Invalidate data range",
"Clean data range",
"Invalidate data range",
"Invalidate instr range"
};
static struct undef_hook blockops_hook __initdata = {
.instr_mask = 0x0fffffd0,
.instr_val = 0x0c401f00,
.cpsr_mask = PSR_T_BIT,
.cpsr_val = 0,
.fn = blockops_trap,
};
static int __init blockops_check(void)
{
register unsigned int err asm("r4") = 0;
unsigned int cache_type;
int i;
asm("mcr p15, 0, %0, c0, c0, 1" : "=r" (cache_type));
printk("Checking V6 block cache operations:\n");
register_undef_hook(&blockops_hook);
__asm__ ("mov r0, %0\n\t"
"mov r1, %1\n\t"
"mov r2, #1\n\t"
".word 0xec401f2c @ mcrr p15, 0, r1, r0, c12, 2\n\t"
"mov r2, #2\n\t"
".word 0xec401f0e @ mcrr p15, 0, r1, r0, c14, 0\n\t"
"mov r2, #4\n\t"
".word 0xec401f0c @ mcrr p15, 0, r1, r0, c12, 0\n\t"
"mov r2, #8\n\t"
".word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0\n\t"
"mov r2, #16\n\t"
".word 0xec401f05 @ mcrr p15, 0, r1, r0, c5, 0\n\t"
:
: "r" (PAGE_OFFSET), "r" (PAGE_OFFSET + 128)
: "r0", "r1", "r2");
unregister_undef_hook(&blockops_hook);
for (i = 0; i < ARRAY_SIZE(func); i++, err >>= 1)
printk("%30s: %ssupported\n", func[i], err & 1 ? "not " : "");
if ((err & 8) == 0) {
printk(" --> Using %s block cache invalidate\n",
cache_type & (1 << 24) ? "harvard" : "unified");
if (cache_type & (1 << 24))
cpu_cache.dma_inv_range = blk_dma_inv_range_harvard;
else
cpu_cache.dma_inv_range = blk_dma_inv_range_unified;
}
if ((err & 4) == 0) {
printk(" --> Using block cache clean\n");
cpu_cache.dma_clean_range = blk_dma_clean_range;
}
if ((err & 2) == 0) {
printk(" --> Using block cache clean+invalidate\n");
cpu_cache.dma_flush_range = blk_dma_flush_range;
cpu_cache.flush_kern_dcache_page = blk_flush_kern_dcache_page;
}
return 0;
}
__initcall(blockops_check);
/*
* linux/arch/arm/mm/cache-v6.S
*
* Copyright (C) 2001 Deep Blue Solutions Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This is the "shell" of the ARMv6 processor support.
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
#include "proc-macros.S"
#define HARVARD_CACHE
#define CACHE_LINE_SIZE 32
#define D_CACHE_LINE_SIZE 32
/*
* v6_flush_cache_all()
*
* Flush the entire cache.
*
* It is assumed that:
*/
ENTRY(v6_flush_kern_cache_all)
mov r0, #0
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
#else
mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate
#endif
mov pc, lr
/*
* v6_flush_cache_all()
*
* Flush all TLB entries in a particular address space
*
* - mm - mm_struct describing address space
*/
ENTRY(v6_flush_user_cache_all)
/*FALLTHROUGH*/
/*
* v6_flush_cache_range(start, end, flags)
*
* Flush a range of TLB entries in the specified address space.
*
* - start - start address (may not be aligned)
* - end - end address (exclusive, may not be aligned)
* - flags - vm_area_struct flags describing address space
*
* It is assumed that:
* - we have a VIPT cache.
*/
ENTRY(v6_flush_user_cache_range)
mov pc, lr
/*
* v6_coherent_kern_range(start,end)
*
* Ensure that the I and D caches are coherent within specified
* region. This is typically used when code has been written to
* a memory region, and will be executed.
*
* - start - virtual start address of region
* - end - virtual end address of region
*
* It is assumed that:
* - the Icache does not read data from the write buffer
*/
ENTRY(v6_coherent_kern_range)
bic r0, r0, #CACHE_LINE_SIZE - 1
1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c10, 1 @ clean D line
mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
#endif
mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blo 1b
#ifdef HARVARD_CACHE
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
#endif
mov pc, lr
/*
* v6_flush_kern_dcache_page(kaddr)
*
* Ensure that the data held in the page kaddr is written back
* to the page in question.
*
* - kaddr - kernel address (guaranteed to be page aligned)
*/
ENTRY(v6_flush_kern_dcache_page)
add r1, r0, #PAGE_SZ
1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
#else
mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate unified line
#endif
add r0, r0, #D_CACHE_LINE_SIZE
cmp r0, r1
blo 1b
#ifdef HARVARD_CACHE
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
#endif
mov pc, lr
/*
* v6_dma_inv_range(start,end)
*
* Invalidate the data cache within the specified region; we will
* be performing a DMA operation in this region and we want to
* purge old data in the cache.
*
* - start - virtual start address of region
* - end - virtual end address of region
*/
ENTRY(v6_dma_inv_range)
tst r0, #D_CACHE_LINE_SIZE - 1
bic r0, r0, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
mcrne p15, 0, r0, c7, c10, 1 @ clean D line
#else
mcrne p15, 0, r0, c7, c11, 1 @ clean unified line
#endif
tst r1, #D_CACHE_LINE_SIZE - 1
bic r1, r1, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line
#else
mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line
#endif
1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c6, 1 @ invalidate D line
#else
mcr p15, 0, r0, c7, c7, 1 @ invalidate unified line
#endif
add r0, r0, #D_CACHE_LINE_SIZE
cmp r0, r1
blo 1b
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mov pc, lr
/*
* v6_dma_clean_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
*/
ENTRY(v6_dma_clean_range)
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c10, 1 @ clean D line
#else
mcr p15, 0, r0, c7, c11, 1 @ clean unified line
#endif
add r0, r0, #D_CACHE_LINE_SIZE
cmp r0, r1
blo 1b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mov pc, lr
/*
* v6_dma_flush_range(start,end)
* - start - virtual start address of region
* - end - virtual end address of region
*/
ENTRY(v6_dma_flush_range)
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef HARVARD_CACHE
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
#else
mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate line
#endif
add r0, r0, #D_CACHE_LINE_SIZE
blo 1b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mov pc, lr
__INITDATA
.type v6_cache_fns, #object
ENTRY(v6_cache_fns)
.long v6_flush_kern_cache_all
.long v6_flush_user_cache_all
.long v6_flush_user_cache_range
.long v6_coherent_kern_range
.long v6_flush_kern_dcache_page
.long v6_dma_inv_range
.long v6_dma_clean_range
.long v6_dma_flush_range
.size v6_cache_fns, . - v6_cache_fns
/*
* linux/arch/arm/mm/copypage-v6.c
*
* Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/shmparam.h>
#include <asm/tlbflush.h>
#if SHMLBA > 16384
#error FIX ME
#endif
#define from_address (0xffff8000)
#define from_pgprot PAGE_KERNEL
#define to_address (0xffffc000)
#define to_pgprot PAGE_KERNEL
static pte_t *from_pte;
static pte_t *to_pte;
static spinlock_t v6_lock = SPIN_LOCK_UNLOCKED;
#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
/*
* Copy the page, taking account of the cache colour.
*/
void v6_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
unsigned int offset = DCACHE_COLOUR(vaddr);
unsigned long from, to;
spin_lock(&v6_lock);
set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
from = from_address + (offset << PAGE_SHIFT);
to = to_address + (offset << PAGE_SHIFT);
flush_tlb_kernel_page(from);
flush_tlb_kernel_page(to);
copy_page((void *)to, (void *)from);
spin_unlock(&v6_lock);
}
void v6_clear_user_page(void *kaddr, unsigned long vaddr)
{
unsigned int offset = DCACHE_COLOUR(vaddr);
unsigned long to = to_address + (offset << PAGE_SHIFT);
spin_lock(&v6_lock);
set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
flush_tlb_kernel_page(to);
clear_page((void *)to);
spin_unlock(&v6_lock);
}
struct cpu_user_fns v6_user_fns __initdata = {
.cpu_clear_user_page = v6_clear_user_page,
.cpu_copy_user_page = v6_copy_user_page,
};
static int __init v6_userpage_init(void)
{
pgd_t *pgd;
pmd_t *pmd;
pgd = pgd_offset_k(from_address);
pmd = pmd_alloc(&init_mm, pgd, from_address);
if (!pmd)
BUG();
from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
if (!from_pte)
BUG();
to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
if (!to_pte)
BUG();
return 0;
}
__initcall(v6_userpage_init);
...@@ -585,20 +585,31 @@ void __init iotable_init(struct map_desc *io_desc, int nr) ...@@ -585,20 +585,31 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
create_mapping(io_desc + i); create_mapping(io_desc + i);
} }
static inline void free_memmap(int node, unsigned long start, unsigned long end) static inline void
free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
{ {
struct page *start_pg, *end_pg;
unsigned long pg, pgend; unsigned long pg, pgend;
start = __phys_to_virt(start); /*
end = __phys_to_virt(end); * Convert start_pfn/end_pfn to a struct page pointer.
*/
pg = PAGE_ALIGN((unsigned long)(virt_to_page(start))); start_pg = pfn_to_page(start_pfn);
pgend = ((unsigned long)(virt_to_page(end))) & PAGE_MASK; end_pg = pfn_to_page(end_pfn);
start = __virt_to_phys(pg); /*
end = __virt_to_phys(pgend); * Convert to physical addresses, and
* round start upwards and end downwards.
*/
pg = PAGE_ALIGN(__pa(start_pg));
pgend = __pa(end_pg) & PAGE_MASK;
free_bootmem_node(NODE_DATA(node), start, end - start); /*
* If there are free pages between these,
* free the section of the memmap array.
*/
if (pg < pgend)
free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
} }
static inline void free_unused_memmap_node(int node, struct meminfo *mi) static inline void free_unused_memmap_node(int node, struct meminfo *mi)
...@@ -615,7 +626,12 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi) ...@@ -615,7 +626,12 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi)
if (mi->bank[i].size == 0 || mi->bank[i].node != node) if (mi->bank[i].size == 0 || mi->bank[i].node != node)
continue; continue;
bank_start = mi->bank[i].start & PAGE_MASK; bank_start = mi->bank[i].start >> PAGE_SHIFT;
if (bank_start < prev_bank_end) {
printk(KERN_ERR "MEM: unordered memory banks. "
"Not freeing memmap.\n");
break;
}
/* /*
* If we had a previous bank, and there is a space * If we had a previous bank, and there is a space
...@@ -625,7 +641,7 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi) ...@@ -625,7 +641,7 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi)
free_memmap(node, prev_bank_end, bank_start); free_memmap(node, prev_bank_end, bank_start);
prev_bank_end = PAGE_ALIGN(mi->bank[i].start + prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
mi->bank[i].size); mi->bank[i].size) >> PAGE_SHIFT;
} }
} }
......
...@@ -35,3 +35,17 @@ ...@@ -35,3 +35,17 @@
ldr \rd, [\rd, #TI_TASK] ldr \rd, [\rd, #TI_TASK]
ldr \rd, [\rd, #TSK_ACTIVE_MM] ldr \rd, [\rd, #TSK_ACTIVE_MM]
.endm .endm
/*
* mmid - get context id from mm pointer (mm->context.id)
*/
.macro mmid, rd, rn
ldr \rd, [\rn, #MM_CONTEXT_ID]
.endm
/*
* mask_asid - mask the ASID from the context ID
*/
.macro asid, rd, rn
and \rd, \rn, #255
.endm
/*
* linux/arch/arm/mm/proc-v6.S
*
* Copyright (C) 2001 Deep Blue Solutions Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This is the "shell" of the ARMv6 processor support.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/constants.h>
#include <asm/procinfo.h>
#include <asm/pgtable.h>
#include "proc-macros.S"
#define D_CACHE_LINE_SIZE 32
.macro cpsie, flags
.ifc \flags, f
.long 0xf1080040
.exitm
.endif
.ifc \flags, i
.long 0xf1080080
.exitm
.endif
.ifc \flags, if
.long 0xf10800c0
.exitm
.endif
.err
.endm
.macro cpsid, flags
.ifc \flags, f
.long 0xf10c0040
.exitm
.endif
.ifc \flags, i
.long 0xf10c0080
.exitm
.endif
.ifc \flags, if
.long 0xf10c00c0
.exitm
.endif
.err
.endm
ENTRY(cpu_v6_proc_init)
mov pc, lr
ENTRY(cpu_v6_proc_fin)
mov pc, lr
/*
* cpu_v6_reset(loc)
*
* Perform a soft reset of the system. Put the CPU into the
* same state as it would be if it had been reset, and branch
* to what would be the reset vector.
*
* - loc - location to jump to for soft reset
*
* It is assumed that:
*/
.align 5
ENTRY(cpu_v6_reset)
mov pc, r0
/*
* cpu_v6_do_idle()
*
* Idle the processor (eg, wait for interrupt).
*
* IRQs are already disabled.
*/
ENTRY(cpu_v6_do_idle)
mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
mov pc, lr
ENTRY(cpu_v6_dcache_clean_area)
#ifndef TLB_CAN_READ_FROM_L1_CACHE
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #D_CACHE_LINE_SIZE
subs r1, r1, #D_CACHE_LINE_SIZE
bhi 1b
#endif
mov pc, lr
/*
* cpu_arm926_switch_mm(pgd_phys, tsk)
*
* Set the translation table base pointer to be pgd_phys
*
* - pgd_phys - physical address of new TTB
*
* It is assumed that:
* - we are not using split page tables
*/
ENTRY(cpu_v6_switch_mm)
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
mcr p15, 0, r1, c13, c0, 1 @ set context ID
mov pc, lr
#define nG (1 << 11)
#define APX (1 << 9)
#define AP1 (1 << 5)
#define AP0 (1 << 4)
#define XN (1 << 0)
/*
* cpu_v6_set_pte(ptep, pte)
*
* Set a level 2 translation table entry.
*
* - ptep - pointer to level 2 translation table entry
* (hardware version is stored at -1024 bytes)
* - pte - PTE value to store
*
* Permissions:
* YUWD APX AP1 AP0 SVC User
* 0xxx 0 0 0 no acc no acc
* 100x 1 0 1 r/o no acc
* 10x0 1 0 1 r/o no acc
* 1011 0 0 1 r/w no acc
* 110x 1 1 0 r/o r/o
* 11x0 1 1 0 r/o r/o
* 1111 0 1 1 r/w r/w
*/
ENTRY(cpu_v6_set_pte)
str r1, [r0], #-2048 @ linux version
bic r2, r1, #0x00000ff0
bic r2, r2, #0x00000003
orr r2, r2, #AP0 | 2
tst r1, #L_PTE_WRITE
tstne r1, #L_PTE_DIRTY
orreq r2, r2, #APX
tst r1, #L_PTE_USER
orrne r2, r2, #AP1 | nG
tstne r2, #APX
eorne r2, r2, #AP0
tst r1, #L_PTE_YOUNG
biceq r2, r2, #APX | AP1 | AP0
@ tst r1, #L_PTE_EXEC
@ orreq r2, r2, #XN
tst r1, #L_PTE_PRESENT
moveq r2, #0
str r2, [r0]
mcr p15, 0, r0, c7, c10, 1 @ flush_pte
mov pc, lr
cpu_v6_name:
.asciz "Some Random V6 Processor"
.align
.section ".text.init", #alloc, #execinstr
/*
* __v6_setup
*
* Initialise TLB, Caches, and MMU state ready to switch the MMU
* on. Return in r0 the new CP15 C1 control register setting.
*
* We automatically detect if we have a Harvard cache, and use the
* Harvard cache control instructions insead of the unified cache
* control instructions.
*
* This should be able to cover all ARMv6 cores.
*
* It is assumed that:
* - cache type register is implemented
*/
__v6_setup:
mrc p15, 0, r10, c0, c0, 1 @ read cache type register
tst r10, #1 << 24 @ Harvard cache?
mov r10, #0
mcrne p15, 0, r10, c7, c14, 0 @ clean+invalidate D cache
mcrne p15, 0, r10, c7, c5, 0 @ invalidate I cache
mcreq p15, 0, r10, c7, c15, 0 @ clean+invalidate cache
mcr p15, 0, r10, c7, c10, 4 @ drain write buffer
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r10, c2, c0, 2 @ TTB control register
mcr p15, 0, r4, c2, c0, 0 @ load TTB0
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
mov r10, #0x1f @ domains 0, 1 = manager
mcr p15, 0, r10, c3, c0, 0 @ load domain access register
mrc p15, 0, r0, c1, c0, 0 @ read control register
ldr r10, cr1_clear @ get mask for bits to clear
bic r0, r0, r10 @ clear bits them
ldr r10, cr1_set @ get mask for bits to set
orr r0, r0, r10 @ set them
mov pc, lr @ return to head.S:__ret
/*
* V X F I D LR
* .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
* rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
* 0 110 0011 1.00 .111 1101 < we want
*/
.type cr1_clear, #object
.type cr1_set, #object
cr1_clear:
.word 0x0120c302
cr1_set:
.word 0x00c0387d
.type v6_processor_functions, #object
ENTRY(v6_processor_functions)
.word v6_early_abort
.word cpu_v6_proc_init
.word cpu_v6_proc_fin
.word cpu_v6_reset
.word cpu_v6_do_idle
.word cpu_v6_dcache_clean_area
.word cpu_v6_switch_mm
.word cpu_v6_set_pte
.size v6_processor_functions, . - v6_processor_functions
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv6"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
cpu_elf_name:
.asciz "v6"
.size cpu_elf_name, . - cpu_elf_name
.align
.section ".proc.info", #alloc, #execinstr
/*
* Match any ARMv6 processor core.
*/
.type __v6_proc_info, #object
__v6_proc_info:
.long 0x00070000
.long 0x00ff0000
.long 0x00000c0e
b __v6_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_FAST_MULT | HWCAP_VFP
.long cpu_v6_name
.long v6_processor_functions
.long v6wbi_tlb_fns
.long v6_user_fns
.long v6_cache_fns
.size __v6_proc_info, . - __v6_proc_info
/*
* linux/arch/arm/mm/tlb-v6.S
*
* Copyright (C) 1997-2002 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ARM architecture version 6 TLB handling functions.
* These assume a split I/D TLB.
*/
#include <linux/linkage.h>
#include <asm/constants.h>
#include <asm/page.h>
#include <asm/tlbflush.h>
#include "proc-macros.S"
#define HARVARD_TLB
/*
* v6wbi_flush_user_tlb_range(start, end, vma)
*
* Invalidate a range of TLB entries in the specified address space.
*
* - start - start address (may not be aligned)
* - end - end address (exclusive, may not be aligned)
* - vma - vma_struct describing address range
*
* It is assumed that:
* - the "Invalidate single entry" instruction will invalidate
* both the I and the D TLBs on Harvard-style TLBs
*/
ENTRY(v6wbi_flush_user_tlb_range)
vma_vm_mm r3, r2 @ get vma->vm_mm
mov ip, #0
mmid r3, r3 @ get vm_mm->context.id
mcr p15, 0, ip, c7, c10, 4 @ drain write buffer
mov r0, r0, lsr #PAGE_SHIFT @ align address
mov r1, r1, lsr #PAGE_SHIFT
asid r3, r3 @ mask ASID
orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
mov r1, r1, lsl #PAGE_SHIFT
vma_vm_flags r2, r2 @ get vma->vm_flags
1:
#ifdef HARVARD_TLB
mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA (was 1)
tst r2, #VM_EXEC @ Executable area ?
mcrne p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA (was 1)
#else
mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate MVA (was 1)
#endif
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
mov pc, lr
/*
* v6wbi_flush_kern_tlb_range(start,end)
*
* Invalidate a range of kernel TLB entries
*
* - start - start address (may not be aligned)
* - end - end address (exclusive, may not be aligned)
*/
ENTRY(v6wbi_flush_kern_tlb_range)
mov r2, #0
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mov r0, r0, lsr #PAGE_SHIFT @ align address
mov r1, r1, lsr #PAGE_SHIFT
mov r0, r0, lsl #PAGE_SHIFT
mov r1, r1, lsl #PAGE_SHIFT
1:
#ifdef HARVARD_TLB
mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA
mcr p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA
#else
mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate MVA
#endif
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
mov pc, lr
.section ".text.init", #alloc, #execinstr
.type v6wbi_tlb_fns, #object
ENTRY(v6wbi_tlb_fns)
.long v6wbi_flush_user_tlb_range
.long v6wbi_flush_kern_tlb_range
.long v6wbi_tlb_flags
.size v6wbi_tlb_fns, . - v6wbi_tlb_fns
...@@ -50,11 +50,6 @@ ...@@ -50,11 +50,6 @@
#ifdef MODULE #ifdef MODULE
void fp_send_sig(unsigned long sig, struct task_struct *p, int priv); void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
#endif
#else #else
#define fp_send_sig send_sig #define fp_send_sig send_sig
#define kern_fp_enter fp_enter #define kern_fp_enter fp_enter
...@@ -172,3 +167,7 @@ void float_raise(signed char flags) ...@@ -172,3 +167,7 @@ void float_raise(signed char flags)
module_init(fpe_init); module_init(fpe_init);
module_exit(fpe_exit); module_exit(fpe_exit);
MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
MODULE_LICENSE("GPL");
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README, # To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk # or contact rmk@arm.linux.org.uk
# #
# Last update: Thu Sep 18 17:15:55 2003 # Last update: Tue Feb 24 17:17:50 2004
# #
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
# #
...@@ -202,7 +202,7 @@ karo ARCH_KARO KARO 190 ...@@ -202,7 +202,7 @@ karo ARCH_KARO KARO 190
fester SA1100_FESTER FESTER 191 fester SA1100_FESTER FESTER 191
gpi ARCH_GPI GPI 192 gpi ARCH_GPI GPI 192
smdk2410 ARCH_SMDK2410 SMDK2410 193 smdk2410 ARCH_SMDK2410 SMDK2410 193
premium ARCH_PREMIUM PREMIUM 194 i519 ARCH_I519 I519 194
nexio SA1100_NEXIO NEXIO 195 nexio SA1100_NEXIO NEXIO 195
bitbox SA1100_BITBOX BITBOX 196 bitbox SA1100_BITBOX BITBOX 196
g200 SA1100_G200 G200 197 g200 SA1100_G200 G200 197
...@@ -259,7 +259,7 @@ stork_nest ARCH_STORK_NEST STORK_NEST 247 ...@@ -259,7 +259,7 @@ stork_nest ARCH_STORK_NEST STORK_NEST 247
stork_egg ARCH_STORK_EGG STORK_EGG 248 stork_egg ARCH_STORK_EGG STORK_EGG 248
wismo SA1100_WISMO WISMO 249 wismo SA1100_WISMO WISMO 249
ezlinx ARCH_EZLINX EZLINX 250 ezlinx ARCH_EZLINX EZLINX 250
at91rm9200 ARCH_AT91 AT91 251 at91rm9200 ARCH_AT91RM9200 AT91RM9200 251
orion ARCH_ORION ORION 252 orion ARCH_ORION ORION 252
neptune ARCH_NEPTUNE NEPTUNE 253 neptune ARCH_NEPTUNE NEPTUNE 253
hackkit SA1100_HACKKIT HACKKIT 254 hackkit SA1100_HACKKIT HACKKIT 254
...@@ -295,7 +295,7 @@ viper ARCH_VIPER VIPER 283 ...@@ -295,7 +295,7 @@ viper ARCH_VIPER VIPER 283
adsbitsyplus SA1100_ADSBITSYPLUS ADSBITSYPLUS 284 adsbitsyplus SA1100_ADSBITSYPLUS ADSBITSYPLUS 284
adsagc SA1100_ADSAGC ADSAGC 285 adsagc SA1100_ADSAGC ADSAGC 285
stp7312 ARCH_STP7312 STP7312 286 stp7312 ARCH_STP7312 STP7312 286
nx_phnx ARCH_PXA255 PXA255 287 nx_phnx MACH_NX_PHNX NX_PHNX 287
wep_ep250 ARCH_WEP_EP250 WEP_EP250 288 wep_ep250 ARCH_WEP_EP250 WEP_EP250 288
inhandelf3 ARCH_INHANDELF3 INHANDELF3 289 inhandelf3 ARCH_INHANDELF3 INHANDELF3 289
adi_coyote ARCH_ADI_COYOTE ADI_COYOTE 290 adi_coyote ARCH_ADI_COYOTE ADI_COYOTE 290
...@@ -364,7 +364,7 @@ ixrd425 ARCH_IXRD425 IXRD425 352 ...@@ -364,7 +364,7 @@ ixrd425 ARCH_IXRD425 IXRD425 352
iq80315 ARCH_IQ80315 IQ80315 353 iq80315 ARCH_IQ80315 IQ80315 353
nmp7312 ARCH_NMP7312 NMP7312 354 nmp7312 ARCH_NMP7312 NMP7312 354
cx861xx ARCH_CX861XX CX861XX 355 cx861xx ARCH_CX861XX CX861XX 355
ixp2000 ARCH_IXP2000 IXP2000 356 enp2611 ARCH_ENP2611 ENP2611 356
xda SA1100_XDA XDA 357 xda SA1100_XDA XDA 357
csir_ims ARCH_CSIR_IMS CSIR_IMS 358 csir_ims ARCH_CSIR_IMS CSIR_IMS 358
ixp421_dnaeeth ARCH_IXP421_DNAEETH IXP421_DNAEETH 359 ixp421_dnaeeth ARCH_IXP421_DNAEETH IXP421_DNAEETH 359
...@@ -385,3 +385,92 @@ gumstik ARCH_GUMSTIK GUMSTIK 373 ...@@ -385,3 +385,92 @@ gumstik ARCH_GUMSTIK GUMSTIK 373
rcube ARCH_RCUBE RCUBE 374 rcube ARCH_RCUBE RCUBE 374
rea_olv ARCH_REA_OLV REA_OLV 375 rea_olv ARCH_REA_OLV REA_OLV 375
pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376 pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376
s3c3410 ARCH_S3C3410 S3C3410 377
espd_4510b ARCH_ESPD_4510B ESPD_4510B 378
mp1x ARCH_MP1X MP1X 379
at91rm9200tb ARCH_AT91RM9200TB AT91RM9200TB 380
adsvgx ARCH_ADSVGX ADSVGX 381
omap1610 ARCH_OMAP1610 OMAP1610 382
pelee ARCH_PELEE PELEE 383
e7xx ARCH_E7XX E7XX 384
iq80331 ARCH_IQ80331 IQ80331 385
versatile_pb ARCH_VERSATILE_PB VERSATILE_PB 387
kev7a400 MACH_KEV7A400 KEV7A400 388
lpd7a400 MACH_LPD7A400 LPD7A400 389
lpd7a404 MACH_LPD7A404 LPD7A404 390
fujitsu_camelot ARCH_FUJITSU_CAMELOT FUJITSU_CAMELOT 391
janus2m ARCH_JANUS2M JANUS2M 392
embtf MACH_EMBTF EMBTF 393
hpm MACH_HPM HPM 394
smdk2410tk MACH_SMDK2410TK SMDK2410TK 395
smdk2410aj MACH_SMDK2410AJ SMDK2410AJ 396
streetracer MACH_STREETRACER STREETRACER 397
eframe MACH_EFRAME EFRAME 398
csb337 MACH_CSB337 CSB337 399
pxa_lark MACH_PXA_LARK PXA_LARK 400
pxa_pnp2110 MACH_PNP2110 PNP2110 401
tcc72x MACH_TCC72X TCC72X 402
altair MACH_ALTAIR ALTAIR 403
kc3 MACH_KC3 KC3 404
sinteftd MACH_SINTEFTD SINTEFTD 405
mainstone MACH_MAINSTONE MAINSTONE 406
aday4x MACH_ADAY4X ADAY4X 407
lite300 MACH_LITE300 LITE300 408
s5c7376 MACH_S5C7376 S5C7376 409
mt02 MACH_MT02 MT02 410
mport3s MACH_MPORT3S MPORT3S 411
ra_alpha MACH_RA_ALPHA RA_ALPHA 412
xcep MACH_XCEP XCEP 413
arcom_mercury MACH_ARCOM_MERCURY ARCOM_MERCURY 414
stargate MACH_STARGATE STARGATE 415
armadilloj MACH_ARMADILLOJ ARMADILLOJ 416
elroy_jack MACH_ELROY_JACK ELROY_JACK 417
backend MACH_BACKEND BACKEND 418
s5linbox MACH_S5LINBOX S5LINBOX 419
nomadik MACH_NOMADIK NOMADIK 420
ia_cpu_9200 MACH_IA_CPU_9200 IA_CPU_9200 421
at91_bja1 MACH_AT91_BJA1 AT91_BJA1 422
corgi MACH_CORGI CORGI 423
poodle MACH_POODLE POODLE 424
ten MACH_TEN TEN 425
roverp5p MACH_ROVERP5P ROVERP5P 426
sc2700 MACH_SC2700 SC2700 427
ex_eagle MACH_EX_EAGLE EX_EAGLE 428
nx_pxa12 MACH_NX_PXA12 NX_PXA12 429
nx_pxa5 MACH_NX_PXA5 NX_PXA5 430
blackboard2 MACH_BLACKBOARD2 BLACKBOARD2 431
i819 MACH_I819 I819 432
ixmb995e MACH_IXMB995E IXMB995E 433
skyrider MACH_SKYRIDER SKYRIDER 434
skyhawk MACH_SKYHAWK SKYHAWK 435
enterprise MACH_ENTERPRISE ENTERPRISE 436
dep2410 MACH_DEP2410 DEP2410 437
armcore MACH_ARMCORE ARMCORE 438
hobbit MACH_HOBBIT HOBBIT 439
h7210 MACH_H7210 H7210 440
pxa_netdcu5 MACH_PXA_NETDCU5 PXA_NETDCU5 441
acc MACH_ACC ACC 442
esl_sarva MACH_ESL_SARVA ESL_SARVA 443
xm250 MACH_XM250 XM250 444
t6tc1xb MACH_T6TC1XB T6TC1XB 445
ess710 MACH_ESS710 ESS710 446
mx3ads MACH_MX3ADS MX3ADS 447
himalaya MACH_HIMALAYA HIMALAYA 448
bolfenk MACH_BOLFENK BOLFENK 449
at91rm9200kr MACH_AT91RM9200KR AT91RM9200KR 450
edb9312 MACH_EDB9312 EDB9312 451
omap_generic MACH_OMAP_GENERIC OMAP_GENERIC 452
aximx3 MACH_AXIMX3 AXIMX3 453
eb67xdip MACH_EB67XDIP EB67XDIP 454
webtxs MACH_WEBTXS WEBTXS 455
hawk MACH_HAWK HAWK 456
ccat91sbc001 MACH_CCAT91SBC001 CCAT91SBC001 457
expresso MACH_EXPRESSO EXPRESSO 458
h4000 MACH_H4000 H4000 459
dino MACH_DINO DINO 460
ml675k MACH_ML675K ML675K 461
edb9301 MACH_EDB9301 EDB9301 462
edb9315 MACH_EDB9315 EDB9315 463
reciva_tt MACH_RECIVA_TT RECIVA_TT 464
cstcb01 MACH_CSTCB01 CSTCB01 465
cstcb1 MACH_CSTCB1 CSTCB1 466
...@@ -89,6 +89,17 @@ config PPC_PMAC ...@@ -89,6 +89,17 @@ config PPC_PMAC
bool "Apple PowerMac G5 support" bool "Apple PowerMac G5 support"
select ADB_PMU select ADB_PMU
config PMAC_DART
bool "Enable DART/IOMMU on PowerMac (allow >2G of RAM)"
depends on PPC_PMAC
depends on EXPERIMENTAL
default n
help
Enabling DART makes it possible to boot a PowerMac G5 with more
than 2GB of memory. Note that the code is very new and untested
at this time, so it has to be considered experimental. Enabling
this might result in data loss.
config PPC_PMAC64 config PPC_PMAC64
bool bool
depends on PPC_PMAC depends on PPC_PMAC
...@@ -109,6 +120,18 @@ config POWER4_ONLY ...@@ -109,6 +120,18 @@ config POWER4_ONLY
binary will not work on POWER3 or RS64 processors when compiled with binary will not work on POWER3 or RS64 processors when compiled with
binutils 2.15 or later. binutils 2.15 or later.
config IOMMU_VMERGE
bool "Enable IOMMU virtual merging (EXPERIMENTAL)"
depends on EXPERIMENTAL
default n
help
Cause IO segments sent to a device for DMA to be merged virtually
by the IOMMU when they happen to have been allocated contiguously.
This doesn't add pressure to the IOMMU allocator. However, some
drivers don't support getting large merged segments coming back
from *_map_sg(). Say Y if you know the drivers you are using are
properly handling this case.
config SMP config SMP
bool "Symmetric multi-processing support" bool "Symmetric multi-processing support"
---help--- ---help---
...@@ -287,9 +310,6 @@ config VIOTAPE ...@@ -287,9 +310,6 @@ config VIOTAPE
If you are running Linux on an iSeries system and you want Linux If you are running Linux on an iSeries system and you want Linux
to read and/or write a tape drive owned by OS/400, say Y here. to read and/or write a tape drive owned by OS/400, say Y here.
config VETH
tristate "iSeries Virtual Ethernet driver support"
endmenu endmenu
config VIOPATH config VIOPATH
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -10,11 +10,12 @@ obj-y := setup.o entry.o traps.o irq.o idle.o \ ...@@ -10,11 +10,12 @@ obj-y := setup.o entry.o traps.o irq.o idle.o \
align.o semaphore.o bitops.o stab.o pacaData.o \ align.o semaphore.o bitops.o stab.o pacaData.o \
udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
ptrace32.o signal32.o pmc.o rtc.o init_task.o \ ptrace32.o signal32.o pmc.o rtc.o init_task.o \
lmb.o cputable.o cpu_setup_power4.o idle_power4.o lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
iommu.o
obj-$(CONFIG_PPC_OF) += of_device.o obj-$(CONFIG_PPC_OF) += of_device.o
obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_dma.o obj-$(CONFIG_PCI) += pci.o pci_dn.o pci_iommu.o
ifdef CONFIG_PPC_ISERIES ifdef CONFIG_PPC_ISERIES
obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o \ obj-$(CONFIG_PCI) += iSeries_pci.o iSeries_pci_reset.o \
...@@ -28,12 +29,12 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ ...@@ -28,12 +29,12 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \
HvCall.o HvLpConfig.o LparData.o mf_proc.o \ HvCall.o HvLpConfig.o LparData.o mf_proc.o \
iSeries_setup.o ItLpQueue.o hvCall.o \ iSeries_setup.o ItLpQueue.o hvCall.o \
mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \
proc_pmc.o proc_pmc.o iSeries_iommu.o
obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \ eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \
open_pic.o xics.o pSeries_htab.o rtas.o \ open_pic.o xics.o pSeries_htab.o rtas.o \
chrp_setup.o i8259.o prom.o vio.o chrp_setup.o i8259.o prom.o vio.o pSeries_iommu.o
obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
...@@ -49,6 +50,8 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o ...@@ -49,6 +50,8 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \
pmac_time.o pmac_nvram.o pmac_low_i2c.o \ pmac_time.o pmac_nvram.o pmac_low_i2c.o \
open_pic_u3.o open_pic_u3.o
obj-$(CONFIG_PMAC_DART) += pmac_iommu.o
ifdef CONFIG_SMP ifdef CONFIG_SMP
obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o
endif endif
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#include <asm/pci_dma.h> #include <asm/iommu.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/irq.h> #include <asm/irq.h>
......
...@@ -826,7 +826,14 @@ SystemCall_common: ...@@ -826,7 +826,14 @@ SystemCall_common:
_GLOBAL(do_hash_page_ISI) _GLOBAL(do_hash_page_ISI)
li r4,0 li r4,0
_GLOBAL(do_hash_page_DSI) _GLOBAL(do_hash_page_DSI)
rlwimi r4,r23,32-13,30,30 /* Insert MSR_PR as _PAGE_USER */ /*
* We need to set the _PAGE_USER bit if MSR_PR is set or if we are
* accessing a userspace segment (even from the kernel). We assume
* kernel addresses always have the high bit set.
*/
rotldi r0,r3,15 /* Move high bit into MSR_PR position */
orc r0,r23,r0
rlwimi r4,r0,32-13,30,30 /* Insert into _PAGE_USER */
ori r4,r4,1 /* add _PAGE_PRESENT */ ori r4,r4,1 /* add _PAGE_PRESENT */
mflr r21 /* Save LR in r21 */ mflr r21 /* Save LR in r21 */
......
/*
* arch/ppc64/kernel/iSeries_iommu.c
*
* Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
*
* Rewrite, cleanup:
*
* Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation
*
* Dynamic DMA mapping support, iSeries-specific parts.
*
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/ppcdebug.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/LparData.h>
#include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/iSeries/iSeries_pci.h>
#include <asm/machdep.h>
#include "pci.h"
static struct iommu_table veth_iommu_table; /* Tce table for virtual ethernet */
static struct iommu_table vio_iommu_table; /* Tce table for virtual I/O */
static struct iSeries_Device_Node veth_dev_node = { .LogicalSlot = 0xFF, .iommu_table = &veth_iommu_table };
static struct iSeries_Device_Node vio_dev_node = { .LogicalSlot = 0xFF, .iommu_table = &vio_iommu_table };
static struct pci_dev _veth_dev = { .sysdata = &veth_dev_node };
static struct pci_dev _vio_dev = { .sysdata = &vio_dev_node, .dev.bus = &pci_bus_type };
/*
* I wonder what the deal is with these. Nobody uses them. Why do they
* exist? Why do we export them to modules? Why is this comment here, and
* why didn't I just delete them?
*/
struct pci_dev *iSeries_veth_dev = &_veth_dev;
struct device *iSeries_vio_dev = &_vio_dev.dev;
EXPORT_SYMBOL(iSeries_veth_dev);
EXPORT_SYMBOL(iSeries_vio_dev);
extern struct list_head iSeries_Global_Device_List;
static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
unsigned long uaddr, int direction)
{
u64 rc;
union tce_entry tce;
while (npages--) {
tce.te_word = 0;
tce.te_bits.tb_rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
if (tbl->it_type == TCE_VB) {
/* Virtual Bus */
tce.te_bits.tb_valid = 1;
tce.te_bits.tb_allio = 1;
if (direction != PCI_DMA_TODEVICE)
tce.te_bits.tb_rdwr = 1;
} else {
/* PCI Bus */
tce.te_bits.tb_rdwr = 1; /* Read allowed */
if (direction != PCI_DMA_TODEVICE)
tce.te_bits.tb_pciwr = 1;
}
rc = HvCallXm_setTce((u64)tbl->it_index,
(u64)index,
tce.te_word);
if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
index++;
uaddr += PAGE_SIZE;
}
}
static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
{
u64 rc;
union tce_entry tce;
while (npages--) {
tce.te_word = 0;
rc = HvCallXm_setTce((u64)tbl->it_index,
(u64)index,
tce.te_word);
if (rc)
panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", rc);
index++;
}
}
void __init iommu_vio_init(void)
{
struct iommu_table *t;
struct iommu_table_cb cb;
unsigned long cbp;
cb.itc_busno = 255; /* Bus 255 is the virtual bus */
cb.itc_virtbus = 0xff; /* Ask for virtual bus */
cbp = virt_to_absolute((unsigned long)&cb);
HvCallXm_getTceTableParms(cbp);
veth_iommu_table.it_size = cb.itc_size / 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_entrysize = sizeof(union tce_entry);
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 = cb.itc_size - 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 * (PAGE_SIZE/sizeof(union tce_entry));
vio_iommu_table.it_index = cb.itc_index;
vio_iommu_table.it_type = TCE_VB;
vio_iommu_table.it_entrysize = sizeof(union tce_entry);
vio_iommu_table.it_blocksize = 1;
t = iommu_init_table(&vio_iommu_table);
if (!t)
printk("Virtual Bus VIO TCE table failed.\n");
}
/*
* This function compares the known tables to find an iommu_table
* that has already been built for hardware TCEs.
*/
static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
{
struct iSeries_Device_Node *dp;
for (dp = (struct iSeries_Device_Node *)iSeries_Global_Device_List.next;
dp != (struct iSeries_Device_Node *)&iSeries_Global_Device_List;
dp = (struct iSeries_Device_Node *)dp->Device_List.next)
if (dp->iommu_table != NULL &&
dp->iommu_table->it_type == TCE_PCI &&
dp->iommu_table->it_offset == tbl->it_offset &&
dp->iommu_table->it_index == tbl->it_index &&
dp->iommu_table->it_size == tbl->it_size)
return dp->iommu_table;
return NULL;
}
/*
* Call Hv with the architected data structure to get TCE table info.
* info. Put the returned data into the Linux representation of the
* TCE table data.
* The Hardware Tce table comes in three flavors.
* 1. TCE table shared between Buses.
* 2. TCE table per Bus.
* 3. TCE Table per IOA.
*/
static void iommu_table_getparms(struct iSeries_Device_Node* dn,
struct iommu_table* tbl)
{
struct iommu_table_cb *parms;
parms = (struct iommu_table_cb*)kmalloc(sizeof(*parms), GFP_KERNEL);
if (parms == NULL)
panic("PCI_DMA: TCE Table Allocation failed.");
memset(parms, 0, sizeof(*parms));
parms->itc_busno = ISERIES_BUS(dn);
parms->itc_slotno = dn->LogicalSlot;
parms->itc_virtbus = 0;
HvCallXm_getTceTableParms(REALADDR(parms));
if (parms->itc_size == 0)
panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
tbl->it_size = parms->itc_size;
tbl->it_busno = parms->itc_busno;
tbl->it_offset = parms->itc_offset;
tbl->it_index = parms->itc_index;
tbl->it_entrysize = sizeof(union tce_entry);
tbl->it_blocksize = 1;
tbl->it_type = TCE_PCI;
kfree(parms);
}
void iommu_devnode_init(struct iSeries_Device_Node *dn) {
struct iommu_table *tbl;
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
iommu_table_getparms(dn, tbl);
/* Look for existing tce table */
dn->iommu_table = iommu_table_find(tbl);
if (dn->iommu_table == NULL)
dn->iommu_table = iommu_init_table(tbl);
else
kfree(tbl);
return;
}
void tce_init_iSeries(void)
{
ppc_md.tce_build = tce_build_iSeries;
ppc_md.tce_free = tce_free_iSeries;
pci_iommu_init();
}
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#include <asm/ppcdebug.h> #include <asm/ppcdebug.h>
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/pci_dma.h> #include <asm/iommu.h>
#include <asm/iSeries/HvCallPci.h> #include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvCallSm.h> #include <asm/iSeries/HvCallSm.h>
...@@ -53,7 +53,7 @@ extern int panic_timeout; ...@@ -53,7 +53,7 @@ extern int panic_timeout;
extern unsigned long iSeries_Base_Io_Memory; extern unsigned long iSeries_Base_Io_Memory;
extern struct TceTable *tceTables[256]; extern struct iommu_table *tceTables[256];
extern void iSeries_MmIoTest(void); extern void iSeries_MmIoTest(void);
...@@ -273,7 +273,7 @@ void __init iSeries_pci_final_fixup(void) ...@@ -273,7 +273,7 @@ void __init iSeries_pci_final_fixup(void)
iSeries_Device_Information(pdev, Buffer, iSeries_Device_Information(pdev, Buffer,
sizeof(Buffer)); sizeof(Buffer));
printk("%d. %s\n", DeviceCount, Buffer); printk("%d. %s\n", DeviceCount, Buffer);
create_pci_bus_tce_table((unsigned long)node); iommu_devnode_init(node);
} else } else
printk("PCI: Device Tree not found for 0x%016lX\n", printk("PCI: Device Tree not found for 0x%016lX\n",
(unsigned long)pdev); (unsigned long)pdev);
......
This diff is collapsed.
...@@ -269,11 +269,13 @@ lmb_phys_mem_size(void) ...@@ -269,11 +269,13 @@ lmb_phys_mem_size(void)
return _lmb->memory.size; return _lmb->memory.size;
#else #else
struct lmb_region *_mem = &(_lmb->memory); struct lmb_region *_mem = &(_lmb->memory);
unsigned long idx = _mem->cnt-1; unsigned long total = 0;
unsigned long lastbase = _mem->region[idx].physbase; int i;
unsigned long lastsize = _mem->region[idx].size;
/* add all physical memory to the bootmem map */
return (lastbase + lastsize); for (i=0; i < _mem->cnt; i++)
total += _mem->region[i].size;
return total;
#endif /* CONFIG_MSCHUNKS */ #endif /* CONFIG_MSCHUNKS */
} }
...@@ -283,15 +285,13 @@ lmb_end_of_DRAM(void) ...@@ -283,15 +285,13 @@ lmb_end_of_DRAM(void)
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
struct lmb *_lmb = PTRRELOC(&lmb); struct lmb *_lmb = PTRRELOC(&lmb);
struct lmb_region *_mem = &(_lmb->memory); struct lmb_region *_mem = &(_lmb->memory);
unsigned long idx; int idx = _mem->cnt - 1;
for(idx=_mem->cnt-1; idx >= 0; idx--) {
#ifdef CONFIG_MSCHUNKS #ifdef CONFIG_MSCHUNKS
return (_mem->region[idx].physbase + _mem->region[idx].size); return (_mem->region[idx].physbase + _mem->region[idx].size);
#else #else
return (_mem->region[idx].base + _mem->region[idx].size); return (_mem->region[idx].base + _mem->region[idx].size);
#endif /* CONFIG_MSCHUNKS */ #endif /* CONFIG_MSCHUNKS */
}
return 0; return 0;
} }
......
...@@ -209,6 +209,48 @@ _GLOBAL(flush_dcache_range) ...@@ -209,6 +209,48 @@ _GLOBAL(flush_dcache_range)
sync sync
blr blr
/*
* Like above, but works on non-mapped physical addresses.
* Use only for non-LPAR setups ! It also assumes real mode
* is cacheable. Used for flushing out the DART before using
* it as uncacheable memory
*
* flush_dcache_phys_range(unsigned long start, unsigned long stop)
*
* flush all bytes from start to stop-1 inclusive
*/
_GLOBAL(flush_dcache_phys_range)
LOADADDR(r10,naca) /* Get Naca address */
ld r10,0(r10)
LOADADDR(r11,systemcfg) /* Get systemcfg address */
ld r11,0(r11)
lwz r7,DCACHEL1LINESIZE(r11) /* Get dcache line size */
addi r5,r7,-1
andc r6,r3,r5 /* round low to line bdy */
subf r8,r6,r4 /* compute length */
add r8,r8,r5 /* ensure we get enough */
lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */
srw. r8,r8,r9 /* compute line count */
beqlr /* nothing to do? */
mfmsr r5 /* Disable MMU Data Relocation */
ori r0,r5,MSR_DR
xori r0,r0,MSR_DR
sync
mtmsr r0
sync
isync
mtctr r8
0: dcbst 0,r6
add r6,r6,r7
bdnz 0b
sync
isync
mtmsr r5 /* Re-enable MMU Data Relocation */
sync
isync
blr
/* /*
* Flush a particular page from the data cache to RAM. * Flush a particular page from the data cache to RAM.
* Note: this is necessary because the instruction cache does *not* * Note: this is necessary because the instruction cache does *not*
......
...@@ -300,7 +300,7 @@ static void pSeries_flush_hash_range(unsigned long context, ...@@ -300,7 +300,7 @@ static void pSeries_flush_hash_range(unsigned long context,
int i, j; int i, j;
HPTE *hptep; HPTE *hptep;
Hpte_dword0 dw0; Hpte_dword0 dw0;
struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()]; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
/* XXX fix for large ptes */ /* XXX fix for large ptes */
unsigned long large = 0; unsigned long large = 0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment