Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 48983
b: refs/heads/master
c: 4ba9dcb
h: refs/heads/master
i:
  48981: e11cdaa
  48979: c8c8c3a
  48975: 4cba0ba
v: v3
  • Loading branch information
Russell King authored and Russell King committed Feb 15, 2007
1 parent 140d384 commit b39fadb
Show file tree
Hide file tree
Showing 16 changed files with 339 additions and 67 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4b17244c133689ad0cbdca37ce3e15068f120428
refs/heads/master: 4ba9dcbeba042b7a1a1366f0dc683a2947ca5577
21 changes: 14 additions & 7 deletions trunk/arch/arm/common/dmabounce.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,14 @@ map_single(struct device *dev, void *ptr, size_t size,
ptr = buf->safe;

dma_addr = buf->safe_dma_addr;
} else {
/*
* We don't need to sync the DMA buffer since
* it was allocated via the coherent allocators.
*/
consistent_sync(ptr, size, dir);
}

consistent_sync(ptr, size, dir);

return dma_addr;
}

Expand Down Expand Up @@ -317,12 +321,12 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
DO_STATS ( device_info->bounce_count++ );

if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
unsigned long ptr;
void *ptr = buf->ptr;

dev_dbg(dev,
"%s: copy back safe %p to unsafe %p size %d\n",
__func__, buf->safe, buf->ptr, size);
memcpy(buf->ptr, buf->safe, size);
__func__, buf->safe, ptr, size);
memcpy(ptr, buf->safe, size);

/*
* DMA buffers must have the same cache properties
Expand All @@ -332,8 +336,8 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
* bidirectional case because we know the cache
* lines will be coherent with the data written.
*/
ptr = (unsigned long)buf->ptr;
dmac_clean_range(ptr, ptr + size);
outer_clean_range(__pa(ptr), __pa(ptr) + size);
}
free_safe_buffer(device_info, buf);
}
Expand Down Expand Up @@ -397,7 +401,10 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
default:
BUG();
}
consistent_sync(buf->safe, size, dir);
/*
* No need to sync the safe buffer - it was allocated
* via the coherent allocators.
*/
} else {
consistent_sync(dma_to_virt(dev, dma_addr), size, dir);
}
Expand Down
3 changes: 3 additions & 0 deletions trunk/arch/arm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ struct cpu_user_fns cpu_user;
#ifdef MULTI_CACHE
struct cpu_cache_fns cpu_cache;
#endif
#ifdef CONFIG_OUTER_CACHE
struct outer_cache_fns outer_cache;
#endif

struct stack {
u32 irq[3];
Expand Down
7 changes: 7 additions & 0 deletions trunk/arch/arm/mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -609,3 +609,10 @@ config NEEDS_SYSCALL_FOR_CMPXCHG
Forget about fast user space cmpxchg support.
It is just not possible.

config OUTER_CACHE
bool
default n

config CACHE_L2X0
bool
select OUTER_CACHE
2 changes: 2 additions & 0 deletions trunk/arch/arm/mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@ obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_V6) += proc-v6.o

obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
104 changes: 104 additions & 0 deletions trunk/arch/arm/mm/cache-l2x0.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
*
* Copyright (C) 2007 ARM Limited
*
* 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 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/init.h>

#include <asm/cacheflush.h>
#include <asm/io.h>
#include <asm/hardware/cache-l2x0.h>

#define CACHE_LINE_SIZE 32

static void __iomem *l2x0_base;

static inline void sync_writel(unsigned long val, unsigned long reg,
unsigned long complete_mask)
{
writel(val, l2x0_base + reg);
/* wait for the operation to complete */
while (readl(l2x0_base + reg) & complete_mask)
;
}

static inline void cache_sync(void)
{
sync_writel(0, L2X0_CACHE_SYNC, 1);
}

static inline void l2x0_inv_all(void)
{
/* invalidate all ways */
sync_writel(0xff, L2X0_INV_WAY, 0xff);
cache_sync();
}

static void l2x0_inv_range(unsigned long start, unsigned long end)
{
unsigned long addr;

start &= ~(CACHE_LINE_SIZE - 1);
for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
sync_writel(addr, L2X0_INV_LINE_PA, 1);
cache_sync();
}

static void l2x0_clean_range(unsigned long start, unsigned long end)
{
unsigned long addr;

start &= ~(CACHE_LINE_SIZE - 1);
for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
sync_writel(addr, L2X0_CLEAN_LINE_PA, 1);
cache_sync();
}

static void l2x0_flush_range(unsigned long start, unsigned long end)
{
unsigned long addr;

start &= ~(CACHE_LINE_SIZE - 1);
for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1);
cache_sync();
}

void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux;

l2x0_base = base;

/* disable L2X0 */
writel(0, l2x0_base + L2X0_CTRL);

aux = readl(l2x0_base + L2X0_AUX_CTRL);
aux &= aux_mask;
aux |= aux_val;
writel(aux, l2x0_base + L2X0_AUX_CTRL);

l2x0_inv_all();

/* enable L2X0 */
writel(1, l2x0_base + L2X0_CTRL);

outer_cache.inv_range = l2x0_inv_range;
outer_cache.clean_range = l2x0_clean_range;
outer_cache.flush_range = l2x0_flush_range;

printk(KERN_INFO "L2X0 cache controller enabled\n");
}
17 changes: 11 additions & 6 deletions trunk/arch/arm/mm/consistent.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,10 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
* kernel direct-mapped region for device DMA.
*/
{
unsigned long kaddr = (unsigned long)page_address(page);
memset(page_address(page), 0, size);
dmac_flush_range(kaddr, kaddr + size);
void *ptr = page_address(page);
memset(ptr, 0, size);
dmac_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
}

