xref: /openbmc/linux/arch/sh/mm/tlb-urb.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
1bb29c677SPaul Mundt /*
2bb29c677SPaul Mundt  * arch/sh/mm/tlb-urb.c
3bb29c677SPaul Mundt  *
4bb29c677SPaul Mundt  * TLB entry wiring helpers for URB-equipped parts.
5bb29c677SPaul Mundt  *
6bb29c677SPaul Mundt  * Copyright (C) 2010  Matt Fleming
7bb29c677SPaul Mundt  *
8bb29c677SPaul Mundt  * This file is subject to the terms and conditions of the GNU General Public
9bb29c677SPaul Mundt  * License.  See the file "COPYING" in the main directory of this archive
10bb29c677SPaul Mundt  * for more details.
11bb29c677SPaul Mundt  */
12bb29c677SPaul Mundt #include <linux/mm.h>
13bb29c677SPaul Mundt #include <linux/io.h>
14bb29c677SPaul Mundt #include <asm/tlb.h>
15bb29c677SPaul Mundt #include <asm/mmu_context.h>
16bb29c677SPaul Mundt 
17bb29c677SPaul Mundt /*
18bb29c677SPaul Mundt  * Load the entry for 'addr' into the TLB and wire the entry.
19bb29c677SPaul Mundt  */
tlb_wire_entry(struct vm_area_struct * vma,unsigned long addr,pte_t pte)20bb29c677SPaul Mundt void tlb_wire_entry(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
21bb29c677SPaul Mundt {
22bb29c677SPaul Mundt 	unsigned long status, flags;
23bb29c677SPaul Mundt 	int urb;
24bb29c677SPaul Mundt 
25bb29c677SPaul Mundt 	local_irq_save(flags);
26bb29c677SPaul Mundt 
27bb29c677SPaul Mundt 	status = __raw_readl(MMUCR);
28bb29c677SPaul Mundt 	urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT;
29*4539282dSMatt Fleming 	status &= ~MMUCR_URC;
30bb29c677SPaul Mundt 
31bb29c677SPaul Mundt 	/*
32bb29c677SPaul Mundt 	 * Make sure we're not trying to wire the last TLB entry slot.
33bb29c677SPaul Mundt 	 */
34bb29c677SPaul Mundt 	BUG_ON(!--urb);
35bb29c677SPaul Mundt 
36bb29c677SPaul Mundt 	urb = urb % MMUCR_URB_NENTRIES;
37bb29c677SPaul Mundt 
38*4539282dSMatt Fleming 	/*
39*4539282dSMatt Fleming 	 * Insert this entry into the highest non-wired TLB slot (via
40*4539282dSMatt Fleming 	 * the URC field).
41*4539282dSMatt Fleming 	 */
42*4539282dSMatt Fleming 	status |= (urb << MMUCR_URC_SHIFT);
43*4539282dSMatt Fleming 	__raw_writel(status, MMUCR);
44*4539282dSMatt Fleming 	ctrl_barrier();
45*4539282dSMatt Fleming 
46*4539282dSMatt Fleming 	/* Load the entry into the TLB */
47*4539282dSMatt Fleming 	__update_tlb(vma, addr, pte);
48*4539282dSMatt Fleming 
49*4539282dSMatt Fleming 	/* ... and wire it up. */
50*4539282dSMatt Fleming 	status = __raw_readl(MMUCR);
51*4539282dSMatt Fleming 
52*4539282dSMatt Fleming 	status &= ~MMUCR_URB;
53bb29c677SPaul Mundt 	status |= (urb << MMUCR_URB_SHIFT);
54*4539282dSMatt Fleming 
55bb29c677SPaul Mundt 	__raw_writel(status, MMUCR);
56bb29c677SPaul Mundt 	ctrl_barrier();
57bb29c677SPaul Mundt 
58bb29c677SPaul Mundt 	local_irq_restore(flags);
59bb29c677SPaul Mundt }
60bb29c677SPaul Mundt 
61bb29c677SPaul Mundt /*
62bb29c677SPaul Mundt  * Unwire the last wired TLB entry.
63bb29c677SPaul Mundt  *
64bb29c677SPaul Mundt  * It should also be noted that it is not possible to wire and unwire
65bb29c677SPaul Mundt  * TLB entries in an arbitrary order. If you wire TLB entry N, followed
66bb29c677SPaul Mundt  * by entry N+1, you must unwire entry N+1 first, then entry N. In this
67bb29c677SPaul Mundt  * respect, it works like a stack or LIFO queue.
68bb29c677SPaul Mundt  */
tlb_unwire_entry(void)69bb29c677SPaul Mundt void tlb_unwire_entry(void)
70bb29c677SPaul Mundt {
71bb29c677SPaul Mundt 	unsigned long status, flags;
72bb29c677SPaul Mundt 	int urb;
73bb29c677SPaul Mundt 
74bb29c677SPaul Mundt 	local_irq_save(flags);
75bb29c677SPaul Mundt 
76bb29c677SPaul Mundt 	status = __raw_readl(MMUCR);
77bb29c677SPaul Mundt 	urb = (status & MMUCR_URB) >> MMUCR_URB_SHIFT;
78bb29c677SPaul Mundt 	status &= ~MMUCR_URB;
79bb29c677SPaul Mundt 
80bb29c677SPaul Mundt 	/*
81bb29c677SPaul Mundt 	 * Make sure we're not trying to unwire a TLB entry when none
82bb29c677SPaul Mundt 	 * have been wired.
83bb29c677SPaul Mundt 	 */
84bb29c677SPaul Mundt 	BUG_ON(urb++ == MMUCR_URB_NENTRIES);
85bb29c677SPaul Mundt 
86bb29c677SPaul Mundt 	urb = urb % MMUCR_URB_NENTRIES;
87bb29c677SPaul Mundt 
88bb29c677SPaul Mundt 	status |= (urb << MMUCR_URB_SHIFT);
89bb29c677SPaul Mundt 	__raw_writel(status, MMUCR);
90bb29c677SPaul Mundt 	ctrl_barrier();
91bb29c677SPaul Mundt 
92bb29c677SPaul Mundt 	local_irq_restore(flags);
93bb29c677SPaul Mundt }
94