File indexing completed on 2025-05-11 08:23:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <bsp/mmu.h>
0037 #include <libcpu/powerpc-utility.h>
0038
0039 #define TEXT __attribute__((section(".bsp_start_text")))
0040
0041 static uintptr_t TEXT power_of_two(uintptr_t val)
0042 {
0043 uintptr_t test_power = QORIQ_MMU_MIN_POWER;
0044 uintptr_t power = test_power;
0045 uintptr_t alignment = 1U << test_power;
0046
0047 while (test_power <= QORIQ_MMU_MAX_POWER && (val & (alignment - 1)) == 0) {
0048 power = test_power;
0049 alignment <<= QORIQ_MMU_POWER_STEP;
0050 test_power += QORIQ_MMU_POWER_STEP;
0051 }
0052
0053 return power;
0054 }
0055
0056 static uintptr_t TEXT max_power_of_two(uintptr_t val)
0057 {
0058 uintptr_t test_power = QORIQ_MMU_MIN_POWER;
0059 uintptr_t power = test_power;
0060 uintptr_t max = 1U << test_power;
0061
0062 do {
0063 power = test_power;
0064 max <<= QORIQ_MMU_POWER_STEP;
0065 test_power += QORIQ_MMU_POWER_STEP;
0066 } while (test_power <= QORIQ_MMU_MAX_POWER && max <= val);
0067
0068 return power;
0069 }
0070
0071 void TEXT qoriq_mmu_context_init(qoriq_mmu_context *self)
0072 {
0073 int *cur = (int *) self;
0074 const int *end = cur + sizeof(*self) / sizeof(*cur);
0075
0076 while (cur != end) {
0077 *cur = 0;
0078 ++cur;
0079 }
0080 }
0081
0082 static void TEXT sort(qoriq_mmu_context *self)
0083 {
0084 qoriq_mmu_entry *entries = self->entries;
0085 int n = self->count;
0086 int i = 0;
0087
0088 for (i = 1; i < n; ++i) {
0089 qoriq_mmu_entry key = entries [i];
0090 int j = 0;
0091
0092 for (j = i - 1; j >= 0 && entries [j].begin > key.begin; --j) {
0093 entries [j + 1] = entries [j];
0094 }
0095
0096 entries [j + 1] = key;
0097 }
0098 }
0099
0100 static bool TEXT mas_compatible(const qoriq_mmu_entry *a, const qoriq_mmu_entry *b)
0101 {
0102 uint32_t m = FSL_EIS_MAS2_M;
0103
0104 return (a->mas2 & ~m) == (b->mas2 & ~m);
0105 }
0106
0107 static bool TEXT can_merge(const qoriq_mmu_entry *prev, const qoriq_mmu_entry *cur)
0108 {
0109 return mas_compatible(prev, cur)
0110 && (prev->begin == cur->begin || prev->last >= cur->begin - 1);
0111 }
0112
0113 static void TEXT merge(qoriq_mmu_context *self)
0114 {
0115 qoriq_mmu_entry *entries = self->entries;
0116 int n = self->count;
0117 int i = 0;
0118
0119 for (i = 1; i < n; ++i) {
0120 qoriq_mmu_entry *prev = &entries [i - 1];
0121 qoriq_mmu_entry *cur = &entries [i];
0122
0123 if (can_merge(prev, cur)) {
0124 int j = 0;
0125
0126 prev->mas1 |= cur->mas1;
0127 prev->mas2 |= cur->mas2;
0128 prev->mas3 |= cur->mas3;
0129
0130 if (cur->last > prev->last) {
0131 prev->last = cur->last;
0132 }
0133
0134 for (j = i + 1; j < n; ++j) {
0135 entries [j - 1] = entries [j];
0136 }
0137
0138 --i;
0139 --n;
0140 }
0141 }
0142
0143 self->count = n;
0144 }
0145
0146 static void TEXT compact(qoriq_mmu_context *self)
0147 {
0148 sort(self);
0149 merge(self);
0150 }
0151
0152 static bool TEXT can_expand_down(
0153 const qoriq_mmu_context *self,
0154 const qoriq_mmu_entry *cur,
0155 int i,
0156 uintptr_t new_begin
0157 )
0158 {
0159 int j;
0160
0161 for (j = 0; j < i; ++j) {
0162 const qoriq_mmu_entry *before = &self->entries[j];
0163
0164 if (
0165 before->begin <= new_begin
0166 && new_begin <= before->last
0167 && !mas_compatible(before, cur)
0168 ) {
0169 return false;
0170 }
0171 }
0172
0173 return true;
0174 }
0175
0176 static bool TEXT can_expand_up(
0177 const qoriq_mmu_context *self,
0178 const qoriq_mmu_entry *cur,
0179 int i,
0180 int n,
0181 uintptr_t new_last
0182 )
0183 {
0184 int j;
0185
0186 for (j = i + 1; j < n; ++j) {
0187 const qoriq_mmu_entry *after = &self->entries[j];
0188
0189 if (
0190 after->begin <= new_last
0191 && new_last <= after->last
0192 && !mas_compatible(after, cur)
0193 ) {
0194 return false;
0195 }
0196 }
0197
0198 return true;
0199 }
0200
0201 static void TEXT align(qoriq_mmu_context *self, uintptr_t alignment)
0202 {
0203 int n = self->count;
0204 int i;
0205
0206 for (i = 0; i < n; ++i) {
0207 qoriq_mmu_entry *cur = &self->entries[i];
0208 uintptr_t new_begin = cur->begin & ~(alignment - 1);
0209 uintptr_t new_last = alignment + (cur->last & ~(alignment - 1)) - 1;
0210
0211 if (
0212 can_expand_down(self, cur, i, new_begin)
0213 && can_expand_up(self, cur, i, n, new_last)
0214 ) {
0215 cur->begin = new_begin;
0216 cur->last = new_last;
0217 }
0218 }
0219 }
0220
0221 static bool TEXT is_full(qoriq_mmu_context *self)
0222 {
0223 return self->count >= QORIQ_TLB1_ENTRY_COUNT;
0224 }
0225
0226 static void TEXT append(qoriq_mmu_context *self, const qoriq_mmu_entry *new_entry)
0227 {
0228 self->entries [self->count] = *new_entry;
0229 ++self->count;
0230 }
0231
0232 bool TEXT qoriq_mmu_add(
0233 qoriq_mmu_context *self,
0234 uintptr_t begin,
0235 uintptr_t last,
0236 uint32_t mas1,
0237 uint32_t mas2,
0238 uint32_t mas3,
0239 uint32_t mas7
0240 )
0241 {
0242 bool ok = true;
0243
0244 if (is_full(self)) {
0245 compact(self);
0246 }
0247
0248 if (!is_full(self)) {
0249 if (begin < last) {
0250 qoriq_mmu_entry new_entry = {
0251 .begin = begin,
0252 .last = last,
0253 .mas1 = mas1,
0254 .mas2 = mas2,
0255 .mas3 = mas3,
0256 .mas7 = mas7
0257 };
0258 append(self, &new_entry);
0259 } else {
0260 ok = false;
0261 }
0262 } else {
0263 ok = false;
0264 }
0265
0266 return ok;
0267 }
0268
0269 static uintptr_t TEXT min(uintptr_t a, uintptr_t b)
0270 {
0271 return a < b ? a : b;
0272 }
0273
0274 static bool TEXT split(qoriq_mmu_context *self, qoriq_mmu_entry *cur)
0275 {
0276 bool again = false;
0277 uintptr_t begin = cur->begin;
0278 uintptr_t end = cur->last + 1;
0279 uintptr_t size = end - begin;
0280 uintptr_t begin_power = power_of_two(begin);
0281 uintptr_t size_power = max_power_of_two(size);
0282 uintptr_t power = min(begin_power, size_power);
0283 uintptr_t split_size = power < 32 ? (1U << power) : 0;
0284 uintptr_t split_pos = begin + split_size;
0285
0286 if (split_pos != end && !is_full(self)) {
0287 qoriq_mmu_entry new_entry = *cur;
0288 cur->begin = split_pos;
0289 new_entry.last = split_pos - 1;
0290 append(self, &new_entry);
0291 again = true;
0292 }
0293
0294 return again;
0295 }
0296
0297 static void TEXT split_all(qoriq_mmu_context *self)
0298 {
0299 qoriq_mmu_entry *entries = self->entries;
0300 int n = self->count;
0301 int i = 0;
0302
0303 for (i = 0; i < n; ++i) {
0304 qoriq_mmu_entry *cur = &entries [i];
0305
0306 while (split(self, cur)) {
0307
0308 }
0309 }
0310 }
0311
0312 static TEXT void partition(qoriq_mmu_context *self)
0313 {
0314 compact(self);
0315 split_all(self);
0316 sort(self);
0317 }
0318
0319 void TEXT qoriq_mmu_partition(qoriq_mmu_context *self, int max_count)
0320 {
0321 uintptr_t alignment = 4096;
0322
0323 sort(self);
0324
0325 do {
0326 align(self, alignment);
0327 partition(self);
0328 alignment *= 4;
0329 } while (self->count > max_count);
0330 }
0331
0332 void TEXT qoriq_mmu_write_to_tlb1(qoriq_mmu_context *self, int first_tlb)
0333 {
0334 qoriq_mmu_entry *entries = self->entries;
0335 int n = self->count;
0336 int i = 0;
0337
0338 for (i = 0; i < n; ++i) {
0339 qoriq_mmu_entry *cur = &entries [i];
0340 uintptr_t ea = cur->begin;
0341 uintptr_t size = cur->last - ea + 1;
0342 uintptr_t tsize = (power_of_two(size) - 10) / 2;
0343 int tlb = first_tlb + i;
0344
0345 qoriq_tlb1_write(
0346 tlb,
0347 cur->mas1,
0348 cur->mas2,
0349 cur->mas3,
0350 cur->mas7,
0351 ea,
0352 (int) tsize
0353 );
0354 }
0355 }
0356
0357 void qoriq_mmu_change_perm(uint32_t test, uint32_t set, uint32_t clear)
0358 {
0359 int i = 0;
0360
0361 for (i = 0; i < QORIQ_TLB1_ENTRY_COUNT; ++i) {
0362 uint32_t mas0 = FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(i);
0363 uint32_t mas1 = 0;
0364
0365 PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
0366 ppc_synchronize_instructions();
0367 ppc_tlbre();
0368 ppc_synchronize_instructions();
0369
0370 PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1, mas1);
0371 if ((mas1 & FSL_EIS_MAS1_V) != 0) {
0372 uint32_t mask = 0x3ff;
0373 uint32_t mas3;
0374 PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
0375
0376 if ((mas3 & mask) == test) {
0377 mas3 &= ~(clear & mask);
0378 mas3 |= set & mask;
0379 PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS3, mas3);
0380 ppc_msync();
0381 ppc_synchronize_instructions();
0382 ppc_tlbwe();
0383 ppc_synchronize_instructions();
0384 }
0385 }
0386 }
0387 }
0388
0389 int qoriq_mmu_find_free_tlb1_entry(void)
0390 {
0391 int i = 0;
0392
0393 for (i = 0; i < QORIQ_TLB1_ENTRY_COUNT; ++i) {
0394 uint32_t mas0 = FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(i);
0395 uint32_t mas1;
0396
0397 PPC_SET_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS0, mas0);
0398 ppc_synchronize_instructions();
0399 ppc_tlbre();
0400 ppc_synchronize_instructions();
0401
0402 PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_MAS1, mas1);
0403 if ((mas1 & FSL_EIS_MAS1_V) == 0) {
0404 return i;
0405 }
0406 }
0407
0408 return -1;
0409 }
0410
0411 void qoriq_mmu_adjust_and_write_to_tlb1(
0412 int tlb,
0413 uintptr_t begin,
0414 uintptr_t last,
0415 uint32_t mas1,
0416 uint32_t mas2,
0417 uint32_t mas3,
0418 uint32_t mas7
0419 )
0420 {
0421 qoriq_mmu_context context;
0422
0423 qoriq_mmu_context_init(&context);
0424 qoriq_mmu_add(
0425 &context,
0426 begin,
0427 last,
0428 mas1,
0429 mas2,
0430 mas3,
0431 mas7
0432 );
0433 qoriq_mmu_partition(&context, 1);
0434 qoriq_mmu_write_to_tlb1(&context, tlb);
0435 }