/*
Expand Down Expand Up @@ -480,20 +481,24 @@ core_initcall(consistent_init);
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
void consistent_sync(void *vaddr, size_t size, int direction)
void consistent_sync(const void *start, size_t size, int direction)
{
unsigned long start = (unsigned long)vaddr;
unsigned long end = start + size;
const void *end = start + size;

BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1));

switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
dmac_inv_range(start, end);
outer_inv_range(__pa(start), __pa(end));
break;
case DMA_TO_DEVICE: /* writeback only */
dmac_clean_range(start, end);
outer_clean_range(__pa(start), __pa(end));
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
dmac_flush_range(start, end);
outer_flush_range(__pa(start), __pa(end));
break;
default:
BUG();
Expand Down
12 changes: 10 additions & 2 deletions trunk/arch/arm/mm/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ unsigned int cpu_last_asid = { 1 << ASID_BITS };
/*
* We fork()ed a process, and we need a new context for the child
* to run in. We reserve version 0 for initial tasks so we will
* always allocate an ASID.
* always allocate an ASID. The ASID 0 is reserved for the TTBR
* register changing sequence.
*/
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
Expand All @@ -38,8 +39,15 @@ void __new_context(struct mm_struct *mm)
* If we've used up all our ASIDs, we need
* to start a new version and flush the TLB.
*/
if ((asid & ~ASID_MASK) == 0)
if ((asid & ~ASID_MASK) == 0) {
asid = ++cpu_last_asid;
/* set the reserved ASID before flushing the TLB */
asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
:
: "r" (0));
isb();
flush_tlb_all();
}

mm->context.id = asid;
}
14 changes: 8 additions & 6 deletions trunk/arch/arm/mm/proc-v6.S
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
#define TTB_RGN_WT (2 << 3)
#define TTB_RGN_WB (3 << 3)

#ifndef CONFIG_SMP
#define TTB_FLAGS TTB_RGN_WBWA
#else
#define TTB_FLAGS TTB_RGN_WBWA|TTB_S
#endif

ENTRY(cpu_v6_proc_init)
mov pc, lr

Expand Down Expand Up @@ -95,9 +101,7 @@ ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
#ifdef CONFIG_SMP
orr r0, r0, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
#endif
orr r0, r0, #TTB_FLAGS
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
Expand Down Expand Up @@ -206,9 +210,7 @@ __v6_setup:
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register
#ifdef CONFIG_SMP
orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
#endif
orr r4, r4, #TTB_FLAGS
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
adr r5, v6_crval
Expand Down
4 changes: 4 additions & 0 deletions trunk/arch/arm/mm/tlb-v6.S
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ ENTRY(v6wbi_flush_user_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier
mov pc, lr

/*
Expand Down Expand Up @@ -80,7 +82,9 @@ ENTRY(v6wbi_flush_kern_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier
mcr p15, 0, r2, c7, c5, 4 @ prefetch flush
mov pc, lr

.section ".text.init", #alloc, #execinstr
Expand Down
49 changes: 43 additions & 6 deletions trunk/include/asm-arm/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,15 @@ struct cpu_cache_fns {
void (*coherent_user_range)(unsigned long, unsigned long);
void (*flush_kern_dcache_page)(void *);

void (*dma_inv_range)(unsigned long, unsigned long);
void (*dma_clean_range)(unsigned long, unsigned long);
void (*dma_flush_range)(unsigned long, unsigned long);
void (*dma_inv_range)(const void *, const void *);
void (*dma_clean_range)(const void *, const void *);
void (*dma_flush_range)(const void *, const void *);
};

struct outer_cache_fns {
void (*inv_range)(unsigned long, unsigned long);
void (*clean_range)(unsigned long, unsigned long);
void (*flush_range)(unsigned long, unsigned long);
};

/*
Expand Down Expand Up @@ -240,9 +246,40 @@ extern void __cpuc_flush_dcache_page(void *);
#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)

extern void dmac_inv_range(unsigned long, unsigned long);
extern void dmac_clean_range(unsigned long, unsigned long);
extern void dmac_flush_range(unsigned long, unsigned long);
extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);

#endif

#ifdef CONFIG_OUTER_CACHE

extern struct outer_cache_fns outer_cache;

static inline void outer_inv_range(unsigned long start, unsigned long end)
{
if (outer_cache.inv_range)
outer_cache.inv_range(start, end);
}
static inline void outer_clean_range(unsigned long start, unsigned long end)
{
if (outer_cache.clean_range)
outer_cache.clean_range(start, end);
}
static inline void outer_flush_range(unsigned long start, unsigned long end)
{
if (outer_cache.flush_range)
outer_cache.flush_range(start, end);
}

#else

static inline void outer_inv_range(unsigned long start, unsigned long end)
{ }
static inline void outer_clean_range(unsigned long start, unsigned long end)
{ }
static inline void outer_flush_range(unsigned long start, unsigned long end)
{ }

#endif

Expand Down
2 changes: 1 addition & 1 deletion trunk/include/asm-arm/dma-mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
extern void consistent_sync(void *kaddr, size_t size, int rw);
extern void consistent_sync(const void *kaddr, size_t size, int rw);

/*
* Return whether the given device DMA address mask can be supported
Expand Down
1 change: 1 addition & 0 deletions trunk/include/asm-arm/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
__asm__ __volatile__( \
"mcr p15, 0, %0, c3, c0 @ set domain" \
: : "r" (x)); \
isb(); \
} while (0)

#define modify_domain(dom,type) \
Expand Down
Loading

0 comments on commit b39fadb

Please sign in to comment.