Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
  1/*
  2 * arch/score/mm/tlb-score.c
  3 *
  4 * Score Processor version.
  5 *
  6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
  7 *  Lennox Wu <lennox.wu@sunplusct.com>
  8 *  Chen Liqin <liqin.chen@sunplusct.com>
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, see the file COPYING, or write
 22 * to the Free Software Foundation, Inc.,
 23 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 24 */
 25
 26#include <linux/highmem.h>
 27#include <linux/module.h>
 28
 29#include <asm/irq.h>
 30#include <asm/mmu_context.h>
 31#include <asm/tlb.h>
 32
 33#define TLBSIZE 32
 34
 35unsigned long asid_cache = ASID_FIRST_VERSION;
 36EXPORT_SYMBOL(asid_cache);
 37
 38void local_flush_tlb_all(void)
 39{
 40	unsigned long flags;
 41	unsigned long old_ASID;
 42	int entry;
 43
 44	local_irq_save(flags);
 45	old_ASID = pevn_get() & ASID_MASK;
 46	pectx_set(0);			/* invalid */
 47	entry = tlblock_get();		/* skip locked entries*/
 48
 49	for (; entry < TLBSIZE; entry++) {
 50		tlbpt_set(entry);
 51		pevn_set(KSEG1);
 52		barrier();
 53		tlb_write_indexed();
 54	}
 55	pevn_set(old_ASID);
 56	local_irq_restore(flags);
 57}
 58
 59/*
 60 * If mm is currently active_mm, we can't really drop it. Instead,
 61 * we will get a new one for it.
 62 */
 63static inline void
 64drop_mmu_context(struct mm_struct *mm)
 65{
 66	unsigned long flags;
 67
 68	local_irq_save(flags);
 69	get_new_mmu_context(mm);
 70	pevn_set(mm->context & ASID_MASK);
 71	local_irq_restore(flags);
 72}
 73
 74void local_flush_tlb_mm(struct mm_struct *mm)
 75{
 76	if (mm->context != 0)
 77		drop_mmu_context(mm);
 78}
 79
 80void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 81	unsigned long end)
 82{
 83	struct mm_struct *mm = vma->vm_mm;
 84	unsigned long vma_mm_context = mm->context;
 85	if (mm->context != 0) {
 86		unsigned long flags;
 87		int size;
 88
 89		local_irq_save(flags);
 90		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 91		if (size <= TLBSIZE) {
 92			int oldpid = pevn_get() & ASID_MASK;
 93			int newpid = vma_mm_context & ASID_MASK;
 94
 95			start &= PAGE_MASK;
 96			end += (PAGE_SIZE - 1);
 97			end &= PAGE_MASK;
 98			while (start < end) {
 99				int idx;
100
101				pevn_set(start | newpid);
102				start += PAGE_SIZE;
103				barrier();
104				tlb_probe();
105				idx = tlbpt_get();
106				pectx_set(0);
107				pevn_set(KSEG1);
108				if (idx < 0)
109					continue;
110				tlb_write_indexed();
111			}
112			pevn_set(oldpid);
113		} else {
114			/* Bigger than TLBSIZE, get new ASID directly */
115			get_new_mmu_context(mm);
116			if (mm == current->active_mm)
117				pevn_set(vma_mm_context & ASID_MASK);
118		}
119		local_irq_restore(flags);
120	}
121}
122
123void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
124{
125	unsigned long flags;
126	int size;
127
128	local_irq_save(flags);
129	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
130	if (size <= TLBSIZE) {
131		int pid = pevn_get();
132
133		start &= PAGE_MASK;
134		end += PAGE_SIZE - 1;
135		end &= PAGE_MASK;
136
137		while (start < end) {
138			long idx;
139
140			pevn_set(start);
141			start += PAGE_SIZE;
142			tlb_probe();
143			idx = tlbpt_get();
144			if (idx < 0)
145				continue;
146			pectx_set(0);
147			pevn_set(KSEG1);
148			barrier();
149			tlb_write_indexed();
150		}
151		pevn_set(pid);
152	} else {
153		local_flush_tlb_all();
154	}
155
156	local_irq_restore(flags);
157}
158
159void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
160{
161	if (vma && vma->vm_mm->context != 0) {
162		unsigned long flags;
163		int oldpid, newpid, idx;
164		unsigned long vma_ASID = vma->vm_mm->context;
165
166		newpid = vma_ASID & ASID_MASK;
167		page &= PAGE_MASK;
168		local_irq_save(flags);
169		oldpid = pevn_get() & ASID_MASK;
170		pevn_set(page | newpid);
171		barrier();
172		tlb_probe();
173		idx = tlbpt_get();
174		pectx_set(0);
175		pevn_set(KSEG1);
176		if (idx < 0)		/* p_bit(31) - 1: miss, 0: hit*/
177			goto finish;
178		barrier();
179		tlb_write_indexed();
180finish:
181		pevn_set(oldpid);
182		local_irq_restore(flags);
183	}
184}
185
186/*
187 * This one is only used for pages with the global bit set so we don't care
188 * much about the ASID.
189 */
190void local_flush_tlb_one(unsigned long page)
191{
192	unsigned long flags;
193	int oldpid, idx;
194
195	local_irq_save(flags);
196	oldpid = pevn_get();
197	page &= (PAGE_MASK << 1);
198	pevn_set(page);
199	barrier();
200	tlb_probe();
201	idx = tlbpt_get();
202	pectx_set(0);
203	if (idx >= 0) {
204		/* Make sure all entries differ. */
205		pevn_set(KSEG1);
206		barrier();
207		tlb_write_indexed();
208	}
209	pevn_set(oldpid);
210	local_irq_restore(flags);
211}
212
213void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
214{
215	unsigned long flags;
216	int idx, pid;
217
218	/*
219	 * Handle debugger faulting in for debugee.
220	 */
221	if (current->active_mm != vma->vm_mm)
222		return;
223
224	pid = pevn_get() & ASID_MASK;
225
226	local_irq_save(flags);
227	address &= PAGE_MASK;
228	pevn_set(address | pid);
229	barrier();
230	tlb_probe();
231	idx = tlbpt_get();
232	pectx_set(pte_val(pte));
233	pevn_set(address | pid);
234	if (idx < 0)
235		tlb_write_random();
236	else
237		tlb_write_indexed();
238
239	pevn_set(pid);
240	local_irq_restore(flags);
241}
242
243void tlb_init(void)
244{
245	tlblock_set(0);
246	local_flush_tlb_all();
247	memcpy((void *)(EXCEPTION_VECTOR_BASE_ADDR + 0x100),
248			&score7_FTLB_refill_Handler, 0xFC);
249	flush_icache_range(EXCEPTION_VECTOR_BASE_ADDR + 0x100,
250			EXCEPTION_VECTOR_BASE_ADDR + 0x1FC);
251}
1