diff options
author | Chris Zankel <chris@zankel.net> | 2007-08-22 13:14:51 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2007-08-27 16:54:16 -0400 |
commit | 6656920b0b50beacb6cb64cf55273cbb686e436e (patch) | |
tree | dab9fdb81821b455a29779de6ca3306dbdf05dbd /arch/xtensa/kernel | |
parent | ff6fd469885aafa5ec387babcb6537f3c00d6df0 (diff) |
[XTENSA] Add support for cache-aliasing
Add support for processors that have cache-aliasing issues, such as
the Stretch S5000 processor. Cache-aliasing means that the size of
the cache (for one way) is larger than the page size, thus, a page
can end up in several places in cache depending on the virtual to
physical translation. The method used here is to map a user page
temporarily through the auto-refill way 0 and of of the DTLB.
We probably will want to revisit this issue and use a better
approach with kmap/kunmap.
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch/xtensa/kernel')
-rw-r--r-- | arch/xtensa/kernel/asm-offsets.c | 13 | ||||
-rw-r--r-- | arch/xtensa/kernel/entry.S | 75 |
2 files changed, 77 insertions, 11 deletions
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 | ||
28 | int main(void) | 29 | int 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 65741e3368e7..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 | ||
@@ -1590,7 +1590,7 @@ ENTRY(fast_second_level_miss) | |||
1590 | * The messy computation for 'pteval' above really simplifies | 1590 | * The messy computation for 'pteval' above really simplifies |
1591 | * into the following: | 1591 | * into the following: |
1592 | * | 1592 | * |
1593 | * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL | 1593 | * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY |
1594 | */ | 1594 | */ |
1595 | 1595 | ||
1596 | movi a1, -PAGE_OFFSET | 1596 | movi a1, -PAGE_OFFSET |
@@ -1602,7 +1602,7 @@ ENTRY(fast_second_level_miss) | |||
1602 | or a0, a0, a1 # ... | PAGE_DIRECTORY | 1602 | or a0, a0, a1 # ... | PAGE_DIRECTORY |
1603 | 1603 | ||
1604 | /* | 1604 | /* |
1605 | * We utilize all three wired-ways (7-9( to hold pmd translations. | 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. | 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 | 1607 | * This allows to map the three most common regions to three different |
1608 | * DTLBs: | 1608 | * DTLBs: |
@@ -1652,6 +1652,73 @@ ENTRY(fast_second_level_miss) | |||
1652 | 9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 | 1652 | 9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0 |
1653 | j 8b | 1653 | j 8b |
1654 | 1654 | ||
1655 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) | ||
1656 | |||
1657 | 2: /* 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 | |||
1714 | 1: witlb a6, a1 | ||
1715 | isync | ||
1716 | j 4b | ||
1717 | |||
1718 | |||
1719 | #endif // DCACHE_WAY_SIZE > PAGE_SIZE | ||
1720 | |||
1721 | |||
1655 | 2: /* Invalid PGD, default exception handling */ | 1722 | 2: /* Invalid PGD, default exception handling */ |
1656 | 1723 | ||
1657 | movi a3, exc_table | 1724 | movi a3, exc_table |