2 * PS3 pagetable management routines.
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006, 2007 Sony Corporation
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/kernel.h>
23 #include <asm/machdep.h>
26 #include <asm/lv1call.h>
27 #include <asm/ps3fb.h>
32 #define DBG udbg_printf
37 static struct hash_pte
*htab
;
38 static unsigned long htab_addr
;
39 static unsigned char *bolttab
;
40 static unsigned char *inusetab
;
42 static DEFINE_SPINLOCK(ps3_bolttab_lock
);
44 #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
45 _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
46 static void _debug_dump_hpte(unsigned long pa
, unsigned long va
,
47 unsigned long group
, unsigned long bitmap
, struct hash_pte lhpte
,
48 int psize
, unsigned long slot
, const char* func
, int line
)
50 DBG("%s:%d: pa = %lxh\n", func
, line
, pa
);
51 DBG("%s:%d: lpar = %lxh\n", func
, line
,
52 ps3_mm_phys_to_lpar(pa
));
53 DBG("%s:%d: va = %lxh\n", func
, line
, va
);
54 DBG("%s:%d: group = %lxh\n", func
, line
, group
);
55 DBG("%s:%d: bitmap = %lxh\n", func
, line
, bitmap
);
56 DBG("%s:%d: hpte.v = %lxh\n", func
, line
, lhpte
.v
);
57 DBG("%s:%d: hpte.r = %lxh\n", func
, line
, lhpte
.r
);
58 DBG("%s:%d: psize = %xh\n", func
, line
, psize
);
59 DBG("%s:%d: slot = %lxh\n", func
, line
, slot
);
62 static long ps3_hpte_insert(unsigned long hpte_group
, unsigned long va
,
63 unsigned long pa
, unsigned long rflags
, unsigned long vflags
,
67 struct hash_pte lhpte
;
72 unsigned long p_pteg
, s_pteg
, b_index
, b_mask
, cb
, ci
;
74 vflags
&= ~HPTE_V_SECONDARY
; /* this bit is ignored */
76 lhpte
.v
= hpte_encode_v(va
, psize
, MMU_SEGSIZE_256M
) |
77 vflags
| HPTE_V_VALID
;
78 lhpte
.r
= hpte_encode_r(ps3_mm_phys_to_lpar(pa
), psize
) | rflags
;
80 p_pteg
= hpte_group
/ HPTES_PER_GROUP
;
81 s_pteg
= ~p_pteg
& htab_hash_mask
;
83 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
85 BUG_ON(bolttab
[p_pteg
] == 0xff && bolttab
[s_pteg
] == 0xff);
87 bitmap
= (inusetab
[p_pteg
] << 8) | inusetab
[s_pteg
];
89 if (bitmap
== 0xffff) {
91 * PTEG is full. Search for victim.
93 bitmap
&= ~((bolttab
[p_pteg
] << 8) | bolttab
[s_pteg
]);
97 } while ((cb
& bitmap
) == 0);
100 * search free slot in hardware order
101 * [primary] 0, 2, 4, 6, 1, 3, 5, 7
102 * [secondary] 0, 2, 4, 6, 1, 3, 5, 7
104 for (ci
= 0; ci
< HPTES_PER_GROUP
; ci
+= 2) {
106 if ((cb
& bitmap
) == 0)
109 for (ci
= 1; ci
< HPTES_PER_GROUP
; ci
+= 2) {
111 if ((cb
& bitmap
) == 0)
114 for (ci
= HPTES_PER_GROUP
; ci
< HPTES_PER_GROUP
*2; ci
+= 2) {
116 if ((cb
& bitmap
) == 0)
119 for (ci
= HPTES_PER_GROUP
+1; ci
< HPTES_PER_GROUP
*2; ci
+= 2) {
121 if ((cb
& bitmap
) == 0)
127 if (ci
< HPTES_PER_GROUP
) {
128 slot
= p_pteg
* HPTES_PER_GROUP
+ ci
;
130 slot
= s_pteg
* HPTES_PER_GROUP
+ (ci
& 7);
131 /* lhpte.dw0.dw0.h = 1; */
132 vflags
|= HPTE_V_SECONDARY
;
133 lhpte
.v
|= HPTE_V_SECONDARY
;
136 result
= lv1_write_htab_entry(0, slot
, lhpte
.v
, lhpte
.r
);
139 debug_dump_hpte(pa
, va
, hpte_group
, bitmap
, lhpte
, psize
, slot
);
144 * If used slot is not in primary HPTE group,
145 * the slot should be in secondary HPTE group.
148 if ((hpte_group
^ slot
) & ~(HPTES_PER_GROUP
- 1)) {
156 b_mask
= (lhpte
.v
& HPTE_V_BOLTED
) ? 1 << 7 : 0 << 7;
157 bolttab
[b_index
] |= b_mask
>> (slot
& 7);
159 inusetab
[b_index
] |= b_mask
>> (slot
& 7);
160 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
162 return (slot
& 7) | (secondary
<< 3);
165 static long ps3_hpte_remove(unsigned long hpte_group
)
167 panic("ps3_hpte_remove() not implemented");
171 static long ps3_hpte_updatepp(unsigned long slot
, unsigned long newpp
,
172 unsigned long va
, int psize
, int ssize
, int local
)
175 unsigned long result
;
176 unsigned long pteg
, bit
;
177 unsigned long hpte_v
, want_v
;
179 want_v
= hpte_encode_v(va
, psize
, MMU_SEGSIZE_256M
);
181 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
183 hpte_v
= htab
[slot
].v
;
184 if (!HPTE_V_COMPARE(hpte_v
, want_v
) || !(hpte_v
& HPTE_V_VALID
)) {
185 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
187 /* ps3_hpte_insert() will be used to update PTE */
191 result
= lv1_write_htab_entry(0, slot
, 0, 0);
194 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n",
195 __func__
, va
, slot
, psize
, result
, result
);
199 pteg
= slot
/ HPTES_PER_GROUP
;
200 bit
= slot
% HPTES_PER_GROUP
;
201 inusetab
[pteg
] &= ~(0x80 >> bit
);
203 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
205 /* ps3_hpte_insert() will be used to update PTE */
209 static void ps3_hpte_updateboltedpp(unsigned long newpp
, unsigned long ea
,
210 int psize
, int ssize
)
212 panic("ps3_hpte_updateboltedpp() not implemented");
215 static void ps3_hpte_invalidate(unsigned long slot
, unsigned long va
,
216 int psize
, int ssize
, int local
)
219 unsigned long result
;
220 unsigned long pteg
, bit
;
222 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
223 result
= lv1_write_htab_entry(0, slot
, 0, 0);
226 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n",
227 __func__
, va
, slot
, psize
, result
, result
);
231 pteg
= slot
/ HPTES_PER_GROUP
;
232 bit
= slot
% HPTES_PER_GROUP
;
233 inusetab
[pteg
] &= ~(0x80 >> bit
);
234 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
237 static void ps3_hpte_clear(void)
241 DBG(" -> %s:%d\n", __func__
, __LINE__
);
243 result
= lv1_unmap_htab(htab_addr
);
247 ps3_mm_vas_destroy();
249 DBG(" <- %s:%d\n", __func__
, __LINE__
);
252 void __init
ps3_hpte_init(unsigned long htab_size
)
256 DBG(" -> %s:%d\n", __func__
, __LINE__
);
258 ppc_md
.hpte_invalidate
= ps3_hpte_invalidate
;
259 ppc_md
.hpte_updatepp
= ps3_hpte_updatepp
;
260 ppc_md
.hpte_updateboltedpp
= ps3_hpte_updateboltedpp
;
261 ppc_md
.hpte_insert
= ps3_hpte_insert
;
262 ppc_md
.hpte_remove
= ps3_hpte_remove
;
263 ppc_md
.hpte_clear_all
= ps3_hpte_clear
;
265 ppc64_pft_size
= __ilog2(htab_size
);
267 bitmap_size
= htab_size
/ sizeof(struct hash_pte
) / 8;
269 bolttab
= __va(lmb_alloc(bitmap_size
, 1));
270 inusetab
= __va(lmb_alloc(bitmap_size
, 1));
272 memset(bolttab
, 0, bitmap_size
);
273 memset(inusetab
, 0, bitmap_size
);
275 DBG(" <- %s:%d\n", __func__
, __LINE__
);
278 void __init
ps3_map_htab(void)
281 unsigned long htab_size
= (1UL << ppc64_pft_size
);
283 result
= lv1_map_htab(0, &htab_addr
);
285 htab
= (__force
struct hash_pte
*)ioremap_flags(htab_addr
, htab_size
,
286 pgprot_val(PAGE_READONLY_X
));
288 DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__
, __LINE__
,
289 htab_addr
, (unsigned long)htab
);