Commit | Line | Data |
---|---|---|
c6cec72b GL |
1 | /* |
2 | * PS3 pagetable management routines. | |
3 | * | |
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | |
36dff96b | 5 | * Copyright 2006, 2007 Sony Corporation |
c6cec72b GL |
6 | * |
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. | |
10 | * | |
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. | |
15 | * | |
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 | |
19 | */ | |
20 | ||
21 | #include <linux/kernel.h> | |
95f72d1e | 22 | #include <linux/memblock.h> |
c6cec72b GL |
23 | |
24 | #include <asm/machdep.h> | |
d9b2b2a2 | 25 | #include <asm/prom.h> |
c6cec72b | 26 | #include <asm/udbg.h> |
c6cec72b | 27 | #include <asm/lv1call.h> |
36dff96b | 28 | #include <asm/ps3fb.h> |
c6cec72b | 29 | |
97db7f7d | 30 | #define PS3_VERBOSE_RESULT |
c6cec72b GL |
31 | #include "platform.h" |
32 | ||
9cfeb74e MM |
33 | /** |
34 | * enum lpar_vas_id - id of LPAR virtual address space. | |
35 | * @lpar_vas_id_current: Current selected virtual address space | |
36 | * | |
37 | * Identify the target LPAR address space. | |
38 | */ | |
39 | ||
40 | enum ps3_lpar_vas_id { | |
41 | PS3_LPAR_VAS_ID_CURRENT = 0, | |
42 | }; | |
43 | ||
44 | ||
45 | static DEFINE_SPINLOCK(ps3_htab_lock); | |
c6cec72b | 46 | |
5524a27d | 47 | static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn, |
1189be65 | 48 | unsigned long pa, unsigned long rflags, unsigned long vflags, |
b1022fbd | 49 | int psize, int apsize, int ssize) |
c6cec72b | 50 | { |
9cfeb74e MM |
51 | int result; |
52 | u64 hpte_v, hpte_r; | |
53 | u64 inserted_index; | |
54 | u64 evicted_v, evicted_r; | |
55 | u64 hpte_v_array[4], hpte_rs; | |
c6cec72b | 56 | unsigned long flags; |
9cfeb74e | 57 | long ret = -1; |
c6cec72b | 58 | |
9cfeb74e MM |
59 | /* |
60 | * lv1_insert_htab_entry() will search for victim | |
61 | * entry in both primary and secondary pte group | |
62 | */ | |
63 | vflags &= ~HPTE_V_SECONDARY; | |
c6cec72b | 64 | |
b1022fbd | 65 | hpte_v = hpte_encode_v(vpn, psize, apsize, ssize) | vflags | HPTE_V_VALID; |
50de596d | 66 | hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize, apsize, ssize) | rflags; |
c6cec72b | 67 | |
9cfeb74e | 68 | spin_lock_irqsave(&ps3_htab_lock, flags); |
c6cec72b | 69 | |
9cfeb74e MM |
70 | /* talk hvc to replace entries BOLTED == 0 */ |
71 | result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group, | |
72 | hpte_v, hpte_r, | |
73 | HPTE_V_BOLTED, 0, | |
74 | &inserted_index, | |
75 | &evicted_v, &evicted_r); | |
c6cec72b GL |
76 | |
77 | if (result) { | |
9cfeb74e | 78 | /* all entries bolted !*/ |
97db7f7d GL |
79 | pr_info("%s:result=%s vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n", |
80 | __func__, ps3_result(result), vpn, pa, hpte_group, | |
81 | hpte_v, hpte_r); | |
c6cec72b GL |
82 | BUG(); |
83 | } | |
84 | ||
85 | /* | |
9cfeb74e | 86 | * see if the entry is inserted into secondary pteg |
c6cec72b | 87 | */ |
9cfeb74e MM |
88 | result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, |
89 | inserted_index & ~0x3UL, | |
90 | &hpte_v_array[0], &hpte_v_array[1], | |
91 | &hpte_v_array[2], &hpte_v_array[3], | |
92 | &hpte_rs); | |
93 | BUG_ON(result); | |
c6cec72b | 94 | |
9cfeb74e MM |
95 | if (hpte_v_array[inserted_index % 4] & HPTE_V_SECONDARY) |
96 | ret = (inserted_index & 7) | (1 << 3); | |
97 | else | |
98 | ret = inserted_index & 7; | |
c6cec72b | 99 | |
9cfeb74e | 100 | spin_unlock_irqrestore(&ps3_htab_lock, flags); |
c6cec72b | 101 | |
9cfeb74e | 102 | return ret; |
c6cec72b GL |
103 | } |
104 | ||
105 | static long ps3_hpte_remove(unsigned long hpte_group) | |
106 | { | |
107 | panic("ps3_hpte_remove() not implemented"); | |
108 | return 0; | |
109 | } | |
110 | ||
111 | static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, | |
db3d8534 | 112 | unsigned long vpn, int psize, int apsize, |
aefa5688 | 113 | int ssize, unsigned long inv_flags) |
c6cec72b | 114 | { |
9cfeb74e MM |
115 | int result; |
116 | u64 hpte_v, want_v, hpte_rs; | |
117 | u64 hpte_v_array[4]; | |
c6cec72b | 118 | unsigned long flags; |
9cfeb74e | 119 | long ret; |
c6cec72b | 120 | |
74f227b2 | 121 | want_v = hpte_encode_avpn(vpn, psize, ssize); |
c6cec72b | 122 | |
9cfeb74e | 123 | spin_lock_irqsave(&ps3_htab_lock, flags); |
c6cec72b | 124 | |
9cfeb74e MM |
125 | result = lv1_read_htab_entries(PS3_LPAR_VAS_ID_CURRENT, slot & ~0x3UL, |
126 | &hpte_v_array[0], &hpte_v_array[1], | |
127 | &hpte_v_array[2], &hpte_v_array[3], | |
128 | &hpte_rs); | |
c6cec72b GL |
129 | |
130 | if (result) { | |
97db7f7d GL |
131 | pr_info("%s: result=%s read vpn=%lx slot=%lx psize=%d\n", |
132 | __func__, ps3_result(result), vpn, slot, psize); | |
c6cec72b GL |
133 | BUG(); |
134 | } | |
135 | ||
9cfeb74e | 136 | hpte_v = hpte_v_array[slot % 4]; |
c6cec72b | 137 | |
9cfeb74e MM |
138 | /* |
139 | * As lv1_read_htab_entries() does not give us the RPN, we can | |
140 | * not synthesize the new hpte_r value here, and therefore can | |
141 | * not update the hpte with lv1_insert_htab_entry(), so we | |
fd0961ff | 142 | * instead invalidate it and ask the caller to update it via |
9cfeb74e MM |
143 | * ps3_hpte_insert() by returning a -1 value. |
144 | */ | |
145 | if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) { | |
146 | /* not found */ | |
147 | ret = -1; | |
148 | } else { | |
149 | /* entry found, just invalidate it */ | |
150 | result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, | |
151 | slot, 0, 0); | |
152 | ret = -1; | |
153 | } | |
c6cec72b | 154 | |
9cfeb74e MM |
155 | spin_unlock_irqrestore(&ps3_htab_lock, flags); |
156 | return ret; | |
c6cec72b GL |
157 | } |
158 | ||
159 | static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, | |
1189be65 | 160 | int psize, int ssize) |
c6cec72b GL |
161 | { |
162 | panic("ps3_hpte_updateboltedpp() not implemented"); | |
163 | } | |
164 | ||
5524a27d | 165 | static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn, |
db3d8534 | 166 | int psize, int apsize, int ssize, int local) |
c6cec72b GL |
167 | { |
168 | unsigned long flags; | |
9cfeb74e MM |
169 | int result; |
170 | ||
171 | spin_lock_irqsave(&ps3_htab_lock, flags); | |
c6cec72b | 172 | |
9cfeb74e | 173 | result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0); |
c6cec72b GL |
174 | |
175 | if (result) { | |
97db7f7d GL |
176 | pr_info("%s: result=%s vpn=%lx slot=%lx psize=%d\n", |
177 | __func__, ps3_result(result), vpn, slot, psize); | |
c6cec72b GL |
178 | BUG(); |
179 | } | |
180 | ||
9cfeb74e | 181 | spin_unlock_irqrestore(&ps3_htab_lock, flags); |
c6cec72b GL |
182 | } |
183 | ||
184 | static void ps3_hpte_clear(void) | |
185 | { | |
9cfeb74e MM |
186 | unsigned long hpte_count = (1UL << ppc64_pft_size) >> 4; |
187 | u64 i; | |
9263e85a | 188 | |
9cfeb74e MM |
189 | for (i = 0; i < hpte_count; i++) |
190 | lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, i, 0, 0); | |
9263e85a GL |
191 | |
192 | ps3_mm_shutdown(); | |
193 | ps3_mm_vas_destroy(); | |
c6cec72b GL |
194 | } |
195 | ||
196 | void __init ps3_hpte_init(unsigned long htab_size) | |
197 | { | |
7025776e BH |
198 | mmu_hash_ops.hpte_invalidate = ps3_hpte_invalidate; |
199 | mmu_hash_ops.hpte_updatepp = ps3_hpte_updatepp; | |
200 | mmu_hash_ops.hpte_updateboltedpp = ps3_hpte_updateboltedpp; | |
201 | mmu_hash_ops.hpte_insert = ps3_hpte_insert; | |
202 | mmu_hash_ops.hpte_remove = ps3_hpte_remove; | |
203 | mmu_hash_ops.hpte_clear_all = ps3_hpte_clear; | |
c6cec72b GL |
204 | |
205 | ppc64_pft_size = __ilog2(htab_size); | |
c6cec72b GL |
206 | } |
207 |