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