Commit b6844e8f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm

* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (237 commits)
  ARM: 7004/1: fix traps.h compile warnings
  ARM: 6998/2: kernel: use proper memory barriers for bitops
  ARM: 6997/1: ep93xx: increase NR_BANKS to 16 for support of 128MB RAM
  ARM: Fix build errors caused by adding generic macros
  ARM: CPU hotplug: ensure we migrate all IRQs off a downed CPU
  ARM: CPU hotplug: pass in proper affinity mask on IRQ migration
  ARM: GIC: avoid routing interrupts to offline CPUs
  ARM: CPU hotplug: fix abuse of irqdesc->node
  ARM: 6981/2: mmci: adjust calculation of f_min
  ARM: 7000/1: LPAE: Use long long printk format for displaying the pud
  ARM: 6999/1: head, zImage: Always Enter the kernel in ARM state
  ARM: btc: avoid invalidating the branch target cache on kernel TLB maintanence
  ARM: ARM_DMA_ZONE_SIZE is no more
  ARM: mach-shark: move ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-sa1100: move ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-realview: move from ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-pxa: move from ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-ixp4xx: move from ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-h720x: move from ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ARM: mach-davinci: move from ARM_DMA_ZONE_SIZE to mdesc->dma_zone_size
  ...
parents 2f175074 3ad55155
...@@ -164,3 +164,8 @@ In either case, the following conditions must be met: ...@@ -164,3 +164,8 @@ In either case, the following conditions must be met:
- The boot loader is expected to call the kernel image by jumping - The boot loader is expected to call the kernel image by jumping
directly to the first instruction of the kernel image. directly to the first instruction of the kernel image.
On CPUs supporting the ARM instruction set, the entry must be
made in ARM state, even for a Thumb-2 kernel.
On CPUs supporting only the Thumb instruction set such as
Cortex-M class CPUs, the entry must be made in Thumb state.
ROM-able zImage boot from eSD
-----------------------------
An ROM-able zImage compiled with ZBOOT_ROM_SDHI may be written to eSD and
SuperH Mobile ARM will to boot directly from the SDHI hardware block.
This is achieved by the mask ROM loading the first portion of the image into
MERAM and then jumping to it. This portion contains loader code which
copies the entire image to SDRAM and jumps to it. From there the zImage
boot code proceeds as normal, uncompressing the image into its final
location and then jumping to it.
This code has been tested on an mackerel board using the developer 1A eSD
boot mode which is configured using the following jumper settings.
8 7 6 5 4 3 2 1
x|x|x|x| |x|x|
S4 -+-+-+-+-+-+-+-
| | | |x| | |x on
The eSD card needs to be present in SDHI slot 1 (CN7).
As such S1 and S33 also need to be configured as per
the notes in arch/arm/mach-shmobile/board-mackerel.c.
A partial zImage must be written to physical partition #1 (boot)
of the eSD at sector 0 in vrl4 format. A utility vrl4 is supplied to
accomplish this.
e.g.
vrl4 < zImage | dd of=/dev/sdX bs=512 count=17
A full copy of _the same_ zImage should be written to physical partition #1
(boot) of the eSD at sector 0. This should _not_ be in vrl4 format.
vrl4 < zImage | dd of=/dev/sdX bs=512
Note: The commands above assume that the physical partition has been
switched. No such facility currently exists in the Linux Kernel.
Physical partitions are described in the eSD specification. At the time of
writing they are not the same as partitions that are typically configured
using fdisk and visible through /proc/partitions
Kernel-provided User Helpers
============================
These are segment of kernel provided user code reachable from user space
at a fixed address in kernel memory. This is used to provide user space
with some operations which require kernel help because of unimplemented
native feature and/or instructions in many ARM CPUs. The idea is for this
code to be executed directly in user mode for best efficiency but which is
too intimate with the kernel counter part to be left to user libraries.
In fact this code might even differ from one CPU to another depending on
the available instruction set, or whether it is a SMP systems. In other
words, the kernel reserves the right to change this code as needed without
warning. Only the entry points and their results as documented here are
guaranteed to be stable.
This is different from (but doesn't preclude) a full blown VDSO
implementation, however a VDSO would prevent some assembly tricks with
constants that allows for efficient branching to those code segments. And
since those code segments only use a few cycles before returning to user
code, the overhead of a VDSO indirect far call would add a measurable
overhead to such minimalistic operations.
User space is expected to bypass those helpers and implement those things
inline (either in the code emitted directly by the compiler, or part of
the implementation of a library call) when optimizing for a recent enough
processor that has the necessary native support, but only if resulting
binaries are already to be incompatible with earlier ARM processors due to
useage of similar native instructions for other things. In other words
don't make binaries unable to run on earlier processors just for the sake
of not using these kernel helpers if your compiled code is not going to
use new instructions for other purpose.
New helpers may be added over time, so an older kernel may be missing some
helpers present in a newer kernel. For this reason, programs must check
the value of __kuser_helper_version (see below) before assuming that it is
safe to call any particular helper. This check should ideally be
performed only once at process startup time, and execution aborted early
if the required helpers are not provided by the kernel version that
process is running on.
kuser_helper_version
--------------------
Location: 0xffff0ffc
Reference declaration:
extern int32_t __kuser_helper_version;
Definition:
This field contains the number of helpers being implemented by the
running kernel. User space may read this to determine the availability
of a particular helper.
Usage example:
#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
void check_kuser_version(void)
{
if (__kuser_helper_version < 2) {
fprintf(stderr, "can't do atomic operations, kernel too old\n");
abort();
}
}
Notes:
User space may assume that the value of this field never changes
during the lifetime of any single process. This means that this
field can be read once during the initialisation of a library or
startup phase of a program.
kuser_get_tls
-------------
Location: 0xffff0fe0
Reference prototype:
void * __kuser_get_tls(void);
Input:
lr = return address
Output:
r0 = TLS value
Clobbered registers:
none
Definition:
Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
Usage example:
typedef void * (__kuser_get_tls_t)(void);
#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
void foo()
{
void *tls = __kuser_get_tls();
printf("TLS = %p\n", tls);
}
Notes:
- Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
kuser_cmpxchg
-------------
Location: 0xffff0fc0
Reference prototype:
int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
Input:
r0 = oldval
r1 = newval
r2 = ptr
lr = return address
Output:
r0 = success code (zero or non-zero)
C flag = set if r0 == 0, clear if r0 != 0
Clobbered registers:
r3, ip, flags
Definition:
Atomically store newval in *ptr only if *ptr is equal to oldval.
Return zero if *ptr was changed or non-zero if no exchange happened.
The C flag is also set if *ptr was changed to allow for assembly
optimization in the calling code.
Usage example:
typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
int atomic_add(volatile int *ptr, int val)
{
int old, new;
do {
old = *ptr;
new = old + val;
} while(__kuser_cmpxchg(old, new, ptr));
return new;
}
Notes:
- This routine already includes memory barriers as needed.
- Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
kuser_memory_barrier
--------------------
Location: 0xffff0fa0
Reference prototype:
void __kuser_memory_barrier(void);
Input:
lr = return address
Output:
none
Clobbered registers:
none
Definition:
Apply any needed memory barrier to preserve consistency with data modified
manually and __kuser_cmpxchg usage.
Usage example:
typedef void (__kuser_dmb_t)(void);
#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
Notes:
- Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
kuser_cmpxchg64
---------------
Location: 0xffff0f60
Reference prototype:
int __kuser_cmpxchg64(const int64_t *oldval,
const int64_t *newval,
volatile int64_t *ptr);
Input:
r0 = pointer to oldval
r1 = pointer to newval
r2 = pointer to target value
lr = return address
Output:
r0 = success code (zero or non-zero)
C flag = set if r0 == 0, clear if r0 != 0
Clobbered registers:
r3, lr, flags
Definition:
Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr
is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was
changed or non-zero if no exchange happened.
The C flag is also set if *ptr was changed to allow for assembly
optimization in the calling code.
Usage example:
typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
const int64_t *newval,
volatile int64_t *ptr);
#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
{
int64_t old, new;
do {
old = *ptr;
new = old + val;
} while(__kuser_cmpxchg64(&old, &new, ptr));
return new;
}
Notes:
- This routine already includes memory barriers as needed.
- Due to the length of this sequence, this spans 2 conventional kuser
"slots", therefore 0xffff0f80 is not used as a valid entry point.
- Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).
* ARM Performance Monitor Units
ARM cores often have a PMU for counting cpu and cache events like cache misses
and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU
representation in the device tree should be done as under:-
Required properties:
- compatible : should be one of
"arm,cortex-a9-pmu"
"arm,cortex-a8-pmu"
"arm,arm1176-pmu"
"arm,arm1136-pmu"
- interrupts : 1 combined interrupt or 1 per core.
Example:
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <100 101>;
};
...@@ -10,7 +10,7 @@ config ARM ...@@ -10,7 +10,7 @@ config ARM
select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL) select HAVE_KPROBES if !XIP_KERNEL
select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_KRETPROBES if (HAVE_KPROBES)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
...@@ -37,6 +37,9 @@ config ARM ...@@ -37,6 +37,9 @@ config ARM
Europe. There is an ARM Linux project with a web page at Europe. There is an ARM Linux project with a web page at
<http://www.arm.linux.org.uk/>. <http://www.arm.linux.org.uk/>.
config ARM_HAS_SG_CHAIN
bool
config HAVE_PWM config HAVE_PWM
bool bool
...@@ -1347,7 +1350,6 @@ config SMP_ON_UP ...@@ -1347,7 +1350,6 @@ config SMP_ON_UP
config HAVE_ARM_SCU config HAVE_ARM_SCU
bool bool
depends on SMP
help help
This option enables support for the ARM system coherency unit This option enables support for the ARM system coherency unit
...@@ -1716,17 +1718,34 @@ config ZBOOT_ROM ...@@ -1716,17 +1718,34 @@ config ZBOOT_ROM
Say Y here if you intend to execute your compressed kernel image Say Y here if you intend to execute your compressed kernel image
(zImage) directly from ROM or flash. If unsure, say N. (zImage) directly from ROM or flash. If unsure, say N.
choice
prompt "Include SD/MMC loader in zImage (EXPERIMENTAL)"
depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL
default ZBOOT_ROM_NONE
help
Include experimental SD/MMC loading code in the ROM-able zImage.
With this enabled it is possible to write the the ROM-able zImage
kernel image to an MMC or SD card and boot the kernel straight
from the reset vector. At reset the processor Mask ROM will load
the first part of the the ROM-able zImage which in turn loads the
rest the kernel image to RAM.
config ZBOOT_ROM_NONE
bool "No SD/MMC loader in zImage (EXPERIMENTAL)"
help
Do not load image from SD or MMC
config ZBOOT_ROM_MMCIF config ZBOOT_ROM_MMCIF
bool "Include MMCIF loader in zImage (EXPERIMENTAL)" bool "Include MMCIF loader in zImage (EXPERIMENTAL)"
depends on ZBOOT_ROM && ARCH_SH7372 && EXPERIMENTAL
help help
Say Y here to include experimental MMCIF loading code in the Load image from MMCIF hardware block.
ROM-able zImage. With this enabled it is possible to write the
the ROM-able zImage kernel image to an MMC card and boot the config ZBOOT_ROM_SH_MOBILE_SDHI
kernel straight from the reset vector. At reset the processor bool "Include SuperH Mobile SDHI loader in zImage (EXPERIMENTAL)"
Mask ROM will load the first part of the the ROM-able zImage help
which in turn loads the rest the kernel image to RAM using the Load image from SDHI hardware block
MMCIF hardware block.
endchoice
config CMDLINE config CMDLINE
string "Default kernel command string" string "Default kernel command string"
......
...@@ -6,13 +6,19 @@ ...@@ -6,13 +6,19 @@
OBJS = OBJS =
# Ensure that mmcif loader code appears early in the image # Ensure that MMCIF loader code appears early in the image
# to minimise that number of bocks that have to be read in # to minimise that number of bocks that have to be read in
# order to load it. # order to load it.
ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y) ifeq ($(CONFIG_ZBOOT_ROM_MMCIF),y)
ifeq ($(CONFIG_ARCH_SH7372),y)
OBJS += mmcif-sh7372.o OBJS += mmcif-sh7372.o
endif endif
# Ensure that SDHI loader code appears early in the image
# to minimise that number of bocks that have to be read in
# order to load it.
ifeq ($(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI),y)
OBJS += sdhi-shmobile.o
OBJS += sdhi-sh7372.o
endif endif
AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
......
...@@ -25,14 +25,14 @@ ...@@ -25,14 +25,14 @@
/* load board-specific initialization code */ /* load board-specific initialization code */
#include <mach/zboot.h> #include <mach/zboot.h>
#ifdef CONFIG_ZBOOT_ROM_MMCIF #if defined(CONFIG_ZBOOT_ROM_MMCIF) || defined(CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI)
/* Load image from MMC */ /* Load image from MMC/SD */
adr sp, __tmp_stack + 128 adr sp, __tmp_stack + 256
ldr r0, __image_start ldr r0, __image_start
ldr r1, __image_end ldr r1, __image_end
subs r1, r1, r0 subs r1, r1, r0
ldr r0, __load_base ldr r0, __load_base
bl mmcif_loader bl mmc_loader
/* Jump to loaded code */ /* Jump to loaded code */
ldr r0, __loaded ldr r0, __loaded
...@@ -51,9 +51,9 @@ __loaded: ...@@ -51,9 +51,9 @@ __loaded:
.long __continue .long __continue
.align .align
__tmp_stack: __tmp_stack:
.space 128 .space 256
__continue: __continue:
#endif /* CONFIG_ZBOOT_ROM_MMCIF */ #endif /* CONFIG_ZBOOT_ROM_MMC || CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI */
b 1f b 1f
__atags:@ tag #1 __atags:@ tag #1
......
...@@ -353,7 +353,8 @@ not_relocated: mov r0, #0 ...@@ -353,7 +353,8 @@ not_relocated: mov r0, #0
mov r0, #0 @ must be zero mov r0, #0 @ must be zero
mov r1, r7 @ restore architecture number mov r1, r7 @ restore architecture number
mov r2, r8 @ restore atags pointer mov r2, r8 @ restore atags pointer
mov pc, r4 @ call kernel ARM( mov pc, r4 ) @ call kernel
THUMB( bx r4 ) @ entry point is always ARM
.align 2 .align 2
.type LC0, #object .type LC0, #object
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
* to an MMC card * to an MMC card
* # dd if=vrl4.out of=/dev/sdx bs=512 seek=1 * # dd if=vrl4.out of=/dev/sdx bs=512 seek=1
*/ */
asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len) asmlinkage void mmc_loader(unsigned char *buf, unsigned long len)
{ {
mmc_init_progress(); mmc_init_progress();
mmc_update_progress(MMC_PROGRESS_ENTER); mmc_update_progress(MMC_PROGRESS_ENTER);
......
/*
* SuperH Mobile SDHI
*
* Copyright (C) 2010 Magnus Damm
* Copyright (C) 2010 Kuninori Morimoto
* Copyright (C) 2010 Simon Horman
*
* 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.
*
* Parts inspired by u-boot
*/
#include <linux/io.h>
#include <mach/mmc.h>
#include <linux/mmc/boot.h>
#include <linux/mmc/tmio.h>
#include "sdhi-shmobile.h"
#define PORT179CR 0xe60520b3
#define PORT180CR 0xe60520b4
#define PORT181CR 0xe60520b5
#define PORT182CR 0xe60520b6
#define PORT183CR 0xe60520b7
#define PORT184CR 0xe60520b8
#define SMSTPCR3 0xe615013c
#define CR_INPUT_ENABLE 0x10
#define CR_FUNCTION1 0x01
#define SDHI1_BASE (void __iomem *)0xe6860000
#define SDHI_BASE SDHI1_BASE
/* SuperH Mobile SDHI loader
*
* loads the zImage from an SD card starting from block 0
* on physical partition 1
*
* The image must be start with a vrl4 header and
* the zImage must start at offset 512 of the image. That is,
* at block 1 (=byte 512) of physical partition 1
*
* Use the following line to write the vrl4 formated zImage
* to an SD card
* # dd if=vrl4.out of=/dev/sdx bs=512
*/
asmlinkage void mmc_loader(unsigned short *buf, unsigned long len)
{
int high_capacity;
mmc_init_progress();
mmc_update_progress(MMC_PROGRESS_ENTER);
/* Initialise SDHI1 */
/* PORT184CR: GPIO_FN_SDHICMD1 Control */
__raw_writeb(CR_FUNCTION1, PORT184CR);
/* PORT179CR: GPIO_FN_SDHICLK1 Control */
__raw_writeb(CR_INPUT_ENABLE|CR_FUNCTION1, PORT179CR);
/* PORT181CR: GPIO_FN_SDHID1_3 Control */
__raw_writeb(CR_FUNCTION1, PORT183CR);
/* PORT182CR: GPIO_FN_SDHID1_2 Control */
__raw_writeb(CR_FUNCTION1, PORT182CR);
/* PORT183CR: GPIO_FN_SDHID1_1 Control */
__raw_writeb(CR_FUNCTION1, PORT181CR);
/* PORT180CR: GPIO_FN_SDHID1_0 Control */
__raw_writeb(CR_FUNCTION1, PORT180CR);
/* Enable clock to SDHI1 hardware block */
__raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 13), SMSTPCR3);
/* setup SDHI hardware */
mmc_update_progress(MMC_PROGRESS_INIT);
high_capacity = sdhi_boot_init(SDHI_BASE);
if (high_capacity < 0)
goto err;
mmc_update_progress(MMC_PROGRESS_LOAD);
/* load kernel */
if (sdhi_boot_do_read(SDHI_BASE, high_capacity,
0, /* Kernel is at block 1 */
(len + TMIO_BBS - 1) / TMIO_BBS, buf))
goto err;
/* Disable clock to SDHI1 hardware block */
__raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3);
mmc_update_progress(MMC_PROGRESS_DONE);
return;
err:
for(;;);
}
This diff is collapsed.
#ifndef SDHI_MOBILE_H
#define SDHI_MOBILE_H
#include <linux/compiler.h>
int sdhi_boot_do_read(void __iomem *base, int high_capacity,
unsigned long offset, unsigned short count,
unsigned short *buf);
int sdhi_boot_init(void __iomem *base);
#endif
...@@ -33,20 +33,24 @@ SECTIONS ...@@ -33,20 +33,24 @@ SECTIONS
*(.text.*) *(.text.*)
*(.fixup) *(.fixup)
*(.gnu.warning) *(.gnu.warning)
*(.glue_7t)
*(.glue_7)
}
.rodata : {
*(.rodata) *(.rodata)
*(.rodata.*) *(.rodata.*)
*(.glue_7) }
*(.glue_7t) .piggydata : {
*(.piggydata) *(.piggydata)
. = ALIGN(4);
} }
. = ALIGN(4);
_etext = .; _etext = .;
.got.plt : { *(.got.plt) }
_got_start = .; _got_start = .;
.got : { *(.got) } .got : { *(.got) }
_got_end = .; _got_end = .;
.got.plt : { *(.got.plt) }
_edata = .; _edata = .;
. = BSS_START; . = BSS_START;
......
...@@ -79,6 +79,8 @@ struct dmabounce_device_info { ...@@ -79,6 +79,8 @@ struct dmabounce_device_info {
struct dmabounce_pool large; struct dmabounce_pool large;
rwlock_t lock; rwlock_t lock;
int (*needs_bounce)(struct device *, dma_addr_t, size_t);
}; };
#ifdef STATS #ifdef STATS
...@@ -210,114 +212,91 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, ...@@ -210,114 +212,91 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev,
if (!dev || !dev->archdata.dmabounce) if (!dev || !dev->archdata.dmabounce)
return NULL; return NULL;
if (dma_mapping_error(dev, dma_addr)) { if (dma_mapping_error(dev, dma_addr)) {
if (dev) dev_err(dev, "Trying to %s invalid mapping\n", where);
dev_err(dev, "Trying to %s invalid mapping\n", where);
else
pr_err("unknown device: Trying to %s invalid mapping\n", where);
return NULL; return NULL;
} }
return find_safe_buffer(dev->archdata.dmabounce, dma_addr); return find_safe_buffer(dev->archdata.dmabounce, dma_addr);
} }
static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
enum dma_data_direction dir)
{ {
struct dmabounce_device_info *device_info = dev->archdata.dmabounce; if (!dev || !dev->archdata.dmabounce)
dma_addr_t dma_addr; return 0;
int needs_bounce = 0;
if (device_info)
DO_STATS ( device_info->map_op_count++ );
dma_addr = virt_to_dma(dev, ptr);
if (dev->dma_mask) { if (dev->dma_mask) {
unsigned long mask = *dev->dma_mask; unsigned long limit, mask = *dev->dma_mask;
unsigned long limit;
limit = (mask + 1) & ~mask; limit = (mask + 1) & ~mask;
if (limit && size > limit) { if (limit && size > limit) {
dev_err(dev, "DMA mapping too big (requested %#x " dev_err(dev, "DMA mapping too big (requested %#x "
"mask %#Lx)\n", size, *dev->dma_mask); "mask %#Lx)\n", size, *dev->dma_mask);
return ~0; return -E2BIG;
} }
/* /* Figure out if we need to bounce from the DMA mask. */
* Figure out if we need to bounce from the DMA mask. if ((dma_addr | (dma_addr + size - 1)) & ~mask)
*/ return 1;
needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask;
} }
if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size);
struct safe_buffer *buf; }
buf = alloc_safe_buffer(device_info, ptr, size, dir); static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
if (buf == 0) { enum dma_data_direction dir)
dev_err(dev, "%s: unable to map unsafe buffer %p!\n", {
__func__, ptr); struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
return ~0; struct safe_buffer *buf;
}
dev_dbg(dev, if (device_info)
"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", DO_STATS ( device_info->map_op_count++ );
__func__, buf->ptr, virt_to_dma(dev, buf->ptr),
buf->safe, buf->safe_dma_addr);
if ((dir == DMA_TO_DEVICE) || buf = alloc_safe_buffer(device_info, ptr, size, dir);
(dir == DMA_BIDIRECTIONAL)) { if (buf == NULL) {
dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
__func__, ptr, buf->safe, size); __func__, ptr);
memcpy(buf->safe, ptr, size); return ~0;
} }
ptr = buf->safe;
dma_addr = buf->safe_dma_addr; dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
} else { __func__, buf->ptr, virt_to_dma(dev, buf->ptr),
/* buf->safe, buf->safe_dma_addr);
* We don't need to sync the DMA buffer since
* it was allocated via the coherent allocators. if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
*/ dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n",
__dma_single_cpu_to_dev(ptr, size, dir); __func__, ptr, buf->safe, size);
memcpy(buf->safe, ptr, size);
} }
return dma_addr; return buf->safe_dma_addr;
} }
static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, static inline void unmap_single(struct device *dev, struct safe_buffer *buf,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); BUG_ON(buf->size != size);
BUG_ON(buf->direction != dir);
if (buf) {
BUG_ON(buf->size != size);
BUG_ON(buf->direction != dir);
dev_dbg(dev, dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
"%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr),
__func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr);
buf->safe, buf->safe_dma_addr);
DO_STATS(dev->archdata.dmabounce->bounce_count++); DO_STATS(dev->archdata.dmabounce->bounce_count++);
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
void *ptr = buf->ptr; void *ptr = buf->ptr;
dev_dbg(dev, dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n",
"%s: copy back safe %p to unsafe %p size %d\n", __func__, buf->safe, ptr, size);
__func__, buf->safe, ptr, size); memcpy(ptr, buf->safe, size);
memcpy(ptr, buf->safe, size);
/* /*
* Since we may have written to a page cache page, * Since we may have written to a page cache page,
* we need to ensure that the data will be coherent * we need to ensure that the data will be coherent
* with user mappings. * with user mappings.
*/ */
__cpuc_flush_dcache_area(ptr, size); __cpuc_flush_dcache_area(ptr, size);
}
free_safe_buffer(dev->archdata.dmabounce, buf);
} else {
__dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
} }
free_safe_buffer(dev->archdata.dmabounce, buf);
} }
/* ************************************************** */ /* ************************************************** */
...@@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, ...@@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
* substitute the safe buffer for the unsafe one. * substitute the safe buffer for the unsafe one.
* (basically move the buffer from an unsafe area to a safe one) * (basically move the buffer from an unsafe area to a safe one)
*/ */
dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction dir)
{
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, ptr, size, dir);
BUG_ON(!valid_dma_direction(dir));
return map_single(dev, ptr, size, dir);
}
EXPORT_SYMBOL(__dma_map_single);
/*
* see if a mapped address was really a "safe" buffer and if so, copy
* the data from the safe buffer back to the unsafe buffer and free up
* the safe buffer. (basically return things back to the way they
* should be)
*/
void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, dir);
unmap_single(dev, dma_addr, size, dir);
}
EXPORT_SYMBOL(__dma_unmap_single);
dma_addr_t __dma_map_page(struct device *dev, struct page *page, dma_addr_t __dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir) unsigned long offset, size_t size, enum dma_data_direction dir)
{ {
dma_addr_t dma_addr;
int ret;
dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n",
__func__, page, offset, size, dir); __func__, page, offset, size, dir);
BUG_ON(!valid_dma_direction(dir)); dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset;
ret = needs_bounce(dev, dma_addr, size);
if (ret < 0)
return ~0;
if (ret == 0) {
__dma_page_cpu_to_dev(page, offset, size, dir);
return dma_addr;
}
if (PageHighMem(page)) { if (PageHighMem(page)) {
dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
"is not supported\n");
return ~0; return ~0;
} }
...@@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page); ...@@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page);
void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", struct safe_buffer *buf;
__func__, (void *) dma_addr, size, dir);
dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n",
__func__, dma_addr, size, dir);
buf = find_safe_buffer_dev(dev, dma_addr, __func__);
if (!buf) {
__dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
dma_addr & ~PAGE_MASK, size, dir);
return;
}
unmap_single(dev, dma_addr, size, dir); unmap_single(dev, buf, size, dir);
} }
EXPORT_SYMBOL(__dma_unmap_page); EXPORT_SYMBOL(__dma_unmap_page);
...@@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, ...@@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
} }
int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
unsigned long large_buffer_size) unsigned long large_buffer_size,
int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t))
{ {
struct dmabounce_device_info *device_info; struct dmabounce_device_info *device_info;
int ret; int ret;
...@@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, ...@@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
device_info->dev = dev; device_info->dev = dev;
INIT_LIST_HEAD(&device_info->safe_buffers); INIT_LIST_HEAD(&device_info->safe_buffers);
rwlock_init(&device_info->lock); rwlock_init(&device_info->lock);
device_info->needs_bounce = needs_bounce_fn;
#ifdef STATS #ifdef STATS
device_info->total_allocs = 0; device_info->total_allocs = 0;
......
...@@ -179,22 +179,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, ...@@ -179,22 +179,21 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
{ {
void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3); void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
unsigned int shift = (d->irq % 4) * 8; unsigned int shift = (d->irq % 4) * 8;
unsigned int cpu = cpumask_first(mask_val); unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
u32 val, mask, bit; u32 val, mask, bit;
if (cpu >= 8) if (cpu >= 8 || cpu >= nr_cpu_ids)
return -EINVAL; return -EINVAL;
mask = 0xff << shift; mask = 0xff << shift;
bit = 1 << (cpu + shift); bit = 1 << (cpu + shift);
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
d->node = cpu;
val = readl_relaxed(reg) & ~mask; val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg); writel_relaxed(val | bit, reg);
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
return 0; return IRQ_SET_MASK_OK;
} }
#endif #endif
......
...@@ -243,6 +243,12 @@ static struct resource it8152_mem = { ...@@ -243,6 +243,12 @@ static struct resource it8152_mem = {
* ITE8152 chip can address up to 64MByte, so all the devices * ITE8152 chip can address up to 64MByte, so all the devices
* connected to ITE8152 (PCI and USB) should have limited DMA window * connected to ITE8152 (PCI and USB) should have limited DMA window
*/ */
static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
{
dev_dbg(dev, "%s: dma_addr %08x, size %08x\n",
__func__, dma_addr, size);
return (dma_addr + size - PHYS_OFFSET) >= SZ_64M;
}
/* /*
* Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all
...@@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev) ...@@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev)
if (dev->dma_mask) if (dev->dma_mask)
*dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
dmabounce_register_dev(dev, 2048, 4096); dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce);
} }
return 0; return 0;
} }
...@@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev) ...@@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev)
return 0; return 0;
} }
int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
{
dev_dbg(dev, "%s: dma_addr %08x, size %08x\n",
__func__, dma_addr, size);
return (dev->bus == &pci_bus_type) &&
((dma_addr + size - PHYS_OFFSET) >= SZ_64M);
}
int dma_set_coherent_mask(struct device *dev, u64 mask) int dma_set_coherent_mask(struct device *dev, u64 mask)
{ {
if (mask >= PHYS_OFFSET + SZ_64M - 1) if (mask >= PHYS_OFFSET + SZ_64M - 1)
......
...@@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, ...@@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2];
} }
#endif
#ifdef CONFIG_DMABOUNCE
/*
* According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a
* significant bug in the SA1111 SDRAM shared memory controller. If
* an access to a region of memory above 1MB relative to the bank base,
* it is important that address bit 10 _NOT_ be asserted. Depending
* on the configuration of the RAM, bit 10 may correspond to one
* of several different (processor-relative) address bits.
*
* This routine only identifies whether or not a given DMA address
* is susceptible to the bug.
*
* This should only get called for sa1111_device types due to the
* way we configure our device dma_masks.
*/
static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
/*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
* target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
* SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid.
*/
return (machine_is_assabet() || machine_is_pfs168()) &&
(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
}
#endif #endif
static void sa1111_dev_release(struct device *_dev) static void sa1111_dev_release(struct device *_dev)
...@@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, ...@@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask;
if (dev->dma_mask != 0xffffffffUL) { if (dev->dma_mask != 0xffffffffUL) {
ret = dmabounce_register_dev(&dev->dev, 1024, 4096); ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
sa1111_needs_bounce);
if (ret) { if (ret) {
dev_err(&dev->dev, "SA1111: Failed to register" dev_err(&dev->dev, "SA1111: Failed to register"
" with dmabounce\n"); " with dmabounce\n");
...@@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip) ...@@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip)
kfree(sachip); kfree(sachip);
} }
/*
* According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a
* significant bug in the SA1111 SDRAM shared memory controller. If
* an access to a region of memory above 1MB relative to the bank base,
* it is important that address bit 10 _NOT_ be asserted. Depending
* on the configuration of the RAM, bit 10 may correspond to one
* of several different (processor-relative) address bits.
*
* This routine only identifies whether or not a given DMA address
* is susceptible to the bug.
*
* This should only get called for sa1111_device types due to the
* way we configure our device dma_masks.
*/
int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
/*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
* target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
* SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid.
*/
return ((machine_is_assabet() || machine_is_pfs168()) &&
(addr >= 0xc8000000 || (addr + size) >= 0xc8000000));
}
struct sa1111_save_data { struct sa1111_save_data {
unsigned int skcr; unsigned int skcr;
unsigned int skpcr; unsigned int skpcr;
......
...@@ -293,4 +293,13 @@ ...@@ -293,4 +293,13 @@
.macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort
.endm .endm
/* Utility macro for declaring string literals */
.macro string name:req, string
.type \name , #object
\name:
.asciz "\string"
.size \name , . - \name
.endm
#endif /* __ASM_ASSEMBLER_H__ */ #endif /* __ASM_ASSEMBLER_H__ */
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <asm/system.h> #include <asm/system.h>
#define smp_mb__before_clear_bit() mb() #define smp_mb__before_clear_bit() smp_mb()
#define smp_mb__after_clear_bit() mb() #define smp_mb__after_clear_bit() smp_mb()
/* /*
* These functions are the basis of our bit ops. * These functions are the basis of our bit ops.
......
...@@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ...@@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
___dma_page_dev_to_cpu(page, off, size, dir); ___dma_page_dev_to_cpu(page, off, size, dir);
} }
/* extern int dma_supported(struct device *, u64);
* Return whether the given device DMA address mask can be supported extern int dma_set_mask(struct device *, u64);
* properly. For example, if your device can only drive the low 24-bits
* during bus mastering, then you would pass 0x00ffffff as the mask
* to this function.
*
* FIXME: This should really be a platform specific issue - we should
* return false if GFP_DMA allocations may not satisfy the supplied 'mask'.
*/
static inline int dma_supported(struct device *dev, u64 mask)
{
if (mask < ISA_DMA_THRESHOLD)
return 0;
return 1;
}
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
{
#ifdef CONFIG_DMABOUNCE
if (dev->archdata.dmabounce) {
if (dma_mask >= ISA_DMA_THRESHOLD)
return 0;
else
return -EIO;
}
#endif
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO;
*dev->dma_mask = dma_mask;
return 0;
}
/* /*
* DMA errors are defined by all-bits-set in the DMA address. * DMA errors are defined by all-bits-set in the DMA address.
...@@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, ...@@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
* @dev: valid struct device pointer * @dev: valid struct device pointer
* @small_buf_size: size of buffers to use with small buffer pool * @small_buf_size: size of buffers to use with small buffer pool
* @large_buf_size: size of buffers to use with large buffer pool (can be 0) * @large_buf_size: size of buffers to use with large buffer pool (can be 0)
* @needs_bounce_fn: called to determine whether buffer needs bouncing
* *
* This function should be called by low-level platform code to register * This function should be called by low-level platform code to register
* a device as requireing DMA buffer bouncing. The function will allocate * a device as requireing DMA buffer bouncing. The function will allocate
* appropriate DMA pools for the device. * appropriate DMA pools for the device.
*
*/ */
extern int dmabounce_register_dev(struct device *, unsigned long, extern int dmabounce_register_dev(struct device *, unsigned long,
unsigned long); unsigned long, int (*)(struct device *, dma_addr_t, size_t));
/** /**
* dmabounce_unregister_dev * dmabounce_unregister_dev
...@@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long, ...@@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long,
*/ */
extern void dmabounce_unregister_dev(struct device *); extern void dmabounce_unregister_dev(struct device *);
/**
* dma_needs_bounce
*
* @dev: valid struct device pointer
* @dma_handle: dma_handle of unbounced buffer
* @size: size of region being mapped
*
* Platforms that utilize the dmabounce mechanism must implement
* this function.
*
* The dmabounce routines call this function whenever a dma-mapping
* is requested to determine whether a given buffer needs to be bounced
* or not. The function must return 0 if the buffer is OK for
* DMA access and 1 if the buffer needs to be bounced.
*
*/
extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
/* /*
* The DMA API, implemented by dmabounce.c. See below for descriptions. * The DMA API, implemented by dmabounce.c. See below for descriptions.
*/ */
extern dma_addr_t __dma_map_single(struct device *, void *, size_t,
enum dma_data_direction);
extern void __dma_unmap_single(struct device *, dma_addr_t, size_t,
enum dma_data_direction);
extern dma_addr_t __dma_map_page(struct device *, struct page *, extern dma_addr_t __dma_map_page(struct device *, struct page *,
unsigned long, size_t, enum dma_data_direction); unsigned long, size_t, enum dma_data_direction);
extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, extern void __dma_unmap_page(struct device *, dma_addr_t, size_t,
...@@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, ...@@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
} }
static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr,
size_t size, enum dma_data_direction dir)
{
__dma_single_cpu_to_dev(cpu_addr, size, dir);
return virt_to_dma(dev, cpu_addr);
}
static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir) unsigned long offset, size_t size, enum dma_data_direction dir)
{ {
...@@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, ...@@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
return pfn_to_dma(dev, page_to_pfn(page)) + offset; return pfn_to_dma(dev, page_to_pfn(page)) + offset;
} }
static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
__dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
}
static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
...@@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, ...@@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
unsigned long offset;
struct page *page;
dma_addr_t addr; dma_addr_t addr;
BUG_ON(!virt_addr_valid(cpu_addr));
BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
BUG_ON(!valid_dma_direction(dir)); BUG_ON(!valid_dma_direction(dir));
addr = __dma_map_single(dev, cpu_addr, size, dir); page = virt_to_page(cpu_addr);
debug_dma_map_page(dev, virt_to_page(cpu_addr), offset = (unsigned long)cpu_addr & ~PAGE_MASK;
(unsigned long)cpu_addr & ~PAGE_MASK, size, addr = __dma_map_page(dev, page, offset, size, dir);
dir, addr, true); debug_dma_map_page(dev, page, offset, size, dir, addr, true);
return addr; return addr;
} }
...@@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, ...@@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
debug_dma_unmap_page(dev, handle, size, dir, true); debug_dma_unmap_page(dev, handle, size, dir, true);
__dma_unmap_single(dev, handle, size, dir); __dma_unmap_page(dev, handle, size, dir);
} }
/** /**
......
#ifndef __ASM_ARM_DMA_H #ifndef __ASM_ARM_DMA_H
#define __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H
#include <asm/memory.h>
/* /*
* This is the maximum virtual address which can be DMA'd from. * This is the maximum virtual address which can be DMA'd from.
*/ */
#ifndef ARM_DMA_ZONE_SIZE #ifndef CONFIG_ZONE_DMA
#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_ADDRESS 0xffffffffUL
#else #else
#define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE) #define MAX_DMA_ADDRESS ({ \
extern unsigned long arm_dma_zone_size; \
arm_dma_zone_size ? \
(PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; })
#endif #endif
#ifdef CONFIG_ISA_DMA_API #ifdef CONFIG_ISA_DMA_API
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
* Interrupt handling. Preserves r7, r8, r9 * Interrupt handling. Preserves r7, r8, r9
*/ */
.macro arch_irq_handler_default .macro arch_irq_handler_default
get_irqnr_preamble r5, lr get_irqnr_preamble r6, lr
1: get_irqnr_and_base r0, r6, r5, lr 1: get_irqnr_and_base r0, r2, r6, lr
movne r1, sp movne r1, sp
@ @
@ routine called with r0 = irq number, r1 = struct pt_regs * @ routine called with r0 = irq number, r1 = struct pt_regs *
...@@ -17,17 +17,17 @@ ...@@ -17,17 +17,17 @@
/* /*
* XXX * XXX
* *
* this macro assumes that irqstat (r6) and base (r5) are * this macro assumes that irqstat (r2) and base (r6) are
* preserved from get_irqnr_and_base above * preserved from get_irqnr_and_base above
*/ */
ALT_SMP(test_for_ipi r0, r6, r5, lr) ALT_SMP(test_for_ipi r0, r2, r6, lr)
ALT_UP_B(9997f) ALT_UP_B(9997f)
movne r1, sp movne r1, sp
adrne lr, BSYM(1b) adrne lr, BSYM(1b)
bne do_IPI bne do_IPI
#ifdef CONFIG_LOCAL_TIMERS #ifdef CONFIG_LOCAL_TIMERS
test_for_ltirq r0, r6, r5, lr test_for_ltirq r0, r2, r6, lr
movne r0, sp movne r0, sp
adrne lr, BSYM(1b) adrne lr, BSYM(1b)
bne do_local_timer bne do_local_timer
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
.align 5 .align 5
.global \symbol_name .global \symbol_name
\symbol_name: \symbol_name:
mov r4, lr mov r8, lr
arch_irq_handler_default arch_irq_handler_default
mov pc, r4 mov pc, r8
.endm .endm
...@@ -4,22 +4,26 @@ ...@@ -4,22 +4,26 @@
/* /*
* HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
*/ */
#define HWCAP_SWP 1 #define HWCAP_SWP (1 << 0)
#define HWCAP_HALF 2 #define HWCAP_HALF (1 << 1)
#define HWCAP_THUMB 4 #define HWCAP_THUMB (1 << 2)
#define HWCAP_26BIT 8 /* Play it safe */ #define HWCAP_26BIT (1 << 3) /* Play it safe */
#define HWCAP_FAST_MULT 16 #define HWCAP_FAST_MULT (1 << 4)
#define HWCAP_FPA 32 #define HWCAP_FPA (1 << 5)
#define HWCAP_VFP 64 #define HWCAP_VFP (1 << 6)
#define HWCAP_EDSP 128 #define HWCAP_EDSP (1 << 7)
#define HWCAP_JAVA 256 #define HWCAP_JAVA (1 << 8)
#define HWCAP_IWMMXT 512 #define HWCAP_IWMMXT (1 << 9)
#define HWCAP_CRUNCH 1024 #define HWCAP_CRUNCH (1 << 10)
#define HWCAP_THUMBEE 2048 #define HWCAP_THUMBEE (1 << 11)
#define HWCAP_NEON 4096 #define HWCAP_NEON (1 << 12)
#define HWCAP_VFPv3 8192 #define HWCAP_VFPv3 (1 << 13)
#define HWCAP_VFPv3D16 16384 #define HWCAP_VFPv3D16 (1 << 14)
#define HWCAP_TLS 32768 #define HWCAP_TLS (1 << 15)
#define HWCAP_VFPv4 (1 << 16)
#define HWCAP_IDIVA (1 << 17)
#define HWCAP_IDIVT (1 << 18)
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
#if defined(__KERNEL__) && !defined(__ASSEMBLY__) #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
/* /*
......
...@@ -24,12 +24,6 @@ ...@@ -24,12 +24,6 @@
#define MAX_INSN_SIZE 2 #define MAX_INSN_SIZE 2
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */ #define MAX_STACK_SIZE 64 /* 32 would probably be OK */
/*
* This undefined instruction must be unique and
* reserved solely for kprobes' use.
*/
#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8
#define regs_return_value(regs) ((regs)->ARM_r0) #define regs_return_value(regs) ((regs)->ARM_r0)
#define flush_insn_slot(p) do { } while (0) #define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0 #define kretprobe_blacklist_size 0
...@@ -38,14 +32,17 @@ typedef u32 kprobe_opcode_t; ...@@ -38,14 +32,17 @@ typedef u32 kprobe_opcode_t;
struct kprobe; struct kprobe;
typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
typedef unsigned long (kprobe_check_cc)(unsigned long); typedef unsigned long (kprobe_check_cc)(unsigned long);
typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *);
typedef void (kprobe_insn_fn_t)(void);
/* Architecture specific copy of original instruction. */ /* Architecture specific copy of original instruction. */
struct arch_specific_insn { struct arch_specific_insn {
kprobe_opcode_t *insn; kprobe_opcode_t *insn;
kprobe_insn_handler_t *insn_handler; kprobe_insn_handler_t *insn_handler;
kprobe_check_cc *insn_check_cc; kprobe_check_cc *insn_check_cc;
kprobe_insn_singlestep_t *insn_singlestep;
kprobe_insn_fn_t *insn_fn;
}; };
struct prev_kprobe { struct prev_kprobe {
...@@ -62,20 +59,9 @@ struct kprobe_ctlblk { ...@@ -62,20 +59,9 @@ struct kprobe_ctlblk {
}; };
void arch_remove_kprobe(struct kprobe *); void arch_remove_kprobe(struct kprobe *);
void kretprobe_trampoline(void);
int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
int kprobe_exceptions_notify(struct notifier_block *self, int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data); unsigned long val, void *data);
enum kprobe_insn {
INSN_REJECTED,
INSN_GOOD,
INSN_GOOD_NO_SLOT
};
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
struct arch_specific_insn *);
void __init arm_kprobe_decode_init(void);
#endif /* _ARM_KPROBES_H */ #endif /* _ARM_KPROBES_H */
...@@ -23,6 +23,10 @@ struct machine_desc { ...@@ -23,6 +23,10 @@ struct machine_desc {
unsigned int nr_irqs; /* number of IRQs */ unsigned int nr_irqs; /* number of IRQs */
#ifdef CONFIG_ZONE_DMA
unsigned long dma_zone_size; /* size of DMA-able area */
#endif
unsigned int video_start; /* start of video RAM */ unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */ unsigned int video_end; /* end of video RAM */
......
...@@ -203,18 +203,6 @@ static inline unsigned long __phys_to_virt(unsigned long x) ...@@ -203,18 +203,6 @@ static inline unsigned long __phys_to_virt(unsigned long x)
#define PHYS_OFFSET PLAT_PHYS_OFFSET #define PHYS_OFFSET PLAT_PHYS_OFFSET
#endif #endif
/*
* The DMA mask corresponding to the maximum bus address allocatable
* using GFP_DMA. The default here places no restriction on DMA
* allocations. This must be the smallest DMA mask in the system,
* so a successful GFP_DMA allocation will always satisfy this.
*/
#ifndef ARM_DMA_ZONE_SIZE
#define ISA_DMA_THRESHOLD (0xffffffffULL)
#else
#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1)
#endif
/* /*
* PFNs are used to describe any physical page; this means * PFNs are used to describe any physical page; this means
* PFN 0 == physical address 0. * PFN 0 == physical address 0.
......
...@@ -24,6 +24,8 @@ enum arm_perf_pmu_ids { ...@@ -24,6 +24,8 @@ enum arm_perf_pmu_ids {
ARM_PERF_PMU_ID_V6MP, ARM_PERF_PMU_ID_V6MP,
ARM_PERF_PMU_ID_CA8, ARM_PERF_PMU_ID_CA8,
ARM_PERF_PMU_ID_CA9, ARM_PERF_PMU_ID_CA9,
ARM_PERF_PMU_ID_CA5,
ARM_PERF_PMU_ID_CA15,
ARM_NUM_PMU_IDS, ARM_NUM_PMU_IDS,
}; };
......
...@@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device); ...@@ -52,7 +52,7 @@ reserve_pmu(enum arm_pmu_type device);
* a cookie. * a cookie.
*/ */
extern int extern int
release_pmu(struct platform_device *pdev); release_pmu(enum arm_pmu_type type);
/** /**
* init_pmu() - Initialise the PMU. * init_pmu() - Initialise the PMU.
......
...@@ -82,13 +82,13 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); ...@@ -82,13 +82,13 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext); extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
#else #else
#define cpu_proc_init() processor._proc_init() #define cpu_proc_init processor._proc_init
#define cpu_proc_fin() processor._proc_fin() #define cpu_proc_fin processor._proc_fin
#define cpu_reset(addr) processor.reset(addr) #define cpu_reset processor.reset
#define cpu_do_idle() processor._do_idle() #define cpu_do_idle processor._do_idle
#define cpu_dcache_clean_area(addr,sz) processor.dcache_clean_area(addr,sz) #define cpu_dcache_clean_area processor.dcache_clean_area
#define cpu_set_pte_ext(ptep,pte,ext) processor.set_pte_ext(ptep,pte,ext) #define cpu_set_pte_ext processor.set_pte_ext
#define cpu_do_switch_mm(pgd,mm) processor.switch_mm(pgd,mm) #define cpu_do_switch_mm processor.switch_mm
#endif #endif
extern void cpu_resume(void); extern void cpu_resume(void);
......
...@@ -69,8 +69,9 @@ ...@@ -69,8 +69,9 @@
#define PSR_c 0x000000ff /* Control */ #define PSR_c 0x000000ff /* Control */
/* /*
* ARMv7 groups of APSR bits * ARMv7 groups of PSR bits
*/ */
#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */
#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ #define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */
#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */
...@@ -199,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs); ...@@ -199,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs);
#define predicate(x) ((x) & 0xf0000000) #define predicate(x) ((x) & 0xf0000000)
#define PREDICATE_ALWAYS 0xe0000000 #define PREDICATE_ALWAYS 0xe0000000
/*
* True if instr is a 32-bit thumb instruction. This works if instr
* is the first or only half-word of a thumb instruction. It also works
* when instr holds all 32-bits of a wide thumb instruction if stored
* in the form (first_half<<16)|(second_half)
*/
#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800)
/* /*
* kprobe-based event tracer support * kprobe-based event tracer support
*/ */
......
#ifndef _ASMARM_SCATTERLIST_H #ifndef _ASMARM_SCATTERLIST_H
#define _ASMARM_SCATTERLIST_H #define _ASMARM_SCATTERLIST_H
#ifdef CONFIG_ARM_HAS_SG_CHAIN
#define ARCH_HAS_SG_CHAIN
#endif
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm-generic/scatterlist.h> #include <asm-generic/scatterlist.h>
......
...@@ -187,12 +187,16 @@ struct tagtable { ...@@ -187,12 +187,16 @@ struct tagtable {
#define __tag __used __attribute__((__section__(".taglist.init"))) #define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \ #define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn } static const struct tagtable __tagtable_##fn __tag = { tag, fn }
/* /*
* Memory map description * Memory map description
*/ */
#define NR_BANKS 8 #ifdef CONFIG_ARCH_EP93XX
# define NR_BANKS 16
#else
# define NR_BANKS 8
#endif
struct membank { struct membank {
phys_addr_t start; phys_addr_t start;
......
#ifndef __ASM_ARM_SUSPEND_H
#define __ASM_ARM_SUSPEND_H
#include <asm/memory.h>
#include <asm/tlbflush.h>
extern void cpu_resume(void);
/*
* Hide the first two arguments to __cpu_suspend - these are an implementation
* detail which platform code shouldn't have to know about.
*/
static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
{
extern int __cpu_suspend(int, long, unsigned long,
int (*)(unsigned long));
int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
flush_tlb_all();
return ret;
}
#endif
...@@ -27,5 +27,7 @@ ...@@ -27,5 +27,7 @@
void *tcm_alloc(size_t len); void *tcm_alloc(size_t len);
void tcm_free(void *addr, size_t len); void tcm_free(void *addr, size_t len);
bool tcm_dtcm_present(void);
bool tcm_itcm_present(void);
#endif #endif
...@@ -34,16 +34,12 @@ ...@@ -34,16 +34,12 @@
#define TLB_V6_D_ASID (1 << 17) #define TLB_V6_D_ASID (1 << 17)
#define TLB_V6_I_ASID (1 << 18) #define TLB_V6_I_ASID (1 << 18)
#define TLB_BTB (1 << 28)
/* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */ /* Unified Inner Shareable TLB operations (ARMv7 MP extensions) */
#define TLB_V7_UIS_PAGE (1 << 19) #define TLB_V7_UIS_PAGE (1 << 19)
#define TLB_V7_UIS_FULL (1 << 20) #define TLB_V7_UIS_FULL (1 << 20)
#define TLB_V7_UIS_ASID (1 << 21) #define TLB_V7_UIS_ASID (1 << 21)
/* Inner Shareable BTB operation (ARMv7 MP extensions) */ #define TLB_BARRIER (1 << 28)
#define TLB_V7_IS_BTB (1 << 22)
#define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */ #define TLB_L2CLEAN_FR (1 << 29) /* Feroceon */
#define TLB_DCLEAN (1 << 30) #define TLB_DCLEAN (1 << 30)
#define TLB_WB (1 << 31) #define TLB_WB (1 << 31)
...@@ -58,7 +54,7 @@ ...@@ -58,7 +54,7 @@
* v4wb - ARMv4 with write buffer without I TLB flush entry instruction * v4wb - ARMv4 with write buffer without I TLB flush entry instruction
* v4wbi - ARMv4 with write buffer with I TLB flush entry instruction * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
* fr - Feroceon (v4wbi with non-outer-cacheable page table walks) * fr - Feroceon (v4wbi with non-outer-cacheable page table walks)
* fa - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB)) * fa - Faraday (v4 with write buffer with UTLB)
* v6wbi - ARMv6 with write buffer with I TLB flush entry instruction * v6wbi - ARMv6 with write buffer with I TLB flush entry instruction
* v7wbi - identical to v6wbi * v7wbi - identical to v6wbi
*/ */
...@@ -99,7 +95,7 @@ ...@@ -99,7 +95,7 @@
# define v4_always_flags (-1UL) # define v4_always_flags (-1UL)
#endif #endif
#define fa_tlb_flags (TLB_WB | TLB_BTB | TLB_DCLEAN | \ #define fa_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
TLB_V4_U_FULL | TLB_V4_U_PAGE) TLB_V4_U_FULL | TLB_V4_U_PAGE)
#ifdef CONFIG_CPU_TLB_FA #ifdef CONFIG_CPU_TLB_FA
...@@ -166,7 +162,7 @@ ...@@ -166,7 +162,7 @@
# define v4wb_always_flags (-1UL) # define v4wb_always_flags (-1UL)
#endif #endif
#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \ #define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
TLB_V6_I_FULL | TLB_V6_D_FULL | \ TLB_V6_I_FULL | TLB_V6_D_FULL | \
TLB_V6_I_PAGE | TLB_V6_D_PAGE | \ TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
TLB_V6_I_ASID | TLB_V6_D_ASID) TLB_V6_I_ASID | TLB_V6_D_ASID)
...@@ -184,9 +180,9 @@ ...@@ -184,9 +180,9 @@
# define v6wbi_always_flags (-1UL) # define v6wbi_always_flags (-1UL)
#endif #endif
#define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \ #define v7wbi_tlb_flags_smp (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID) TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
#define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BTB | \ #define v7wbi_tlb_flags_up (TLB_WB | TLB_DCLEAN | TLB_BARRIER | \
TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID) TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
#ifdef CONFIG_CPU_TLB_V7 #ifdef CONFIG_CPU_TLB_V7
...@@ -341,15 +337,7 @@ static inline void local_flush_tlb_all(void) ...@@ -341,15 +337,7 @@ static inline void local_flush_tlb_all(void)
if (tlb_flag(TLB_V7_UIS_FULL)) if (tlb_flag(TLB_V7_UIS_FULL))
asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_BTB)) { if (tlb_flag(TLB_BARRIER)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
isb();
}
if (tlb_flag(TLB_V7_IS_BTB)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
dsb(); dsb();
isb(); isb();
} }
...@@ -389,17 +377,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) ...@@ -389,17 +377,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc");
#endif #endif
if (tlb_flag(TLB_BTB)) { if (tlb_flag(TLB_BARRIER))
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
}
if (tlb_flag(TLB_V7_IS_BTB)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
dsb(); dsb();
isb();
}
} }
static inline void static inline void
...@@ -439,17 +418,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) ...@@ -439,17 +418,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc");
#endif #endif
if (tlb_flag(TLB_BTB)) { if (tlb_flag(TLB_BARRIER))
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
}
if (tlb_flag(TLB_V7_IS_BTB)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
dsb(); dsb();
isb();
}
} }
static inline void local_flush_tlb_kernel_page(unsigned long kaddr) static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
...@@ -482,15 +452,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) ...@@ -482,15 +452,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
if (tlb_flag(TLB_V7_UIS_PAGE)) if (tlb_flag(TLB_V7_UIS_PAGE))
asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_BTB)) { if (tlb_flag(TLB_BARRIER)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
dsb();
isb();
}
if (tlb_flag(TLB_V7_IS_BTB)) {
/* flush the branch target cache */
asm("mcr p15, 0, %0, c7, c1, 6" : : "r" (zero) : "cc");
dsb(); dsb();
isb(); isb();
} }
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
#include <linux/list.h> #include <linux/list.h>
struct pt_regs;
struct task_struct;
struct undef_hook { struct undef_hook {
struct list_head node; struct list_head node;
u32 instr_mask; u32 instr_mask;
......
...@@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o ...@@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
else
obj-$(CONFIG_KPROBES) += kprobes-arm.o
endif
obj-$(CONFIG_ATAGS_PROC) += atags.o obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
......
...@@ -59,6 +59,9 @@ int main(void) ...@@ -59,6 +59,9 @@ int main(void)
DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value));
DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate));
DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate)); DEFINE(TI_VFPSTATE, offsetof(struct thread_info, vfpstate));
#ifdef CONFIG_SMP
DEFINE(VFP_CPU, offsetof(union vfp_state, hard.cpu));
#endif
#ifdef CONFIG_ARM_THUMBEE #ifdef CONFIG_ARM_THUMBEE
DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state)); DEFINE(TI_THUMBEE_STATE, offsetof(struct thread_info, thumbee_state));
#endif #endif
......
This diff is collapsed.
...@@ -121,15 +121,13 @@ ...@@ -121,15 +121,13 @@
.endm .endm
#else /* CONFIG_THUMB2_KERNEL */ #else /* CONFIG_THUMB2_KERNEL */
.macro svc_exit, rpsr .macro svc_exit, rpsr
ldr lr, [sp, #S_SP] @ top of the stack
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
clrex @ clear the exclusive monitor clrex @ clear the exclusive monitor
ldr r0, [sp, #S_SP] @ top of the stack stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context
ldr r1, [sp, #S_PC] @ return address
tst r0, #4 @ orig stack 8-byte aligned?
stmdb r0, {r1, \rpsr} @ rfe context
ldmia sp, {r0 - r12} ldmia sp, {r0 - r12}
ldr lr, [sp, #S_LR] mov sp, lr
addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned ldr lr, [sp], #4
addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned
rfeia sp! rfeia sp!
.endm .endm
...@@ -165,25 +163,6 @@ ...@@ -165,25 +163,6 @@
.endm .endm
#endif /* !CONFIG_THUMB2_KERNEL */ #endif /* !CONFIG_THUMB2_KERNEL */
@
@ Debug exceptions are taken as prefetch or data aborts.
@ We must disable preemption during the handler so that
@ we can access the debug registers safely.
@
.macro debug_entry, fsr
#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT)
ldr r4, =0x40f @ mask out fsr.fs
and r5, r4, \fsr
cmp r5, #2 @ debug exception
bne 1f
get_thread_info r10
ldr r6, [r10, #TI_PREEMPT] @ get preempt count
add r11, r6, #1 @ increment it
str r11, [r10, #TI_PREEMPT]
1:
#endif
.endm
/* /*
* These are the registers used in the syscall handler, and allow us to * These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6. * have in theory up to 7 arguments to a function - r0 to r6.
......
...@@ -32,8 +32,16 @@ ...@@ -32,8 +32,16 @@
* numbers for r1. * numbers for r1.
* *
*/ */
.arm
__HEAD __HEAD
ENTRY(stext) ENTRY(stext)
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled @ and irqs disabled
#ifndef CONFIG_CPU_CP15 #ifndef CONFIG_CPU_CP15
......
...@@ -71,8 +71,16 @@ ...@@ -71,8 +71,16 @@
* crap here - that's what the boot loader (or in extreme, well justified * crap here - that's what the boot loader (or in extreme, well justified
* circumstances, zImage) is for. * circumstances, zImage) is for.
*/ */
.arm
__HEAD __HEAD
ENTRY(stext) ENTRY(stext)
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
@ and irqs disabled @ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id mrc p15, 0, r9, c0, c0 @ get processor id
......
...@@ -796,7 +796,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) ...@@ -796,7 +796,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
/* /*
* Called from either the Data Abort Handler [watchpoint] or the * Called from either the Data Abort Handler [watchpoint] or the
* Prefetch Abort Handler [breakpoint] with preemption disabled. * Prefetch Abort Handler [breakpoint] with interrupts disabled.
*/ */
static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
struct pt_regs *regs) struct pt_regs *regs)
...@@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ...@@ -804,8 +804,10 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
int ret = 0; int ret = 0;
u32 dscr; u32 dscr;
/* We must be called with preemption disabled. */ preempt_disable();
WARN_ON(preemptible());
if (interrupts_enabled(regs))
local_irq_enable();
/* We only handle watchpoints and hardware breakpoints. */ /* We only handle watchpoints and hardware breakpoints. */
ARM_DBG_READ(c1, 0, dscr); ARM_DBG_READ(c1, 0, dscr);
...@@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, ...@@ -824,10 +826,6 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
ret = 1; /* Unhandled fault. */ ret = 1; /* Unhandled fault. */
} }
/*
* Re-enable preemption after it was disabled in the
* low-level exception handling code.
*/
preempt_enable(); preempt_enable();
return ret; return ret;
......
...@@ -131,54 +131,63 @@ int __init arch_probe_nr_irqs(void) ...@@ -131,54 +131,63 @@ int __init arch_probe_nr_irqs(void)
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static bool migrate_one_irq(struct irq_data *d) static bool migrate_one_irq(struct irq_desc *desc)
{ {
unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); struct irq_data *d = irq_desc_get_irq_data(desc);
const struct cpumask *affinity = d->affinity;
struct irq_chip *c;
bool ret = false; bool ret = false;
if (cpu >= nr_cpu_ids) { /*
cpu = cpumask_any(cpu_online_mask); * If this is a per-CPU interrupt, or the affinity does not
* include this CPU, then we have nothing to do.
*/
if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
return false;
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
affinity = cpu_online_mask;
ret = true; ret = true;
} }
pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); c = irq_data_get_irq_chip(d);
if (c->irq_set_affinity)
d->chip->irq_set_affinity(d, cpumask_of(cpu), true); c->irq_set_affinity(d, affinity, true);
else
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
return ret; return ret;
} }
/* /*
* The CPU has been marked offline. Migrate IRQs off this CPU. If * The current CPU has been marked offline. Migrate IRQs off this CPU.
* the affinity settings do not allow other CPUs, force them onto any * If the affinity settings do not allow other CPUs, force them onto any
* available CPU. * available CPU.
*
* Note: we must iterate over all IRQs, whether they have an attached
* action structure or not, as we need to get chained interrupts too.
*/ */
void migrate_irqs(void) void migrate_irqs(void)
{ {
unsigned int i, cpu = smp_processor_id(); unsigned int i;
struct irq_desc *desc; struct irq_desc *desc;
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
struct irq_data *d = &desc->irq_data;
bool affinity_broken = false; bool affinity_broken = false;
raw_spin_lock(&desc->lock); if (!desc)
do { continue;
if (desc->action == NULL)
break;
if (d->node != cpu)
break;
affinity_broken = migrate_one_irq(d); raw_spin_lock(&desc->lock);
} while (0); affinity_broken = migrate_one_irq(desc);
raw_spin_unlock(&desc->lock); raw_spin_unlock(&desc->lock);
if (affinity_broken && printk_ratelimit()) if (affinity_broken && printk_ratelimit())
pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); pr_warning("IRQ%u no longer affine to CPU%u\n", i,
smp_processor_id());
} }
local_irq_restore(flags); local_irq_restore(flags);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -435,7 +435,7 @@ armpmu_reserve_hardware(void) ...@@ -435,7 +435,7 @@ armpmu_reserve_hardware(void)
if (irq >= 0) if (irq >= 0)
free_irq(irq, NULL); free_irq(irq, NULL);
} }
release_pmu(pmu_device); release_pmu(ARM_PMU_DEVICE_CPU);
pmu_device = NULL; pmu_device = NULL;
} }
...@@ -454,7 +454,7 @@ armpmu_release_hardware(void) ...@@ -454,7 +454,7 @@ armpmu_release_hardware(void)
} }
armpmu->stop(); armpmu->stop();
release_pmu(pmu_device); release_pmu(ARM_PMU_DEVICE_CPU);
pmu_device = NULL; pmu_device = NULL;
} }
...@@ -662,6 +662,12 @@ init_hw_perf_events(void) ...@@ -662,6 +662,12 @@ init_hw_perf_events(void)
case 0xC090: /* Cortex-A9 */ case 0xC090: /* Cortex-A9 */
armpmu = armv7_a9_pmu_init(); armpmu = armv7_a9_pmu_init();
break; break;
case 0xC050: /* Cortex-A5 */
armpmu = armv7_a5_pmu_init();
break;
case 0xC0F0: /* Cortex-A15 */
armpmu = armv7_a15_pmu_init();
break;
} }
/* Intel CPUs [xscale]. */ /* Intel CPUs [xscale]. */
} else if (0x69 == implementor) { } else if (0x69 == implementor) {
......
This diff is collapsed.
This diff is collapsed.
...@@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = { ...@@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = {
.fn = break_trap, .fn = break_trap,
}; };
static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr)
{
unsigned int instr2;
void __user *pc;
/* Check the second half of the instruction. */
pc = (void __user *)(instruction_pointer(regs) + 2);
if (processor_mode(regs) == SVC_MODE) {
instr2 = *(u16 *) pc;
} else {
get_user(instr2, (u16 __user *)pc);
}
if (instr2 == 0xa000) {
ptrace_break(current, regs);
return 0;
} else {
return 1;
}
}
static struct undef_hook thumb2_break_hook = { static struct undef_hook thumb2_break_hook = {
.instr_mask = 0xffff, .instr_mask = 0xffffffff,
.instr_val = 0xf7f0, .instr_val = 0xf7f0a000,
.cpsr_mask = PSR_T_BIT, .cpsr_mask = PSR_T_BIT,
.cpsr_val = PSR_T_BIT, .cpsr_val = PSR_T_BIT,
.fn = thumb2_break_trap, .fn = break_trap,
}; };
static int __init ptrace_break_init(void) static int __init ptrace_break_init(void)
......
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.
...@@ -80,7 +80,3 @@ ...@@ -80,7 +80,3 @@
.macro arch_ret_to_user, tmp1, tmp2 .macro arch_ret_to_user, tmp1, tmp2
.endm .endm
.macro irq_prio_table
.endm
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.
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.
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