source: rtems/c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c @ 9ec5ff4e

5
Last change on this file since 9ec5ff4e was 9ec5ff4e, checked in by Sebastian Huber <sebastian.huber@…>, on 01/09/18 at 09:09:57

bsp/qoriq: Fix hypervisor guest MMU config

Account for DPAA resources defined in the device tree.

Prevent merging of areas with incompatible MAS2.

Update #3085.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup QorIQMMU
5 *
6 * @brief MMU implementation.
7 */
8
9/*
10 * Copyright (c) 2011, 2018 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <bsp/mmu.h>
24#include <libcpu/powerpc-utility.h>
25
26#define TEXT __attribute__((section(".bsp_start_text")))
27
28static uintptr_t TEXT power_of_two(uintptr_t val)
29{
30        uintptr_t test_power = QORIQ_MMU_MIN_POWER;
31        uintptr_t power = test_power;
32        uintptr_t alignment = 1U << test_power;
33
34        while (test_power <= QORIQ_MMU_MAX_POWER && (val & (alignment - 1)) == 0) {
35                power = test_power;
36                alignment <<= QORIQ_MMU_POWER_STEP;
37                test_power += QORIQ_MMU_POWER_STEP;
38        }
39
40        return power;
41}
42
43static uintptr_t TEXT max_power_of_two(uintptr_t val)
44{
45        uintptr_t test_power = QORIQ_MMU_MIN_POWER;
46        uintptr_t power = test_power;
47        uintptr_t max = 1U << test_power;
48
49        do {
50                power = test_power;
51                max <<= QORIQ_MMU_POWER_STEP;
52                test_power += QORIQ_MMU_POWER_STEP;
53        } while (test_power <= QORIQ_MMU_MAX_POWER && max <= val);
54
55        return power;
56}
57
58void TEXT qoriq_mmu_context_init(qoriq_mmu_context *self)
59{
60        int *cur = (int *) self;
61        const int *end = cur + sizeof(*self) / sizeof(*cur);
62
63        while (cur != end) {
64                *cur = 0;
65                ++cur;
66        }
67}
68
69static void TEXT sort(qoriq_mmu_context *self)
70{
71        qoriq_mmu_entry *entries = self->entries;
72        int n = self->count;
73        int i = 0;
74
75        for (i = 1; i < n; ++i) {
76                qoriq_mmu_entry key = entries [i];
77                int j = 0;
78
79                for (j = i - 1; j >= 0 && entries [j].begin > key.begin; --j) {
80                        entries [j + 1] = entries [j];
81                }
82
83                entries [j + 1] = key;
84        }
85}
86
87static bool TEXT mas_compatible(const qoriq_mmu_entry *a, const qoriq_mmu_entry *b)
88{
89        uint32_t m = FSL_EIS_MAS2_M;
90
91        return (a->mas2 & ~m) == (b->mas2 & ~m);
92}
93
94static bool TEXT can_merge(const qoriq_mmu_entry *prev, const qoriq_mmu_entry *cur)
95{
96        return mas_compatible(prev, cur)
97                && (prev->begin == cur->begin || prev->last >= cur->begin - 1);
98}
99
100static void TEXT merge(qoriq_mmu_context *self)
101{
102        qoriq_mmu_entry *entries = self->entries;
103        int n = self->count;
104        int i = 0;
105
106        for (i = 1; i < n; ++i) {
107                qoriq_mmu_entry *prev = &entries [i - 1];
108                qoriq_mmu_entry *cur = &entries [i];
109
110                if (can_merge(prev, cur)) {
111                        int j = 0;
112
113                        prev->mas1 |= cur->mas1;
114                        prev->mas2 |= cur->mas2;
115                        prev->mas3 |= cur->mas3;
116
117                        if (cur->last > prev->last) {
118                                prev->last = cur->last;
119                        }
120
121                        for (j = i + 1; j < n; ++j) {
122                                entries [j - 1] = entries [j];
123                        }
124
125                        --i;
126                        --n;
127                }
128        }
129
130        self->count = n;
131}
132
133static void TEXT compact(qoriq_mmu_context *self)
134{
135        sort(self);
136        merge(self);
137}
138
139static bool TEXT can_expand_down(
140        const qoriq_mmu_context *self,
141        const qoriq_mmu_entry *cur,
142        int i,
143        uintptr_t new_begin
144)
145{
146        int j;
147
148        for (j = 0; j < i; ++j) {
149                const qoriq_mmu_entry *before = &self->entries[j];
150
151                if (
152                        before->begin <= new_begin
153                                && new_begin <= before->last
154                                && !mas_compatible(before, cur)
155                ) {
156                        return false;
157                }
158        }
159
160        return true;
161}
162
163static bool TEXT can_expand_up(
164        const qoriq_mmu_context *self,
165        const qoriq_mmu_entry *cur,
166        int i,
167        int n,
168        uintptr_t new_last
169)
170{
171        int j;
172
173        for (j = i + 1; j < n; ++j) {
174                const qoriq_mmu_entry *after = &self->entries[j];
175
176                if (
177                        after->begin <= new_last
178                                && new_last <= after->last
179                                && !mas_compatible(after, cur)
180                ) {
181                        return false;
182                }
183        }
184
185        return true;
186}
187
188static void TEXT align(qoriq_mmu_context *self, uintptr_t alignment)
189{
190        int n = self->count;
191        int i;
192
193        for (i = 0; i < n; ++i) {
194                qoriq_mmu_entry *cur = &self->entries[i];
195                uintptr_t new_begin = cur->begin & ~(alignment - 1);
196                uintptr_t new_last = alignment + (cur->last & ~(alignment - 1)) - 1;
197
198                if (
199                        can_expand_down(self, cur, i, new_begin)
200                                && can_expand_up(self, cur, i, n, new_last)
201                ) {
202                        cur->begin = new_begin;
203                        cur->last = new_last;
204                }
205        }
206}
207
208static bool TEXT is_full(qoriq_mmu_context *self)
209{
210        return self->count >= QORIQ_TLB1_ENTRY_COUNT;
211}
212
213static void TEXT append(qoriq_mmu_context *self, const qoriq_mmu_entry *new_entry)
214{
215        self->entries [self->count] = *new_entry;
216        ++self->count;
217}
218
219bool TEXT qoriq_mmu_add(
220        qoriq_mmu_context *self,
221        uintptr_t begin,
222        uintptr_t last,
223        uint32_t mas1,
224        uint32_t mas2,
225        uint32_t mas3,
226        uint32_t mas7
227)
228{
229        bool ok = true;
230
231        if (is_full(self)) {
232                compact(self);
233        }
234
235        if (!is_full(self)) {
236                if (begin < last) {
237                        qoriq_mmu_entry new_entry = {
238                                .begin = begin,
239                                .last = last,
240                                .mas1 = mas1,
241                                .mas2 = mas2,
242                                .mas3 = mas3,
243                                .mas7 = mas7
244                        };
245                        append(self, &new_entry);
246                } else {
247                        ok = false;
248                }
249        } else {
250                ok = false;
251        }
252
253        return ok;
254}
255
256static uintptr_t TEXT min(uintptr_t a, uintptr_t b)
257{
258        return a < b ? a : b;
259}
260
261static bool TEXT split(qoriq_mmu_context *self, qoriq_mmu_entry *cur)
262{
263        bool again = false;
264        uintptr_t begin = cur->begin;
265        uintptr_t end = cur->last + 1;
266        uintptr_t size = end - begin;
267        uintptr_t begin_power = power_of_two(begin);
268        uintptr_t size_power = max_power_of_two(size);
269        uintptr_t power = min(begin_power, size_power);
270        uintptr_t split_size = power < 32 ? (1U << power) : 0;
271        uintptr_t split_pos = begin + split_size;
272
273        if (split_pos != end && !is_full(self)) {
274                qoriq_mmu_entry new_entry = *cur;
275                cur->begin = split_pos;
276                new_entry.last = split_pos - 1;
277                append(self, &new_entry);
278                again = true;
279        }
280
281        return again;
282}
283
284static void TEXT split_all(qoriq_mmu_context *self)
285{
286        qoriq_mmu_entry *entries = self->entries;
287        int n = self->count;
288        int i = 0;
289
290        for (i = 0; i < n; ++i) {
291                qoriq_mmu_entry *cur = &entries [i];
292
293                while (split(self, cur)) {
294                        /* Repeat */
295                }
296        }
297}
298
299static TEXT void partition(qoriq_mmu_context *self)
300{
301        compact(self);
302        split_all(self);
303        sort(self);
304}
305
306void TEXT qoriq_mmu_partition(qoriq_mmu_context *self, int max_count)
307{
308        uintptr_t alignment = 4096;
309
310        sort(self);
311
312        do {
313                align(self, alignment);
314                partition(self);
315                alignment *= 4;
316        } while (self->count > max_count);
317}
318
319void TEXT qoriq_mmu_write_to_tlb1(qoriq_mmu_context *self, int first_tlb)
320{
321        qoriq_mmu_entry *entries = self->entries;
322        int n = self->count;
323        int i = 0;
324
325        for (i = 0; i < n; ++i) {
326                qoriq_mmu_entry *cur = &entries [i];
327                uintptr_t ea = cur->begin;
328                uintptr_t size = cur->last - ea + 1;
329                uintptr_t tsize = (power_of_two(size) - 10) / 2;
330                int tlb = first_tlb + i;
331
332                qoriq_tlb1_write(
333                        tlb,
334                        cur->mas1,
335                        cur->mas2,
336                        cur->mas3,
337                        cur->mas7,
338                        ea,
339                        (int) tsize
340                );
341        }
342}
343
344void qoriq_mmu_change_perm(uint32_t test, uint32_t set, uint32_t clear)
345{
346        int i = 0;
347
348        for (i = 0; i < 16; ++i) {
349                uint32_t mas0 = FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(i);
350                uint32_t mas1 = 0;
351
352                PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
353                asm volatile ("tlbre");
354
355                mas1 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1);
356                if ((mas1 & FSL_EIS_MAS1_V) != 0) {
357                        uint32_t mask = 0x3ff;
358                        uint32_t mas3 = PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3);
359
360                        if ((mas3 & mask) == test) {
361                                mas3 &= ~(clear & mask);
362                                mas3 |= set & mask;
363                                PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
364                                asm volatile ("isync; msync; tlbwe; isync" : : : "memory");
365                        }
366                }
367        }
368}
Note: See TracBrowser for help on using the repository browser.