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
, int psize
)
66 struct hash_pte lhpte
;
71 unsigned long p_pteg
, s_pteg
, b_index
, b_mask
, cb
, ci
;
73 vflags
&= ~HPTE_V_SECONDARY
; /* this bit is ignored */
75 lhpte
.v
= hpte_encode_v(va
, psize
) | vflags
| HPTE_V_VALID
;
76 lhpte
.r
= hpte_encode_r(ps3_mm_phys_to_lpar(pa
), psize
) | rflags
;
78 p_pteg
= hpte_group
/ HPTES_PER_GROUP
;
79 s_pteg
= ~p_pteg
& htab_hash_mask
;
81 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
83 BUG_ON(bolttab
[p_pteg
] == 0xff && bolttab
[s_pteg
] == 0xff);
85 bitmap
= (inusetab
[p_pteg
] << 8) | inusetab
[s_pteg
];
87 if (bitmap
== 0xffff) {
89 * PTEG is full. Search for victim.
91 bitmap
&= ~((bolttab
[p_pteg
] << 8) | bolttab
[s_pteg
]);
95 } while ((cb
& bitmap
) == 0);
98 * search free slot in hardware order
99 * [primary] 0, 2, 4, 6, 1, 3, 5, 7
100 * [secondary] 0, 2, 4, 6, 1, 3, 5, 7
102 for (ci
= 0; ci
< HPTES_PER_GROUP
; ci
+= 2) {
104 if ((cb
& bitmap
) == 0)
107 for (ci
= 1; ci
< HPTES_PER_GROUP
; ci
+= 2) {
109 if ((cb
& bitmap
) == 0)
112 for (ci
= HPTES_PER_GROUP
; ci
< HPTES_PER_GROUP
*2; ci
+= 2) {
114 if ((cb
& bitmap
) == 0)
117 for (ci
= HPTES_PER_GROUP
+1; ci
< HPTES_PER_GROUP
*2; ci
+= 2) {
119 if ((cb
& bitmap
) == 0)
125 if (ci
< HPTES_PER_GROUP
) {
126 slot
= p_pteg
* HPTES_PER_GROUP
+ ci
;
128 slot
= s_pteg
* HPTES_PER_GROUP
+ (ci
& 7);
129 /* lhpte.dw0.dw0.h = 1; */
130 vflags
|= HPTE_V_SECONDARY
;
131 lhpte
.v
|= HPTE_V_SECONDARY
;
134 result
= lv1_write_htab_entry(0, slot
, lhpte
.v
, lhpte
.r
);
137 debug_dump_hpte(pa
, va
, hpte_group
, bitmap
, lhpte
, psize
, slot
);
142 * If used slot is not in primary HPTE group,
143 * the slot should be in secondary HPTE group.
146 if ((hpte_group
^ slot
) & ~(HPTES_PER_GROUP
- 1)) {
154 b_mask
= (lhpte
.v
& HPTE_V_BOLTED
) ? 1 << 7 : 0 << 7;
155 bolttab
[b_index
] |= b_mask
>> (slot
& 7);
157 inusetab
[b_index
] |= b_mask
>> (slot
& 7);
158 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
160 return (slot
& 7) | (secondary
<< 3);
163 static long ps3_hpte_remove(unsigned long hpte_group
)
165 panic("ps3_hpte_remove() not implemented");
169 static long ps3_hpte_updatepp(unsigned long slot
, unsigned long newpp
,
170 unsigned long va
, int psize
, int local
)
173 unsigned long result
;
174 unsigned long pteg
, bit
;
175 unsigned long hpte_v
, want_v
;
177 want_v
= hpte_encode_v(va
, psize
);
179 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
181 hpte_v
= htab
[slot
].v
;
182 if (!HPTE_V_COMPARE(hpte_v
, want_v
) || !(hpte_v
& HPTE_V_VALID
)) {
183 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
185 /* ps3_hpte_insert() will be used to update PTE */
189 result
= lv1_write_htab_entry(0, slot
, 0, 0);
192 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n",
193 __func__
, va
, slot
, psize
, result
, result
);
197 pteg
= slot
/ HPTES_PER_GROUP
;
198 bit
= slot
% HPTES_PER_GROUP
;
199 inusetab
[pteg
] &= ~(0x80 >> bit
);
201 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
203 /* ps3_hpte_insert() will be used to update PTE */
207 static void ps3_hpte_updateboltedpp(unsigned long newpp
, unsigned long ea
,
210 panic("ps3_hpte_updateboltedpp() not implemented");
213 static void ps3_hpte_invalidate(unsigned long slot
, unsigned long va
,
214 int psize
, int local
)
217 unsigned long result
;
218 unsigned long pteg
, bit
;
220 spin_lock_irqsave(&ps3_bolttab_lock
, flags
);
221 result
= lv1_write_htab_entry(0, slot
, 0, 0);
224 DBG("%s: va=%lx slot=%lx psize=%d result = %ld (0x%lx)\n",
225 __func__
, va
, slot
, psize
, result
, result
);
229 pteg
= slot
/ HPTES_PER_GROUP
;
230 bit
= slot
% HPTES_PER_GROUP
;
231 inusetab
[pteg
] &= ~(0x80 >> bit
);
232 spin_unlock_irqrestore(&ps3_bolttab_lock
, flags
);
235 static void ps3_hpte_clear(void)
239 DBG(" -> %s:%d\n", __func__
, __LINE__
);
241 result
= lv1_unmap_htab(htab_addr
);
245 ps3_mm_vas_destroy();
247 DBG(" <- %s:%d\n", __func__
, __LINE__
);
250 void __init
ps3_hpte_init(unsigned long htab_size
)
254 DBG(" -> %s:%d\n", __func__
, __LINE__
);
256 ppc_md
.hpte_invalidate
= ps3_hpte_invalidate
;
257 ppc_md
.hpte_updatepp
= ps3_hpte_updatepp
;
258 ppc_md
.hpte_updateboltedpp
= ps3_hpte_updateboltedpp
;
259 ppc_md
.hpte_insert
= ps3_hpte_insert
;
260 ppc_md
.hpte_remove
= ps3_hpte_remove
;
261 ppc_md
.hpte_clear_all
= ps3_hpte_clear
;
263 ppc64_pft_size
= __ilog2(htab_size
);
265 bitmap_size
= htab_size
/ sizeof(struct hash_pte
) / 8;
267 bolttab
= __va(lmb_alloc(bitmap_size
, 1));
268 inusetab
= __va(lmb_alloc(bitmap_size
, 1));
270 memset(bolttab
, 0, bitmap_size
);
271 memset(inusetab
, 0, bitmap_size
);
273 DBG(" <- %s:%d\n", __func__
, __LINE__
);
276 void __init
ps3_map_htab(void)
279 unsigned long htab_size
= (1UL << ppc64_pft_size
);
281 result
= lv1_map_htab(0, &htab_addr
);
283 htab
= (__force
struct hash_pte
*)ioremap_flags(htab_addr
, htab_size
,
284 pgprot_val(PAGE_READONLY_X
));
286 DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__
, __LINE__
,
287 htab_addr
, (unsigned long)htab
);