aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-10-13 09:43:54 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-10-13 09:43:54 -0400
commitb160292cc216a50fd0cd386b0bda2cd48352c73b (patch)
treeef07cf98f91353ee4c9ec1e1ca7a2a5d9d4b538a /arch/xtensa
parentb37bde147890c8fea8369a5a4e230dabdea4ebfb (diff)
parentbbf25010f1a6b761914430f5fca081ec8c7accd1 (diff)
Merge Linux 2.6.23
Diffstat (limited to 'arch/xtensa')
-rw-r--r--arch/xtensa/Makefile7
-rw-r--r--arch/xtensa/kernel/Makefile2
-rw-r--r--arch/xtensa/kernel/asm-offsets.c13
-rw-r--r--arch/xtensa/kernel/entry.S115
-rw-r--r--arch/xtensa/kernel/init_task.c38
-rw-r--r--arch/xtensa/kernel/io.c75
-rw-r--r--arch/xtensa/kernel/module.c195
-rw-r--r--arch/xtensa/kernel/pci.c69
-rw-r--r--arch/xtensa/kernel/process.c15
-rw-r--r--arch/xtensa/kernel/semaphore.c2
-rw-r--r--arch/xtensa/kernel/syscall.c5
-rw-r--r--arch/xtensa/kernel/time.c46
-rw-r--r--arch/xtensa/kernel/traps.c4
-rw-r--r--arch/xtensa/mm/Makefile6
-rw-r--r--arch/xtensa/mm/cache.c256
-rw-r--r--arch/xtensa/mm/fault.c6
-rw-r--r--arch/xtensa/mm/init.c252
-rw-r--r--arch/xtensa/mm/misc.S306
-rw-r--r--arch/xtensa/platform-iss/console.c1
19 files changed, 986 insertions, 427 deletions
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 95f836db38fa..acf05be24929 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -27,7 +27,12 @@ platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
27PLATFORM = $(platform-y) 27PLATFORM = $(platform-y)
28export PLATFORM 28export PLATFORM
29 29
30CFLAGS += -pipe -mlongcalls 30# temporarily until string.h is fixed
31cflags-y += -ffreestanding
32
33cflags-y += -pipe -mlongcalls
34
35CFLAGS += $(cflags-y)
31 36
32KBUILD_DEFCONFIG := iss_defconfig 37KBUILD_DEFCONFIG := iss_defconfig
33 38
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 71f733c4f66d..f582d6a24ec2 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds
7 7
8obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \ 8obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \
9 setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \ 9 setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \
10 pci-dma.o 10 pci-dma.o init_task.o io.o
11 11
12## windowspill.o 12## windowspill.o
13 13
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index d0323cd6a2ea..d5ffe7b6443e 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -18,12 +18,13 @@
18#include <linux/stddef.h> 18#include <linux/stddef.h>
19#include <linux/thread_info.h> 19#include <linux/thread_info.h>
20#include <linux/ptrace.h> 20#include <linux/ptrace.h>
21#include <linux/mm.h>
22
21#include <asm/ptrace.h> 23#include <asm/ptrace.h>
22#include <asm/processor.h> 24#include <asm/processor.h>
23#include <asm/uaccess.h> 25#include <asm/uaccess.h>
24 26
25#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 27#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
26#define BLANK() asm volatile("\n->" : : )
27 28
28int main(void) 29int main(void)
29{ 30{
@@ -63,7 +64,6 @@ int main(void)
63 DEFINE(PT_SIZE, sizeof(struct pt_regs)); 64 DEFINE(PT_SIZE, sizeof(struct pt_regs));
64 DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS])); 65 DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
65 DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS])); 66 DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
66 BLANK();
67 67
68 /* struct task_struct */ 68 /* struct task_struct */
69 DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace)); 69 DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
@@ -73,27 +73,26 @@ int main(void)
73 DEFINE(TASK_THREAD, offsetof (struct task_struct, thread)); 73 DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
74 DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack)); 74 DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
75 DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct)); 75 DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
76 BLANK();
77 76
78 /* struct thread_info (offset from start_struct) */ 77 /* struct thread_info (offset from start_struct) */
79 DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra)); 78 DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
80 DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp)); 79 DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
81 DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save)); 80 DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
82 DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds)); 81 DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
83 BLANK();
84 82
85 /* struct mm_struct */ 83 /* struct mm_struct */
86 DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users)); 84 DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
87 DEFINE(MM_PGD, offsetof (struct mm_struct, pgd)); 85 DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
88 DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context)); 86 DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
89 BLANK(); 87
90 DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT); 88 /* struct page */
89 DEFINE(PAGE_FLAGS, offsetof(struct page, flags));
91 90
92 /* constants */ 91 /* constants */
93 DEFINE(_CLONE_VM, CLONE_VM); 92 DEFINE(_CLONE_VM, CLONE_VM);
94 DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED); 93 DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
94 DEFINE(PG_ARCH_1, PG_arch_1);
95 95
96 return 0; 96 return 0;
97} 97}
98 98
99
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 8dc7a2c26ff9..91a689eca43d 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -7,7 +7,7 @@
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 * 9 *
10 * Copyright (C) 2004-2005 by Tensilica Inc. 10 * Copyright (C) 2004-2007 by Tensilica Inc.
11 * 11 *
12 * Chris Zankel <chris@zankel.net> 12 * Chris Zankel <chris@zankel.net>
13 * 13 *
@@ -169,7 +169,7 @@ _user_exception:
169 * We have to save all registers up to the first '1' from 169 * We have to save all registers up to the first '1' from
170 * the right, except the current frame (bit 0). 170 * the right, except the current frame (bit 0).
171 * Assume a2 is: 001001000110001 171 * Assume a2 is: 001001000110001
172 * All regiser frames starting from the top fiel to the marked '1' 172 * All register frames starting from the top field to the marked '1'
173 * must be saved. 173 * must be saved.
174 */ 174 */
175 175
@@ -1572,10 +1572,12 @@ ENTRY(fast_second_level_miss)
1572 l32i a0, a1, TASK_MM # tsk->mm 1572 l32i a0, a1, TASK_MM # tsk->mm
1573 beqz a0, 9f 1573 beqz a0, 9f
1574 1574
15758: rsr a1, EXCVADDR # fault address 1575
1576 _PGD_OFFSET(a0, a1, a1) 1576 /* We deliberately destroy a3 that holds the exception table. */
1577
15788: rsr a3, EXCVADDR # fault address
1579 _PGD_OFFSET(a0, a3, a1)
1577 l32i a0, a0, 0 # read pmdval 1580 l32i a0, a0, 0 # read pmdval
1578 //beqi a0, _PAGE_USER, 2f
1579 beqz a0, 2f 1581 beqz a0, 2f
1580 1582
1581 /* Read ptevaddr and convert to top of page-table page. 1583 /* Read ptevaddr and convert to top of page-table page.
@@ -1588,7 +1590,7 @@ ENTRY(fast_second_level_miss)
1588 * The messy computation for 'pteval' above really simplifies 1590 * The messy computation for 'pteval' above really simplifies
1589 * into the following: 1591 * into the following:
1590 * 1592 *
1591 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL 1593 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY
1592 */ 1594 */
1593 1595
1594 movi a1, -PAGE_OFFSET 1596 movi a1, -PAGE_OFFSET
@@ -1596,20 +1598,34 @@ ENTRY(fast_second_level_miss)
1596 extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK 1598 extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK
1597 xor a0, a0, a1 1599 xor a0, a0, a1
1598 1600
1599 1601 movi a1, _PAGE_DIRECTORY
1600 movi a1, PAGE_DIRECTORY
1601 or a0, a0, a1 # ... | PAGE_DIRECTORY 1602 or a0, a0, a1 # ... | PAGE_DIRECTORY
1602 1603
1604 /*
1605 * We utilize all three wired-ways (7-9) to hold pmd translations.
1606 * Memory regions are mapped to the DTLBs according to bits 28 and 29.
1607 * This allows to map the three most common regions to three different
1608 * DTLBs:
1609 * 0,1 -> way 7 program (0040.0000) and virtual (c000.0000)
1610 * 2 -> way 8 shared libaries (2000.0000)
1611 * 3 -> way 0 stack (3000.0000)
1612 */
1613
1614 extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,3
1603 rsr a1, PTEVADDR 1615 rsr a1, PTEVADDR
1616 addx2 a3, a3, a3 # -> 0,3,6,9
1604 srli a1, a1, PAGE_SHIFT 1617 srli a1, a1, PAGE_SHIFT
1618 extui a3, a3, 2, 2 # -> 0,0,1,2
1605 slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK 1619 slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK
1606 addi a1, a1, DTLB_WAY_PGD # ... + way_number 1620 addi a3, a3, DTLB_WAY_PGD
1621 add a1, a1, a3 # ... + way_number
1607 1622
1608 wdtlb a0, a1 16233: wdtlb a0, a1
1609 dsync 1624 dsync
1610 1625
1611 /* Exit critical section. */ 1626 /* Exit critical section. */
1612 1627
16284: movi a3, exc_table # restore a3
1613 movi a0, 0 1629 movi a0, 0
1614 s32i a0, a3, EXC_TABLE_FIXUP 1630 s32i a0, a3, EXC_TABLE_FIXUP
1615 1631
@@ -1636,8 +1652,76 @@ ENTRY(fast_second_level_miss)
16369: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 16529: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
1637 j 8b 1653 j 8b
1638 1654
1655#if (DCACHE_WAY_SIZE > PAGE_SIZE)
1656
16572: /* Special case for cache aliasing.
1658 * We (should) only get here if a clear_user_page, copy_user_page
1659 * or the aliased cache flush functions got preemptively interrupted
1660 * by another task. Re-establish temporary mapping to the
1661 * TLBTEMP_BASE areas.
1662 */
1663
1664 /* We shouldn't be in a double exception */
1665
1666 l32i a0, a2, PT_DEPC
1667 bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f
1668
1669 /* Make sure the exception originated in the special functions */
1670
1671 movi a0, __tlbtemp_mapping_start
1672 rsr a3, EPC_1
1673 bltu a3, a0, 2f
1674 movi a0, __tlbtemp_mapping_end
1675 bgeu a3, a0, 2f
1676
1677 /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */
1678
1679 movi a3, TLBTEMP_BASE_1
1680 rsr a0, EXCVADDR
1681 bltu a0, a3, 2f
1682
1683 addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
1684 bgeu a1, a3, 2f
1685
1686 /* Check if we have to restore an ITLB mapping. */
1687
1688 movi a1, __tlbtemp_mapping_itlb
1689 rsr a3, EPC_1
1690 sub a3, a3, a1
1691
1692 /* Calculate VPN */
1693
1694 movi a1, PAGE_MASK
1695 and a1, a1, a0
1696
1697 /* Jump for ITLB entry */
1698
1699 bgez a3, 1f
1700
1701 /* We can use up to two TLBTEMP areas, one for src and one for dst. */
1702
1703 extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1
1704 add a1, a3, a1
1705
1706 /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */
1707
1708 mov a0, a6
1709 movnez a0, a7, a3
1710 j 3b
1711
1712 /* ITLB entry. We only use dst in a6. */
1713
17141: witlb a6, a1
1715 isync
1716 j 4b
1717
1718
1719#endif // DCACHE_WAY_SIZE > PAGE_SIZE
1720
1721
16392: /* Invalid PGD, default exception handling */ 17222: /* Invalid PGD, default exception handling */
1640 1723
1724 movi a3, exc_table
1641 rsr a1, DEPC 1725 rsr a1, DEPC
1642 xsr a3, EXCSAVE_1 1726 xsr a3, EXCSAVE_1
1643 s32i a1, a2, PT_AREG2 1727 s32i a1, a2, PT_AREG2
@@ -1682,15 +1766,15 @@ ENTRY(fast_store_prohibited)
16828: rsr a1, EXCVADDR # fault address 17668: rsr a1, EXCVADDR # fault address
1683 _PGD_OFFSET(a0, a1, a4) 1767 _PGD_OFFSET(a0, a1, a4)
1684 l32i a0, a0, 0 1768 l32i a0, a0, 0
1685 //beqi a0, _PAGE_USER, 2f # FIXME use _PAGE_INVALID
1686 beqz a0, 2f 1769 beqz a0, 2f
1687 1770
1771 /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/
1772
1688 _PTE_OFFSET(a0, a1, a4) 1773 _PTE_OFFSET(a0, a1, a4)
1689 l32i a4, a0, 0 # read pteval 1774 l32i a4, a0, 0 # read pteval
1690 movi a1, _PAGE_VALID | _PAGE_RW 1775 bbci.l a4, _PAGE_WRITABLE_BIT, 2f
1691 bnall a4, a1, 2f
1692 1776
1693 movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE 1777 movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
1694 or a4, a4, a1 1778 or a4, a4, a1
1695 rsr a1, EXCVADDR 1779 rsr a1, EXCVADDR
1696 s32i a4, a0, 0 1780 s32i a4, a0, 0
@@ -1700,10 +1784,7 @@ ENTRY(fast_store_prohibited)
1700 dhwb a0, 0 1784 dhwb a0, 0
1701#endif 1785#endif
1702 pdtlb a0, a1 1786 pdtlb a0, a1
1703 beqz a0, 1f
1704 idtlb a0 // FIXME do we need this?
1705 wdtlb a4, a0 1787 wdtlb a4, a0
17061:
1707 1788
1708 /* Exit critical section. */ 1789 /* Exit critical section. */
1709 1790
diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c
new file mode 100644
index 000000000000..021b4f46ff94
--- /dev/null
+++ b/arch/xtensa/kernel/init_task.c
@@ -0,0 +1,38 @@
1/*
2 * arch/xtensa/kernel/init_task.c
3 *
4 * Xtensa Processor version.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 *
10 * Copyright (C) 2007 Tensilica Inc.
11 *
12 * Chris Zankel <chris@zankel.net>
13 */
14
15#include <linux/mm.h>
16#include <linux/fs.h>
17#include <linux/init.h>
18#include <linux/init_task.h>
19#include <linux/module.h>
20#include <linux/mqueue.h>
21
22#include <asm/uaccess.h>
23
24static struct fs_struct init_fs = INIT_FS;
25static struct files_struct init_files = INIT_FILES;
26static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
27static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
28struct mm_struct init_mm = INIT_MM(init_mm);
29
30EXPORT_SYMBOL(init_mm);
31
32union thread_union init_thread_union
33 __attribute__((__section__(".data.init_task"))) =
34{ INIT_THREAD_INFO(init_task) };
35
36struct task_struct init_task = INIT_TASK(init_task);
37
38EXPORT_SYMBOL(init_task);
diff --git a/arch/xtensa/kernel/io.c b/arch/xtensa/kernel/io.c
new file mode 100644
index 000000000000..5b65269b1d2f
--- /dev/null
+++ b/arch/xtensa/kernel/io.c
@@ -0,0 +1,75 @@
1/*
2 * arch/xtensa/io.c
3 *
4 * IO primitives
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 * Copied from sparc.
12 *
13 * Chris Zankel <chris@zankel.net>
14 *
15 */
16
17#include <asm/io.h>
18#include <asm/byteorder.h>
19
20void outsb(unsigned long addr, const void *src, unsigned long count) {
21 while (count) {
22 count -= 1;
23 writeb(*(const char *)src, addr);
24 src += 1;
25 addr += 1;
26 }
27}
28
29void outsw(unsigned long addr, const void *src, unsigned long count) {
30 while (count) {
31 count -= 2;
32 writew(*(const short *)src, addr);
33 src += 2;
34 addr += 2;
35 }
36}
37
38void outsl(unsigned long addr, const void *src, unsigned long count) {
39 while (count) {
40 count -= 4;
41 writel(*(const long *)src, addr);
42 src += 4;
43 addr += 4;
44 }
45}
46
47void insb(unsigned long addr, void *dst, unsigned long count) {
48 while (count) {
49 count -= 1;
50 *(unsigned char *)dst = readb(addr);
51 dst += 1;
52 addr += 1;
53 }
54}
55
56void insw(unsigned long addr, void *dst, unsigned long count) {
57 while (count) {
58 count -= 2;
59 *(unsigned short *)dst = readw(addr);
60 dst += 2;
61 addr += 2;
62 }
63}
64
65void insl(unsigned long addr, void *dst, unsigned long count) {
66 while (count) {
67 count -= 4;
68 /*
69 * XXX I am sure we are in for an unaligned trap here.
70 */
71 *(unsigned long *)dst = readl(addr);
72 dst += 4;
73 addr += 4;
74 }
75}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
index 2ea1755a0858..ddf14dcf2ad9 100644
--- a/arch/xtensa/kernel/module.c
+++ b/arch/xtensa/kernel/module.c
@@ -7,7 +7,7 @@
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 * 9 *
10 * Copyright (C) 2001 - 2005 Tensilica Inc. 10 * Copyright (C) 2001 - 2006 Tensilica Inc.
11 * 11 *
12 * Chris Zankel <chris@zankel.net> 12 * Chris Zankel <chris@zankel.net>
13 * 13 *
@@ -22,57 +22,216 @@
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/cache.h> 23#include <linux/cache.h>
24 24
25LIST_HEAD(module_buf_list); 25#undef DEBUG_RELOCATE
26 26
27void *module_alloc(unsigned long size) 27void *module_alloc(unsigned long size)
28{ 28{
29 panic("module_alloc not implemented"); 29 if (size == 0)
30 return NULL;
31 return vmalloc(size);
30} 32}
31 33
32void module_free(struct module *mod, void *module_region) 34void module_free(struct module *mod, void *module_region)
33{ 35{
34 panic("module_free not implemented"); 36 vfree(module_region);
37 /* FIXME: If module_region == mod->init_region, trim exception
38 table entries. */
35} 39}
36 40
37int module_frob_arch_sections(Elf32_Ehdr *hdr, 41int module_frob_arch_sections(Elf32_Ehdr *hdr,
38 Elf32_Shdr *sechdrs, 42 Elf32_Shdr *sechdrs,
39 char *secstrings, 43 char *secstrings,
40 struct module *me) 44 struct module *mod)
41{ 45{
42 panic("module_frob_arch_sections not implemented"); 46 return 0;
47}
48
49static int
50decode_calln_opcode (unsigned char *location)
51{
52#ifdef __XTENSA_EB__
53 return (location[0] & 0xf0) == 0x50;
54#endif
55#ifdef __XTENSA_EL__
56 return (location[0] & 0xf) == 0x5;
57#endif
58}
59
60static int
61decode_l32r_opcode (unsigned char *location)
62{
63#ifdef __XTENSA_EB__
64 return (location[0] & 0xf0) == 0x10;
65#endif
66#ifdef __XTENSA_EL__
67 return (location[0] & 0xf) == 0x1;
68#endif
43} 69}
44 70
45int apply_relocate(Elf32_Shdr *sechdrs, 71int apply_relocate(Elf32_Shdr *sechdrs,
46 const char *strtab, 72 const char *strtab,
47 unsigned int symindex, 73 unsigned int symindex,
48 unsigned int relsec, 74 unsigned int relsec,
49 struct module *module) 75 struct module *mod)
50{ 76{
51 panic ("apply_relocate not implemented"); 77 printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
78 mod->name);
79 return -ENOEXEC;
80
52} 81}
53 82
54int apply_relocate_add(Elf32_Shdr *sechdrs, 83int apply_relocate_add(Elf32_Shdr *sechdrs,
55 const char *strtab, 84 const char *strtab,
56 unsigned int symindex, 85 unsigned int symindex,
57 unsigned int relsec, 86 unsigned int relsec,
58 struct module *module) 87 struct module *mod)
59{ 88{
60 panic("apply_relocate_add not implemented"); 89 unsigned int i;
90 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
91 Elf32_Sym *sym;
92 unsigned char *location;
93 uint32_t value;
94
95#ifdef DEBUG_RELOCATE
96 printk("Applying relocate section %u to %u\n", relsec,
97 sechdrs[relsec].sh_info);
98#endif
99 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
100 location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
101 + rela[i].r_offset;
102 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
103 + ELF32_R_SYM(rela[i].r_info);
104 value = sym->st_value + rela[i].r_addend;
105
106 switch (ELF32_R_TYPE(rela[i].r_info)) {
107 case R_XTENSA_NONE:
108 case R_XTENSA_DIFF8:
109 case R_XTENSA_DIFF16:
110 case R_XTENSA_DIFF32:
111 case R_XTENSA_ASM_EXPAND:
112 break;
113
114 case R_XTENSA_32:
115 case R_XTENSA_PLT:
116 *(uint32_t *)location += value;
117 break;
118
119 case R_XTENSA_SLOT0_OP:
120 if (decode_calln_opcode(location)) {
121 value -= ((unsigned long)location & -4) + 4;
122 if ((value & 3) != 0 ||
123 ((value + (1 << 19)) >> 20) != 0) {
124 printk("%s: relocation out of range, "
125 "section %d reloc %d "
126 "sym '%s'\n",
127 mod->name, relsec, i,
128 strtab + sym->st_name);
129 return -ENOEXEC;
130 }
131 value = (signed int)value >> 2;
132#ifdef __XTENSA_EB__
133 location[0] = ((location[0] & ~0x3) |
134 ((value >> 16) & 0x3));
135 location[1] = (value >> 8) & 0xff;
136 location[2] = value & 0xff;
137#endif
138#ifdef __XTENSA_EL__
139 location[0] = ((location[0] & ~0xc0) |
140 ((value << 6) & 0xc0));
141 location[1] = (value >> 2) & 0xff;
142 location[2] = (value >> 10) & 0xff;
143#endif
144 } else if (decode_l32r_opcode(location)) {
145 value -= (((unsigned long)location + 3) & -4);
146 if ((value & 3) != 0 ||
147 (signed int)value >> 18 != -1) {
148 printk("%s: relocation out of range, "
149 "section %d reloc %d "
150 "sym '%s'\n",
151 mod->name, relsec, i,
152 strtab + sym->st_name);
153 return -ENOEXEC;
154 }
155 value = (signed int)value >> 2;
156
157#ifdef __XTENSA_EB__
158 location[1] = (value >> 8) & 0xff;
159 location[2] = value & 0xff;
160#endif
161#ifdef __XTENSA_EL__
162 location[1] = value & 0xff;
163 location[2] = (value >> 8) & 0xff;
164#endif
165 }
166 /* FIXME: Ignore any other opcodes. The Xtensa
167 assembler currently assumes that the linker will
168 always do relaxation and so all PC-relative
169 operands need relocations. (The assembler also
170 writes out the tentative PC-relative values,
171 assuming no link-time relaxation, so it is usually
172 safe to ignore the relocations.) If the
173 assembler's "--no-link-relax" flag can be made to
174 work, and if all kernel modules can be assembled
175 with that flag, then unexpected relocations could
176 be detected here. */
177 break;
178
179 case R_XTENSA_SLOT1_OP:
180 case R_XTENSA_SLOT2_OP:
181 case R_XTENSA_SLOT3_OP:
182 case R_XTENSA_SLOT4_OP:
183 case R_XTENSA_SLOT5_OP:
184 case R_XTENSA_SLOT6_OP:
185 case R_XTENSA_SLOT7_OP:
186 case R_XTENSA_SLOT8_OP:
187 case R_XTENSA_SLOT9_OP:
188 case R_XTENSA_SLOT10_OP:
189 case R_XTENSA_SLOT11_OP:
190 case R_XTENSA_SLOT12_OP:
191 case R_XTENSA_SLOT13_OP:
192 case R_XTENSA_SLOT14_OP:
193 printk("%s: unexpected FLIX relocation: %u\n",
194 mod->name,
195 ELF32_R_TYPE(rela[i].r_info));
196 return -ENOEXEC;
197
198 case R_XTENSA_SLOT0_ALT:
199 case R_XTENSA_SLOT1_ALT:
200 case R_XTENSA_SLOT2_ALT:
201 case R_XTENSA_SLOT3_ALT:
202 case R_XTENSA_SLOT4_ALT:
203 case R_XTENSA_SLOT5_ALT:
204 case R_XTENSA_SLOT6_ALT:
205 case R_XTENSA_SLOT7_ALT:
206 case R_XTENSA_SLOT8_ALT:
207 case R_XTENSA_SLOT9_ALT:
208 case R_XTENSA_SLOT10_ALT:
209 case R_XTENSA_SLOT11_ALT:
210 case R_XTENSA_SLOT12_ALT:
211 case R_XTENSA_SLOT13_ALT:
212 case R_XTENSA_SLOT14_ALT:
213 printk("%s: unexpected ALT relocation: %u\n",
214 mod->name,
215 ELF32_R_TYPE(rela[i].r_info));
216 return -ENOEXEC;
217
218 default:
219 printk("%s: unexpected relocation: %u\n",
220 mod->name,
221 ELF32_R_TYPE(rela[i].r_info));
222 return -ENOEXEC;
223 }
224 }
225 return 0;
61} 226}
62 227
63int module_finalize(const Elf_Ehdr *hdr, 228int module_finalize(const Elf_Ehdr *hdr,
64 const Elf_Shdr *sechdrs, 229 const Elf_Shdr *sechdrs,
65 struct module *me) 230 struct module *mod)
66{ 231{
67 panic ("module_finalize not implemented"); 232 return 0;
68} 233}
69 234
70void module_arch_cleanup(struct module *mod) 235void module_arch_cleanup(struct module *mod)
71{ 236{
72 panic("module_arch_cleanup not implemented");
73}
74
75struct bug_entry *module_find_bug(unsigned long bugaddr)
76{
77 panic("module_find_bug not implemented");
78} 237}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 77deae5290f0..b7c073484e01 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -394,72 +394,3 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
394 394
395 return ret; 395 return ret;
396} 396}
397
398/*
399 * This probably belongs here rather than ioport.c because
400 * we do not want this crud linked into SBus kernels.
401 * Also, think for a moment about likes of floppy.c that
402 * include architecture specific parts. They may want to redefine ins/outs.
403 *
404 * We do not use horrible macros here because we want to
405 * advance pointer by sizeof(size).
406 */
407void outsb(unsigned long addr, const void *src, unsigned long count) {
408 while (count) {
409 count -= 1;
410 writeb(*(const char *)src, addr);
411 src += 1;
412 addr += 1;
413 }
414}
415
416void outsw(unsigned long addr, const void *src, unsigned long count) {
417 while (count) {
418 count -= 2;
419 writew(*(const short *)src, addr);
420 src += 2;
421 addr += 2;
422 }
423}
424
425void outsl(unsigned long addr, const void *src, unsigned long count) {
426 while (count) {
427 count -= 4;
428 writel(*(const long *)src, addr);
429 src += 4;
430 addr += 4;
431 }
432}
433
434void insb(unsigned long addr, void *dst, unsigned long count) {
435 while (count) {
436 count -= 1;
437 *(unsigned char *)dst = readb(addr);
438 dst += 1;
439 addr += 1;
440 }
441}
442
443void insw(unsigned long addr, void *dst, unsigned long count) {
444 while (count) {
445 count -= 2;
446 *(unsigned short *)dst = readw(addr);
447 dst += 2;
448 addr += 2;
449 }
450}
451
452void insl(unsigned long addr, void *dst, unsigned long count) {
453 while (count) {
454 count -= 4;
455 /*
456 * XXX I am sure we are in for an unaligned trap here.
457 */
458 *(unsigned long *)dst = readl(addr);
459 dst += 4;
460 addr += 4;
461 }
462}
463
464
465
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index ce758bab95b1..f53d7bd9dfb2 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -30,6 +30,7 @@
30#include <linux/init_task.h> 30#include <linux/init_task.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/mqueue.h> 32#include <linux/mqueue.h>
33#include <linux/fs.h>
33 34
34#include <asm/pgtable.h> 35#include <asm/pgtable.h>
35#include <asm/uaccess.h> 36#include <asm/uaccess.h>
@@ -45,20 +46,6 @@
45 46
46extern void ret_from_fork(void); 47extern void ret_from_fork(void);
47 48
48static struct fs_struct init_fs = INIT_FS;
49static struct files_struct init_files = INIT_FILES;
50static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
51static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
52struct mm_struct init_mm = INIT_MM(init_mm);
53EXPORT_SYMBOL(init_mm);
54
55union thread_union init_thread_union
56 __attribute__((__section__(".data.init_task"))) =
57{ INIT_THREAD_INFO(init_task) };
58
59struct task_struct init_task = INIT_TASK(init_task);
60EXPORT_SYMBOL(init_task);
61
62struct task_struct *current_set[NR_CPUS] = {&init_task, }; 49struct task_struct *current_set[NR_CPUS] = {&init_task, };
63 50
64void (*pm_power_off)(void) = NULL; 51void (*pm_power_off)(void) = NULL;
diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
index d40f4b1b75ac..995c6410ae10 100644
--- a/arch/xtensa/kernel/semaphore.c
+++ b/arch/xtensa/kernel/semaphore.c
@@ -100,7 +100,7 @@ static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
100 return ret; 100 return ret;
101} 101}
102 102
103spinlock_t semaphore_wake_lock; 103DEFINE_SPINLOCK(semaphore_wake_lock);
104 104
105/* 105/*
106 * Semaphores are implemented using a two-way counter: 106 * Semaphores are implemented using a two-way counter:
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
index fe3834bc1dbf..f3e16efcd47a 100644
--- a/arch/xtensa/kernel/syscall.c
+++ b/arch/xtensa/kernel/syscall.c
@@ -93,3 +93,8 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
93 return (long)ret; 93 return (long)ret;
94} 94}
95 95
96asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len)
97{
98 return sys_fadvise64_64(fd, offset, len, advice);
99}
100
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 22949be4a5d8..60d29fe0b1bd 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -32,12 +32,20 @@ EXPORT_SYMBOL(rtc_lock);
32 32
33#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT 33#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
34unsigned long ccount_per_jiffy; /* per 1/HZ */ 34unsigned long ccount_per_jiffy; /* per 1/HZ */
35unsigned long ccount_nsec; /* nsec per ccount increment */ 35unsigned long nsec_per_ccount; /* nsec per ccount increment */
36#endif 36#endif
37 37
38unsigned int last_ccount_stamp;
39static long last_rtc_update = 0; 38static long last_rtc_update = 0;
40 39
40/*
41 * Scheduler clock - returns current tim in nanosec units.
42 */
43
44unsigned long long sched_clock(void)
45{
46 return (unsigned long long)jiffies * (1000000000 / HZ);
47}
48
41static irqreturn_t timer_interrupt(int irq, void *dev_id); 49static irqreturn_t timer_interrupt(int irq, void *dev_id);
42static struct irqaction timer_irqaction = { 50static struct irqaction timer_irqaction = {
43 .handler = timer_interrupt, 51 .handler = timer_interrupt,
@@ -69,7 +77,6 @@ void __init time_init(void)
69 77
70 xtime.tv_nsec = 0; 78 xtime.tv_nsec = 0;
71 last_rtc_update = xtime.tv_sec = sec_n; 79 last_rtc_update = xtime.tv_sec = sec_n;
72 last_ccount_stamp = get_ccount();
73 80
74 set_normalized_timespec(&wall_to_monotonic, 81 set_normalized_timespec(&wall_to_monotonic,
75 -xtime.tv_sec, -xtime.tv_nsec); 82 -xtime.tv_sec, -xtime.tv_nsec);
@@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv)
85{ 92{
86 time_t wtm_sec, sec = tv->tv_sec; 93 time_t wtm_sec, sec = tv->tv_sec;
87 long wtm_nsec, nsec = tv->tv_nsec; 94 long wtm_nsec, nsec = tv->tv_nsec;
88 unsigned long ccount; 95 unsigned long delta;
89 96
90 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) 97 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
91 return -EINVAL; 98 return -EINVAL;
@@ -97,8 +104,10 @@ int do_settimeofday(struct timespec *tv)
97 * wall time. Discover what correction gettimeofday() would have 104 * wall time. Discover what correction gettimeofday() would have
98 * made, and then undo it! 105 * made, and then undo it!
99 */ 106 */
100 ccount = get_ccount(); 107
101 nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC; 108 delta = CCOUNT_PER_JIFFY;
109 delta += get_ccount() - get_linux_timer();
110 nsec -= delta * NSEC_PER_CCOUNT;
102 111
103 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); 112 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
104 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); 113 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -117,17 +126,21 @@ EXPORT_SYMBOL(do_settimeofday);
117void do_gettimeofday(struct timeval *tv) 126void do_gettimeofday(struct timeval *tv)
118{ 127{
119 unsigned long flags; 128 unsigned long flags;
120 unsigned long sec, usec, delta, seq; 129 unsigned long volatile sec, usec, delta, seq;
121 130
122 do { 131 do {
123 seq = read_seqbegin_irqsave(&xtime_lock, flags); 132 seq = read_seqbegin_irqsave(&xtime_lock, flags);
124 133
125 delta = get_ccount() - last_ccount_stamp;
126 sec = xtime.tv_sec; 134 sec = xtime.tv_sec;
127 usec = (xtime.tv_nsec / NSEC_PER_USEC); 135 usec = (xtime.tv_nsec / NSEC_PER_USEC);
136
137 delta = get_linux_timer() - get_ccount();
138
128 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); 139 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
129 140
130 usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC; 141 usec += (((unsigned long) CCOUNT_PER_JIFFY - delta)
142 * (unsigned long) NSEC_PER_CCOUNT) / NSEC_PER_USEC;
143
131 for (; usec >= 1000000; sec++, usec -= 1000000) 144 for (; usec >= 1000000; sec++, usec -= 1000000)
132 ; 145 ;
133 146
@@ -158,9 +171,12 @@ again:
158 171
159 write_seqlock(&xtime_lock); 172 write_seqlock(&xtime_lock);
160 173
161 last_ccount_stamp = next; 174 do_timer(1); /* Linux handler in kernel/timer.c */
175
176 /* Note that writing CCOMPARE clears the interrupt. */
177
162 next += CCOUNT_PER_JIFFY; 178 next += CCOUNT_PER_JIFFY;
163 do_timer (1); /* Linux handler in kernel/timer.c */ 179 set_linux_timer(next);
164 180
165 if (ntp_synced() && 181 if (ntp_synced() &&
166 xtime.tv_sec - last_rtc_update >= 659 && 182 xtime.tv_sec - last_rtc_update >= 659 &&
@@ -175,19 +191,15 @@ again:
175 write_sequnlock(&xtime_lock); 191 write_sequnlock(&xtime_lock);
176 } 192 }
177 193
178 /* NOTE: writing CCOMPAREn clears the interrupt. */ 194 /* Allow platform to do something useful (Wdog). */
179 195
180 set_linux_timer (next); 196 platform_heartbeat();
181 197
182 /* Make sure we didn't miss any tick... */ 198 /* Make sure we didn't miss any tick... */
183 199
184 if ((signed long)(get_ccount() - next) > 0) 200 if ((signed long)(get_ccount() - next) > 0)
185 goto again; 201 goto again;
186 202
187 /* Allow platform to do something useful (Wdog). */
188
189 platform_heartbeat();
190
191 return IRQ_HANDLED; 203 return IRQ_HANDLED;
192} 204}
193 205
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index c5e62f9d9f50..8be99c777d9d 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -83,7 +83,7 @@ typedef struct {
83 void* handler; 83 void* handler;
84} dispatch_init_table_t; 84} dispatch_init_table_t;
85 85
86dispatch_init_table_t __init dispatch_init_table[] = { 86static dispatch_init_table_t __initdata dispatch_init_table[] = {
87 87
88{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction}, 88{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
89{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel }, 89{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
@@ -305,7 +305,7 @@ do_debug(struct pt_regs *regs)
305 305
306#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler)) 306#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
307 307
308void trap_init(void) 308void __init trap_init(void)
309{ 309{
310 int i; 310 int i;
311 311
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
index a5aed5932d7b..10aec22a8f98 100644
--- a/arch/xtensa/mm/Makefile
+++ b/arch/xtensa/mm/Makefile
@@ -5,9 +5,5 @@
5# removes any old dependencies. DON'T put your own dependencies here 5# removes any old dependencies. DON'T put your own dependencies here
6# unless it's something special (ie not a .c file). 6# unless it's something special (ie not a .c file).
7# 7#
8# Note 2! The CFLAGS definition is now in the main makefile...
9 8
10obj-y := init.o fault.o tlb.o misc.o 9obj-y := init.o fault.o tlb.o misc.o cache.o
11obj-m :=
12obj-n :=
13obj- :=
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
new file mode 100644
index 000000000000..9a1fa9478ae7
--- /dev/null
+++ b/arch/xtensa/mm/cache.c
@@ -0,0 +1,256 @@
1/*
2 * arch/xtensa/mm/cache.c
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 2001-2006 Tensilica Inc.
9 *
10 * Chris Zankel <chris@zankel.net>
11 * Joe Taylor
12 * Marc Gauthier
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/signal.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/string.h>
22#include <linux/types.h>
23#include <linux/ptrace.h>
24#include <linux/bootmem.h>
25#include <linux/swap.h>
26#include <linux/pagemap.h>
27
28#include <asm/pgtable.h>
29#include <asm/bootparam.h>
30#include <asm/mmu_context.h>
31#include <asm/tlb.h>
32#include <asm/tlbflush.h>
33#include <asm/page.h>
34#include <asm/pgalloc.h>
35#include <asm/pgtable.h>
36
37//#define printd(x...) printk(x)
38#define printd(x...) do { } while(0)
39
40/*
41 * Note:
42 * The kernel provides one architecture bit PG_arch_1 in the page flags that
43 * can be used for cache coherency.
44 *
45 * I$-D$ coherency.
46 *
47 * The Xtensa architecture doesn't keep the instruction cache coherent with
48 * the data cache. We use the architecture bit to indicate if the caches
49 * are coherent. The kernel clears this bit whenever a page is added to the
50 * page cache. At that time, the caches might not be in sync. We, therefore,
51 * define this flag as 'clean' if set.
52 *
53 * D-cache aliasing.
54 *
55 * With cache aliasing, we have to always flush the cache when pages are
56 * unmapped (see tlb_start_vma(). So, we use this flag to indicate a dirty
57 * page.
58 *
59 *
60 *
61 */
62
63#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
64
65/*
66 * Any time the kernel writes to a user page cache page, or it is about to
67 * read from a page cache page this routine is called.
68 *
69 */
70
71void flush_dcache_page(struct page *page)
72{
73 struct address_space *mapping = page_mapping(page);
74
75 /*
76 * If we have a mapping but the page is not mapped to user-space
77 * yet, we simply mark this page dirty and defer flushing the
78 * caches until update_mmu().
79 */
80
81 if (mapping && !mapping_mapped(mapping)) {
82 if (!test_bit(PG_arch_1, &page->flags))
83 set_bit(PG_arch_1, &page->flags);
84 return;
85
86 } else {
87
88 unsigned long phys = page_to_phys(page);
89 unsigned long temp = page->index << PAGE_SHIFT;
90 unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys));
91 unsigned long virt;
92
93 /*
94 * Flush the page in kernel space and user space.
95 * Note that we can omit that step if aliasing is not
96 * an issue, but we do have to synchronize I$ and D$
97 * if we have a mapping.
98 */
99
100 if (!alias && !mapping)
101 return;
102
103 __flush_invalidate_dcache_page((long)page_address(page));
104
105 virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK);
106
107 if (alias)
108 __flush_invalidate_dcache_page_alias(virt, phys);
109
110 if (mapping)
111 __invalidate_icache_page_alias(virt, phys);
112 }
113
114 /* There shouldn't be an entry in the cache for this page anymore. */
115}
116
117
118/*
119 * For now, flush the whole cache. FIXME??
120 */
121
122void flush_cache_range(struct vm_area_struct* vma,
123 unsigned long start, unsigned long end)
124{
125 __flush_invalidate_dcache_all();
126 __invalidate_icache_all();
127}
128
129/*
130 * Remove any entry in the cache for this page.
131 *
132 * Note that this function is only called for user pages, so use the
133 * alias versions of the cache flush functions.
134 */
135
136void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
137 unsigned long pfn)
138{
139 /* Note that we have to use the 'alias' address to avoid multi-hit */
140
141 unsigned long phys = page_to_phys(pfn_to_page(pfn));
142 unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK);
143
144 __flush_invalidate_dcache_page_alias(virt, phys);
145 __invalidate_icache_page_alias(virt, phys);
146}
147
148#endif
149
150void
151update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
152{
153 unsigned long pfn = pte_pfn(pte);
154 struct page *page;
155
156 if (!pfn_valid(pfn))
157 return;
158
159 page = pfn_to_page(pfn);
160
161 /* Invalidate old entry in TLBs */
162
163 invalidate_itlb_mapping(addr);
164 invalidate_dtlb_mapping(addr);
165
166#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
167
168 if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
169
170 unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
171 unsigned long paddr = (unsigned long) page_address(page);
172 unsigned long phys = page_to_phys(page);
173
174 __flush_invalidate_dcache_page(paddr);
175
176 __flush_invalidate_dcache_page_alias(vaddr, phys);
177 __invalidate_icache_page_alias(vaddr, phys);
178
179 clear_bit(PG_arch_1, &page->flags);
180 }
181#else
182 if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
183 && (vma->vm_flags & VM_EXEC) != 0) {
184 unsigned long vaddr = addr & PAGE_MASK;
185 __flush_dcache_page(vaddr);
186 __invalidate_icache_page(vaddr);
187 set_bit(PG_arch_1, &page->flags);
188 }
189#endif
190}
191
192/*
193 * access_process_vm() has called get_user_pages(), which has done a
194 * flush_dcache_page() on the page.
195 */
196
197#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
198
199void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
200 unsigned long vaddr, void *dst, const void *src,
201 unsigned long len)
202{
203 unsigned long phys = page_to_phys(page);
204 unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
205
206 /* Flush and invalidate user page if aliased. */
207
208 if (alias) {
209 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
210 __flush_invalidate_dcache_page_alias(temp, phys);
211 }
212
213 /* Copy data */
214
215 memcpy(dst, src, len);
216
217 /*
218 * Flush and invalidate kernel page if aliased and synchronize
219 * data and instruction caches for executable pages.
220 */
221
222 if (alias) {
223 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
224
225 __flush_invalidate_dcache_range((unsigned long) dst, len);
226 if ((vma->vm_flags & VM_EXEC) != 0) {
227 __invalidate_icache_page_alias(temp, phys);
228 }
229
230 } else if ((vma->vm_flags & VM_EXEC) != 0) {
231 __flush_dcache_range((unsigned long)dst,len);
232 __invalidate_icache_range((unsigned long) dst, len);
233 }
234}
235
236extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
237 unsigned long vaddr, void *dst, const void *src,
238 unsigned long len)
239{
240 unsigned long phys = page_to_phys(page);
241 unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
242
243 /*
244 * Flush user page if aliased.
245 * (Note: a simply flush would be sufficient)
246 */
247
248 if (alias) {
249 unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
250 __flush_invalidate_dcache_page_alias(temp, phys);
251 }
252
253 memcpy(dst, src, len);
254}
255
256#endif
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 16004067add3..45d28f217c03 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -24,6 +24,8 @@
24unsigned long asid_cache = ASID_USER_FIRST; 24unsigned long asid_cache = ASID_USER_FIRST;
25void bad_page_fault(struct pt_regs*, unsigned long, int); 25void bad_page_fault(struct pt_regs*, unsigned long, int);
26 26
27#undef DEBUG_PAGE_FAULT
28
27/* 29/*
28 * This routine handles page faults. It determines the address, 30 * This routine handles page faults. It determines the address,
29 * and the problem, and then passes it off to one of the appropriate 31 * and the problem, and then passes it off to one of the appropriate
@@ -64,7 +66,7 @@ void do_page_fault(struct pt_regs *regs)
64 exccause == EXCCAUSE_ITLB_MISS || 66 exccause == EXCCAUSE_ITLB_MISS ||
65 exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0; 67 exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
66 68
67#if 0 69#ifdef DEBUG_PAGE_FAULT
68 printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid, 70 printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
69 address, exccause, regs->pc, is_write? "w":"", is_exec? "x":""); 71 address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
70#endif 72#endif
@@ -219,7 +221,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
219 221
220 /* Are we prepared to handle this kernel fault? */ 222 /* Are we prepared to handle this kernel fault? */
221 if ((entry = search_exception_tables(regs->pc)) != NULL) { 223 if ((entry = search_exception_tables(regs->pc)) != NULL) {
222#if 1 224#ifdef DEBUG_PAGE_FAULT
223 printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n", 225 printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
224 current->comm, regs->pc, entry->fixup); 226 current->comm, regs->pc, entry->fixup);
225#endif 227#endif
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 8415c76f11c2..b3086f34a8e7 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -15,40 +15,24 @@
15 * Kevin Chea 15 * Kevin Chea
16 */ 16 */
17 17
18#include <linux/init.h>
19#include <linux/signal.h>
20#include <linux/sched.h>
21#include <linux/kernel.h> 18#include <linux/kernel.h>
22#include <linux/errno.h> 19#include <linux/errno.h>
23#include <linux/string.h>
24#include <linux/types.h>
25#include <linux/ptrace.h>
26#include <linux/bootmem.h> 20#include <linux/bootmem.h>
27#include <linux/swap.h> 21#include <linux/swap.h>
22#include <linux/mman.h>
23#include <linux/nodemask.h>
24#include <linux/mm.h>
25#include <linux/slab.h>
28 26
29#include <asm/pgtable.h> 27#include <asm/pgtable.h>
30#include <asm/bootparam.h> 28#include <asm/bootparam.h>
31#include <asm/mmu_context.h> 29#include <asm/mmu_context.h>
32#include <asm/tlb.h> 30#include <asm/tlb.h>
33#include <asm/tlbflush.h>
34#include <asm/page.h> 31#include <asm/page.h>
35#include <asm/pgalloc.h> 32#include <asm/pgalloc.h>
36#include <asm/pgtable.h>
37
38 33
39#define DEBUG 0
40 34
41DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 35DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
42//static DEFINE_SPINLOCK(tlb_lock);
43
44/*
45 * This flag is used to indicate that the page was mapped and modified in
46 * kernel space, so the cache is probably dirty at that address.
47 * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
48 * synchronizes the caches if this bit is set.
49 */
50
51#define PG_cache_clean PG_arch_1
52 36
53/* References to section boundaries */ 37/* References to section boundaries */
54 38
@@ -323,228 +307,22 @@ void show_mem(void)
323 printk("%d free pages\n", free); 307 printk("%d free pages\n", free);
324} 308}
325 309
326/* ------------------------------------------------------------------------- */ 310struct kmem_cache *pgtable_cache __read_mostly;
327
328#if (DCACHE_WAY_SIZE > PAGE_SIZE)
329
330/*
331 * With cache aliasing, the page color of the page in kernel space and user
332 * space might mismatch. We temporarily map the page to a different virtual
333 * address with the same color and clear the page there.
334 */
335
336void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
337{
338
339 /* There shouldn't be any entries for this page. */
340
341 __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
342
343 if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
344 unsigned long v, p;
345
346 /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
347
348 spin_lock(&tlb_lock);
349
350 p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
351 kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
352 v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
353 __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
354
355 clear_page(kaddr);
356
357 spin_unlock(&tlb_lock);
358 } else {
359 clear_page(kaddr);
360 }
361
362 /* We need to make sure that i$ and d$ are coherent. */
363
364 clear_bit(PG_cache_clean, &page->flags);
365}
366
367/*
368 * With cache aliasing, we have to make sure that the page color of the page
369 * in kernel space matches that of the virtual user address before we read
370 * the page. If the page color differ, we create a temporary DTLB entry with
371 * the corrent page color and use this 'temporary' address as the source.
372 * We then use the same approach as in clear_user_page and copy the data
373 * to the kernel space and clear the PG_cache_clean bit to synchronize caches
374 * later.
375 *
376 * Note:
377 * Instead of using another 'way' for the temporary DTLB entry, we could
378 * probably use the same entry that points to the kernel address (after
379 * saving the original value and restoring it when we are done).
380 */
381 311
382void copy_user_page(void* to, void* from, unsigned long vaddr, 312static void pgd_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
383 struct page* to_page)
384{ 313{
385 /* There shouldn't be any entries for the new page. */ 314 pte_t* ptep = (pte_t*)addr;
386 315 int i;
387 __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
388
389 spin_lock(&tlb_lock);
390
391 if (!PAGE_COLOR_EQ(vaddr, from)) {
392 unsigned long v, p, t;
393
394 __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
395 : "=a"(p), "=a"(t) : "a"(from));
396 from = (void*)PAGE_COLOR_MAP0(vaddr);
397 v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
398 __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
399 }
400
401 if (!PAGE_COLOR_EQ(vaddr, to)) {
402 unsigned long v, p;
403
404 p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
405 to = (void*)PAGE_COLOR_MAP1(vaddr);
406 v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
407 __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
408 }
409 copy_page(to, from);
410
411 spin_unlock(&tlb_lock);
412
413 /* We need to make sure that i$ and d$ are coherent. */
414
415 clear_bit(PG_cache_clean, &to_page->flags);
416}
417
418
419
420/*
421 * Any time the kernel writes to a user page cache page, or it is about to
422 * read from a page cache page this routine is called.
423 *
424 * Note:
425 * The kernel currently only provides one architecture bit in the page
426 * flags that we use for I$/D$ coherency. Maybe, in future, we can
427 * use a sepearte bit for deferred dcache aliasing:
428 * If the page is not mapped yet, we only need to set a flag,
429 * if mapped, we need to invalidate the page.
430 */
431// FIXME: we probably need this for WB caches not only for Page Coloring..
432
433void flush_dcache_page(struct page *page)
434{
435 unsigned long addr = __pa(page_address(page));
436 struct address_space *mapping = page_mapping(page);
437
438 __flush_invalidate_dcache_page_phys(addr);
439
440 if (!test_bit(PG_cache_clean, &page->flags))
441 return;
442
443 /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
444#if 0
445 if (mapping && !mapping_mapped(mapping))
446 clear_bit(PG_cache_clean, &page->flags);
447 else
448#endif
449 __invalidate_icache_page_phys(addr);
450}
451
452void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
453 unsigned long e)
454{
455 __flush_invalidate_cache_all();
456}
457
458void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
459 unsigned long pfn)
460{
461 struct page *page = pfn_to_page(pfn);
462
463 /* Remove any entry for the old mapping. */
464
465 if (current->active_mm == vma->vm_mm) {
466 unsigned long addr = __pa(page_address(page));
467 __flush_invalidate_dcache_page_phys(addr);
468 if ((vma->vm_flags & VM_EXEC) != 0)
469 __invalidate_icache_page_phys(addr);
470 } else {
471 BUG();
472 }
473}
474
475#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
476
477
478pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
479{
480 pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
481 if (likely(pte)) {
482 pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
483 int i;
484 for (i = 0; i < 1024; i++, ptep++)
485 pte_clear(mm, addr, ptep);
486 }
487 return pte;
488}
489
490struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
491{
492 struct page *page;
493
494 page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
495
496 if (likely(page)) {
497 pte_t* ptep = kmap_atomic(page, KM_USER0);
498 int i;
499 316
500 for (i = 0; i < 1024; i++, ptep++) 317 for (i = 0; i < 1024; i++, ptep++)
501 pte_clear(mm, addr, ptep); 318 pte_clear(NULL, 0, ptep);
502 319
503 kunmap_atomic(ptep, KM_USER0);
504 }
505 return page;
506} 320}
507 321
508 322void __init pgtable_cache_init(void)
509/*
510 * Handle D$/I$ coherency.
511 *
512 * Note:
513 * We only have one architecture bit for the page flags, so we cannot handle
514 * cache aliasing, yet.
515 */
516
517void
518update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
519{ 323{
520 unsigned long pfn = pte_pfn(pte); 324 pgtable_cache = kmem_cache_create("pgd",
521 struct page *page; 325 PAGE_SIZE, PAGE_SIZE,
522 unsigned long vaddr = addr & PAGE_MASK; 326 SLAB_HWCACHE_ALIGN,
523 327 pgd_ctor);
524 if (!pfn_valid(pfn))
525 return;
526
527 page = pfn_to_page(pfn);
528
529 invalidate_itlb_mapping(addr);
530 invalidate_dtlb_mapping(addr);
531
532 /* We have a new mapping. Use it. */
533
534 write_dtlb_entry(pte, dtlb_probe(addr));
535
536 /* If the processor can execute from this page, synchronize D$/I$. */
537
538 if ((vma->vm_flags & VM_EXEC) != 0) {
539
540 write_itlb_entry(pte, itlb_probe(addr));
541
542 /* Synchronize caches, if not clean. */
543
544 if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
545 __flush_dcache_page(vaddr);
546 __invalidate_icache_page(vaddr);
547 }
548 }
549} 328}
550
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
index ae085332c607..e1f880368e32 100644
--- a/arch/xtensa/mm/misc.S
+++ b/arch/xtensa/mm/misc.S
@@ -7,29 +7,33 @@
7 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details. 8 * for more details.
9 * 9 *
10 * Copyright (C) 2001 - 2005 Tensilica Inc. 10 * Copyright (C) 2001 - 2007 Tensilica Inc.
11 * 11 *
12 * Chris Zankel <chris@zankel.net> 12 * Chris Zankel <chris@zankel.net>
13 */ 13 */
14 14
15/* Note: we might want to implement some of the loops as zero-overhead-loops,
16 * where applicable and if supported by the processor.
17 */
18 15
19#include <linux/linkage.h> 16#include <linux/linkage.h>
20#include <asm/page.h> 17#include <asm/page.h>
21#include <asm/pgtable.h> 18#include <asm/pgtable.h>
22#include <asm/asmmacro.h> 19#include <asm/asmmacro.h>
23#include <asm/cacheasm.h> 20#include <asm/cacheasm.h>
21#include <asm/tlbflush.h>
22
24 23
25/* clear_page (page) */ 24/*
25 * clear_page and clear_user_page are the same for non-cache-aliased configs.
26 *
27 * clear_page (unsigned long page)
28 * a2
29 */
26 30
27ENTRY(clear_page) 31ENTRY(clear_page)
28 entry a1, 16 32 entry a1, 16
29 addi a4, a2, PAGE_SIZE
30 movi a3, 0
31 33
321: s32i a3, a2, 0 34 movi a3, 0
35 __loopi a2, a7, PAGE_SIZE, 32
36 s32i a3, a2, 0
33 s32i a3, a2, 4 37 s32i a3, a2, 4
34 s32i a3, a2, 8 38 s32i a3, a2, 8
35 s32i a3, a2, 12 39 s32i a3, a2, 12
@@ -37,42 +41,277 @@ ENTRY(clear_page)
37 s32i a3, a2, 20 41 s32i a3, a2, 20
38 s32i a3, a2, 24 42 s32i a3, a2, 24
39 s32i a3, a2, 28 43 s32i a3, a2, 28
40 addi a2, a2, 32 44 __endla a2, a7, 32
41 blt a2, a4, 1b
42 45
43 retw 46 retw
44 47
45/* 48/*
49 * copy_page and copy_user_page are the same for non-cache-aliased configs.
50 *
46 * copy_page (void *to, void *from) 51 * copy_page (void *to, void *from)
47 * a2 a3 52 * a2 a3
48 */ 53 */
49 54
50ENTRY(copy_page) 55ENTRY(copy_page)
51 entry a1, 16 56 entry a1, 16
52 addi a4, a2, PAGE_SIZE
53
541: l32i a5, a3, 0
55 l32i a6, a3, 4
56 l32i a7, a3, 8
57 s32i a5, a2, 0
58 s32i a6, a2, 4
59 s32i a7, a2, 8
60 l32i a5, a3, 12
61 l32i a6, a3, 16
62 l32i a7, a3, 20
63 s32i a5, a2, 12
64 s32i a6, a2, 16
65 s32i a7, a2, 20
66 l32i a5, a3, 24
67 l32i a6, a3, 28
68 s32i a5, a2, 24
69 s32i a6, a2, 28
70 addi a2, a2, 32
71 addi a3, a3, 32
72 blt a2, a4, 1b
73 57
58 __loopi a2, a4, PAGE_SIZE, 32
59
60 l32i a8, a3, 0
61 l32i a9, a3, 4
62 s32i a8, a2, 0
63 s32i a9, a2, 4
64
65 l32i a8, a3, 8
66 l32i a9, a3, 12
67 s32i a8, a2, 8
68 s32i a9, a2, 12
69
70 l32i a8, a3, 16
71 l32i a9, a3, 20
72 s32i a8, a2, 16
73 s32i a9, a2, 20
74
75 l32i a8, a3, 24
76 l32i a9, a3, 28
77 s32i a8, a2, 24
78 s32i a9, a2, 28
79
80 addi a2, a2, 32
81 addi a3, a3, 32
82
83 __endl a2, a4
84
85 retw
86
87/*
88 * If we have to deal with cache aliasing, we use temporary memory mappings
89 * to ensure that the source and destination pages have the same color as
90 * the virtual address. We use way 0 and 1 for temporary mappings in such cases.
91 *
92 * The temporary DTLB entries shouldn't be flushed by interrupts, but are
93 * flushed by preemptive task switches. Special code in the
94 * fast_second_level_miss handler re-established the temporary mapping.
95 * It requires that the PPNs for the destination and source addresses are
96 * in a6, and a7, respectively.
97 */
98
99/* TLB miss exceptions are treated special in the following region */
100
101ENTRY(__tlbtemp_mapping_start)
102
103#if (DCACHE_WAY_SIZE > PAGE_SIZE)
104
105/*
106 * clear_user_page (void *addr, unsigned long vaddr, struct page *page)
107 * a2 a3 a4
108 */
109
110ENTRY(clear_user_page)
111 entry a1, 32
112
113 /* Mark page dirty and determine alias. */
114
115 movi a7, (1 << PG_ARCH_1)
116 l32i a5, a4, PAGE_FLAGS
117 xor a6, a2, a3
118 extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER
119 extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
120 or a5, a5, a7
121 slli a3, a3, PAGE_SHIFT
122 s32i a5, a4, PAGE_FLAGS
123
124 /* Skip setting up a temporary DTLB if not aliased. */
125
126 beqz a6, 1f
127
128 /* Invalidate kernel page. */
129
130 mov a10, a2
131 call8 __invalidate_dcache_page
132
133 /* Setup a temporary DTLB with the color of the VPN */
134
135 movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
136 movi a5, TLBTEMP_BASE_1 # virt
137 add a6, a2, a4 # ppn
138 add a2, a5, a3 # add 'color'
139
140 wdtlb a6, a2
141 dsync
142
1431: movi a3, 0
144 __loopi a2, a7, PAGE_SIZE, 32
145 s32i a3, a2, 0
146 s32i a3, a2, 4
147 s32i a3, a2, 8
148 s32i a3, a2, 12
149 s32i a3, a2, 16
150 s32i a3, a2, 20
151 s32i a3, a2, 24
152 s32i a3, a2, 28
153 __endla a2, a7, 32
154
155 bnez a6, 1f
156 retw
157
158 /* We need to invalidate the temporary idtlb entry, if any. */
159
1601: addi a2, a2, -PAGE_SIZE
161 idtlb a2
162 dsync
163
164 retw
165
166/*
167 * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
168 * a2 a3 a4 a5
169 */
170
171ENTRY(copy_user_page)
172
173 entry a1, 32
174
175 /* Mark page dirty and determine alias for destination. */
176
177 movi a8, (1 << PG_ARCH_1)
178 l32i a9, a5, PAGE_FLAGS
179 xor a6, a2, a4
180 xor a7, a3, a4
181 extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER
182 extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
183 extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER
184 or a9, a9, a8
185 slli a4, a4, PAGE_SHIFT
186 s32i a9, a5, PAGE_FLAGS
187 movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
188
189 beqz a6, 1f
190
191 /* Invalidate dcache */
192
193 mov a10, a2
194 call8 __invalidate_dcache_page
195
196 /* Setup a temporary DTLB with a matching color. */
197
198 movi a8, TLBTEMP_BASE_1 # base
199 add a6, a2, a5 # ppn
200 add a2, a8, a4 # add 'color'
201
202 wdtlb a6, a2
203 dsync
204
205 /* Skip setting up a temporary DTLB for destination if not aliased. */
206
2071: beqz a7, 1f
208
209 /* Setup a temporary DTLB with a matching color. */
210
211 movi a8, TLBTEMP_BASE_2 # base
212 add a7, a3, a5 # ppn
213 add a3, a8, a4
214 addi a8, a3, 1 # way1
215
216 wdtlb a7, a8
217 dsync
218
2191: __loopi a2, a4, PAGE_SIZE, 32
220
221 l32i a8, a3, 0
222 l32i a9, a3, 4
223 s32i a8, a2, 0
224 s32i a9, a2, 4
225
226 l32i a8, a3, 8
227 l32i a9, a3, 12
228 s32i a8, a2, 8
229 s32i a9, a2, 12
230
231 l32i a8, a3, 16
232 l32i a9, a3, 20
233 s32i a8, a2, 16
234 s32i a9, a2, 20
235
236 l32i a8, a3, 24
237 l32i a9, a3, 28
238 s32i a8, a2, 24
239 s32i a9, a2, 28
240
241 addi a2, a2, 32
242 addi a3, a3, 32
243
244 __endl a2, a4
245
246 /* We need to invalidate any temporary mapping! */
247
248 bnez a6, 1f
249 bnez a7, 2f
250 retw
251
2521: addi a2, a2, -PAGE_SIZE
253 idtlb a2
254 dsync
255 bnez a7, 2f
256 retw
257
2582: addi a3, a3, -PAGE_SIZE+1
259 idtlb a3
260 dsync
261
262 retw
263
264#endif
265
266#if (DCACHE_WAY_SIZE > PAGE_SIZE)
267
268/*
269 * void __flush_invalidate_dcache_page_alias (addr, phys)
270 * a2 a3
271 */
272
273ENTRY(__flush_invalidate_dcache_page_alias)
274 entry sp, 16
275
276 movi a7, 0 # required for exception handler
277 addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
278 mov a4, a2
279 wdtlb a6, a2
280 dsync
281
282 ___flush_invalidate_dcache_page a2 a3
283
284 idtlb a4
285 dsync
286
287 retw
288
289#endif
290
291ENTRY(__tlbtemp_mapping_itlb)
292
293#if (ICACHE_WAY_SIZE > PAGE_SIZE)
294
295ENTRY(__invalidate_icache_page_alias)
296 entry sp, 16
297
298 addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
299 mov a4, a2
300 witlb a6, a2
301 isync
302
303 ___invalidate_icache_page a2 a3
304
305 iitlb a4
306 isync
74 retw 307 retw
75 308
309#endif
310
311/* End of special treatment in tlb miss exception */
312
313ENTRY(__tlbtemp_mapping_end)
314
76/* 315/*
77 * void __invalidate_icache_page(ulong start) 316 * void __invalidate_icache_page(ulong start)
78 */ 317 */
@@ -121,8 +360,6 @@ ENTRY(__flush_dcache_page)
121 dsync 360 dsync
122 retw 361 retw
123 362
124
125
126/* 363/*
127 * void __invalidate_icache_range(ulong start, ulong size) 364 * void __invalidate_icache_range(ulong start, ulong size)
128 */ 365 */
@@ -168,7 +405,6 @@ ENTRY(__invalidate_dcache_range)
168 405
169 ___invalidate_dcache_range a2 a3 a4 406 ___invalidate_dcache_range a2 a3 a4
170 407
171
172 retw 408 retw
173 409
174/* 410/*
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 2f4f20ffe666..854677d0c3f6 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -20,7 +20,6 @@
20#include <linux/param.h> 20#include <linux/param.h>
21#include <linux/serial.h> 21#include <linux/serial.h>
22#include <linux/serialP.h> 22#include <linux/serialP.h>
23#include <linux/console.h>
24 23
25#include <asm/uaccess.h> 24#include <asm/uaccess.h>
26#include <asm/irq.h> 25#include <asm/irq.h>