aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2005-09-27 12:28:45 -0400
committerStephen Rothwell <sfr@canb.auug.org.au>2005-09-27 12:28:45 -0400
commite508f438e0c152dcd1fbec5104e9c0ee28f352d4 (patch)
treebf67e0848e8ec5c5c255a8223550e9970cbdc29d /arch/powerpc
parentcb5c7980ab16c461a883ec7899675be57798d285 (diff)
powerpc: Move iSeries_htab.c to powerpc/platforms/iseries
And rename it to htab.c Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/iseries/Makefile2
-rw-r--r--arch/powerpc/platforms/iseries/htab.c256
2 files changed, 257 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index 0bd671573c87..4ef588c1b606 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -1,2 +1,2 @@
1obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \ 1obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \
2 hvcall.o proc.o 2 hvcall.o proc.o htab.o
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
new file mode 100644
index 000000000000..431b22767d06
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/htab.c
@@ -0,0 +1,256 @@
1/*
2 * iSeries hashtable management.
3 * Derived from pSeries_htab.c
4 *
5 * SMP scalability work:
6 * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <asm/machdep.h>
14#include <asm/pgtable.h>
15#include <asm/mmu.h>
16#include <asm/mmu_context.h>
17#include <asm/iSeries/HvCallHpt.h>
18#include <asm/abs_addr.h>
19#include <linux/spinlock.h>
20
21static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp =
22 { [0 ... 63] = SPIN_LOCK_UNLOCKED};
23
24/*
25 * Very primitive algorithm for picking up a lock
26 */
27static inline void iSeries_hlock(unsigned long slot)
28{
29 if (slot & 0x8)
30 slot = ~slot;
31 spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
32}
33
34static inline void iSeries_hunlock(unsigned long slot)
35{
36 if (slot & 0x8)
37 slot = ~slot;
38 spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
39}
40
41static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
42 unsigned long prpn, unsigned long vflags,
43 unsigned long rflags)
44{
45 unsigned long arpn;
46 long slot;
47 hpte_t lhpte;
48 int secondary = 0;
49
50 /*
51 * The hypervisor tries both primary and secondary.
52 * If we are being called to insert in the secondary,
53 * it means we have already tried both primary and secondary,
54 * so we return failure immediately.
55 */
56 if (vflags & HPTE_V_SECONDARY)
57 return -1;
58
59 iSeries_hlock(hpte_group);
60
61 slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT);
62 BUG_ON(lhpte.v & HPTE_V_VALID);
63
64 if (slot == -1) { /* No available entry found in either group */
65 iSeries_hunlock(hpte_group);
66 return -1;
67 }
68
69 if (slot < 0) { /* MSB set means secondary group */
70 vflags |= HPTE_V_VALID;
71 secondary = 1;
72 slot &= 0x7fffffffffffffff;
73 }
74
75 arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT;
76
77 lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID;
78 lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags;
79
80 /* Now fill in the actual HPTE */
81 HvCallHpt_addValidate(slot, secondary, &lhpte);
82
83 iSeries_hunlock(hpte_group);
84
85 return (secondary << 3) | (slot & 7);
86}
87
88long iSeries_hpte_bolt_or_insert(unsigned long hpte_group,
89 unsigned long va, unsigned long prpn, unsigned long vflags,
90 unsigned long rflags)
91{
92 long slot;
93 hpte_t lhpte;
94
95 slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT);
96
97 if (lhpte.v & HPTE_V_VALID) {
98 /* Bolt the existing HPTE */
99 HvCallHpt_setSwBits(slot, 0x10, 0);
100 HvCallHpt_setPp(slot, PP_RWXX);
101 return 0;
102 }
103
104 return iSeries_hpte_insert(hpte_group, va, prpn, vflags, rflags);
105}
106
107static unsigned long iSeries_hpte_getword0(unsigned long slot)
108{
109 hpte_t hpte;
110
111 HvCallHpt_get(&hpte, slot);
112 return hpte.v;
113}
114
115static long iSeries_hpte_remove(unsigned long hpte_group)
116{
117 unsigned long slot_offset;
118 int i;
119 unsigned long hpte_v;
120
121 /* Pick a random slot to start at */
122 slot_offset = mftb() & 0x7;
123
124 iSeries_hlock(hpte_group);
125
126 for (i = 0; i < HPTES_PER_GROUP; i++) {
127 hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);
128
129 if (! (hpte_v & HPTE_V_BOLTED)) {
130 HvCallHpt_invalidateSetSwBitsGet(hpte_group +
131 slot_offset, 0, 0);
132 iSeries_hunlock(hpte_group);
133 return i;
134 }
135
136 slot_offset++;
137 slot_offset &= 0x7;
138 }
139
140 iSeries_hunlock(hpte_group);
141
142 return -1;
143}
144
145/*
146 * The HyperVisor expects the "flags" argument in this form:
147 * bits 0..59 : reserved
148 * bit 60 : N
149 * bits 61..63 : PP2,PP1,PP0
150 */
151static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
152 unsigned long va, int large, int local)
153{
154 hpte_t hpte;
155 unsigned long avpn = va >> 23;
156
157 iSeries_hlock(slot);
158
159 HvCallHpt_get(&hpte, slot);
160 if ((HPTE_V_AVPN_VAL(hpte.v) == avpn) && (hpte.v & HPTE_V_VALID)) {
161 /*
162 * Hypervisor expects bits as NPPP, which is
163 * different from how they are mapped in our PP.
164 */
165 HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));
166 iSeries_hunlock(slot);
167 return 0;
168 }
169 iSeries_hunlock(slot);
170
171 return -1;
172}
173
174/*
175 * Functions used to find the PTE for a particular virtual address.
176 * Only used during boot when bolting pages.
177 *
178 * Input : vpn : virtual page number
179 * Output: PTE index within the page table of the entry
180 * -1 on failure
181 */
182static long iSeries_hpte_find(unsigned long vpn)
183{
184 hpte_t hpte;
185 long slot;
186
187 /*
188 * The HvCallHpt_findValid interface is as follows:
189 * 0xffffffffffffffff : No entry found.
190 * 0x00000000xxxxxxxx : Entry found in primary group, slot x
191 * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
192 */
193 slot = HvCallHpt_findValid(&hpte, vpn);
194 if (hpte.v & HPTE_V_VALID) {
195 if (slot < 0) {
196 slot &= 0x7fffffffffffffff;
197 slot = -slot;
198 }
199 } else
200 slot = -1;
201 return slot;
202}
203
204/*
205 * Update the page protection bits. Intended to be used to create
206 * guard pages for kernel data structures on pages which are bolted
207 * in the HPT. Assumes pages being operated on will not be stolen.
208 * Does not work on large pages.
209 *
210 * No need to lock here because we should be the only user.
211 */
212static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
213{
214 unsigned long vsid,va,vpn;
215 long slot;
216
217 vsid = get_kernel_vsid(ea);
218 va = (vsid << 28) | (ea & 0x0fffffff);
219 vpn = va >> PAGE_SHIFT;
220 slot = iSeries_hpte_find(vpn);
221 if (slot == -1)
222 panic("updateboltedpp: Could not find page to bolt\n");
223 HvCallHpt_setPp(slot, newpp);
224}
225
226static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
227 int large, int local)
228{
229 unsigned long hpte_v;
230 unsigned long avpn = va >> 23;
231 unsigned long flags;
232
233 local_irq_save(flags);
234
235 iSeries_hlock(slot);
236
237 hpte_v = iSeries_hpte_getword0(slot);
238
239 if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))
240 HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
241
242 iSeries_hunlock(slot);
243
244 local_irq_restore(flags);
245}
246
247void hpte_init_iSeries(void)
248{
249 ppc_md.hpte_invalidate = iSeries_hpte_invalidate;
250 ppc_md.hpte_updatepp = iSeries_hpte_updatepp;
251 ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
252 ppc_md.hpte_insert = iSeries_hpte_insert;
253 ppc_md.hpte_remove = iSeries_hpte_remove;
254
255 htab_finish_init();
256}