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