From 9ec5ff4e577c2c06b8a839f090761f55fa70fab8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 9 Jan 2018 10:09:57 +0100 Subject: 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. --- .../lib/libbsp/powerpc/qoriq/startup/mmu-config.c | 128 +++++++++++++++++++-- c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c | 98 +++++++++++----- 2 files changed, 188 insertions(+), 38 deletions(-) (limited to 'c/src/lib/libbsp/powerpc/qoriq') diff --git a/c/src/lib/libbsp/powerpc/qoriq/startup/mmu-config.c b/c/src/lib/libbsp/powerpc/qoriq/startup/mmu-config.c index 90b0534fa3..91a6240e10 100644 --- a/c/src/lib/libbsp/powerpc/qoriq/startup/mmu-config.c +++ b/c/src/lib/libbsp/powerpc/qoriq/startup/mmu-config.c @@ -7,7 +7,7 @@ */ /* - * Copyright (c) 2011, 2017 embedded brains GmbH. All rights reserved. + * Copyright (c) 2011, 2018 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -150,9 +150,103 @@ static entry DATA config[] = { static DATA char memory_path[] = "/memory"; -static void TEXT config_fdt_adjust(void) +#ifdef QORIQ_IS_HYPERVISOR_GUEST +static void TEXT add_dpaa_bqman_portals( + qoriq_mmu_context *context, + const void *fdt, + const char *compatible +) +{ + int node; + + node = -1; + + while (true) { + const void *val; + int len; + uintptr_t paddr; + uintptr_t size; + + node = fdt_node_offset_by_compatible(fdt, node, compatible); + if (node < 0) { + break; + } + + val = fdt_getprop(fdt, node, "reg", &len); + if (len != 32) { + continue; + } + + paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]); + size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]); + + qoriq_mmu_add( + context, + paddr, + paddr + size - 1, + 0, + FSL_EIS_MAS2_M | FSL_EIS_MAS2_G, + FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, + QORIQ_MMU_DEVICE_MAS7 + ); + + paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]); + size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[3]); + + qoriq_mmu_add( + context, + paddr, + paddr + size - 1, + 0, + FSL_EIS_MAS2_I | FSL_EIS_MAS2_G, + FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, + QORIQ_MMU_DEVICE_MAS7 + ); + } +} + +static void TEXT add_dpaa_bpool(qoriq_mmu_context *context, const void *fdt) +{ + int node; + + node = -1; + + while (true) { + const void *val; + int len; + uintptr_t config_count; + uintptr_t size; + uintptr_t paddr; + + node = fdt_node_offset_by_compatible(fdt, node, "fsl,bpool"); + if (node < 0) { + break; + } + + val = fdt_getprop(fdt, node, "fsl,bpool-ethernet-cfg", &len); + if (len != 24) { + continue; + } + + config_count = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[0]); + size = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[1]); + paddr = (uintptr_t) fdt64_to_cpu(((fdt64_t *) val)[2]); + + qoriq_mmu_add( + context, + paddr, + paddr + config_count * size - 1, + 0, + FSL_EIS_MAS2_M, + FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW, + 0 + ); + } +} +#endif + +static void TEXT config_fdt_adjust(const void *fdt) { - const void *fdt = bsp_fdt_get(); int node; node = fdt_path_offset_namelen( @@ -198,13 +292,9 @@ static void TEXT config_fdt_adjust(void) void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb) { qoriq_mmu_context context; - int i = 0; - - if (boot_processor) { - config_fdt_adjust(); - } - - qoriq_mmu_context_init(&context); + const void *fdt; + int max_count; + int i; for (i = 0; i < QORIQ_TLB1_ENTRY_COUNT; ++i) { if (i != scratch_tlb) { @@ -212,6 +302,22 @@ void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb) } } + fdt = bsp_fdt_get(); + qoriq_mmu_context_init(&context); + +#ifdef QORIQ_IS_HYPERVISOR_GUEST + add_dpaa_bqman_portals(&context, fdt, "fsl,bman-portal"); + add_dpaa_bqman_portals(&context, fdt, "fsl,qman-portal"); + add_dpaa_bpool(&context, fdt); + max_count = QORIQ_TLB1_ENTRY_COUNT - 1; +#else + max_count = (3 * QORIQ_TLB1_ENTRY_COUNT) / 4; +#endif + + if (boot_processor) { + config_fdt_adjust(fdt); + } + for (i = 0; i < (int) (sizeof(config) / sizeof(config [0])); ++i) { const entry *cur = &config [i]; if (cur->size > 0) { @@ -227,7 +333,7 @@ void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb) } } - qoriq_mmu_partition(&context, (3 * QORIQ_TLB1_ENTRY_COUNT) / 4); + qoriq_mmu_partition(&context, max_count); qoriq_mmu_write_to_tlb1(&context, first_tlb); } diff --git a/c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c b/c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c index 12dcc71f50..2629c9f999 100644 --- a/c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c +++ b/c/src/lib/libbsp/powerpc/qoriq/startup/mmu.c @@ -7,7 +7,7 @@ */ /* - * Copyright (c) 2011-2015 embedded brains GmbH. All rights reserved. + * Copyright (c) 2011, 2018 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -84,31 +84,17 @@ static void TEXT sort(qoriq_mmu_context *self) } } -static bool TEXT mas_equal(const qoriq_mmu_entry *a, const qoriq_mmu_entry *b) +static bool TEXT mas_compatible(const qoriq_mmu_entry *a, const qoriq_mmu_entry *b) { - return a->mas1 == b->mas1 && a->mas2 == b->mas2 && a->mas3 == b->mas3; + uint32_t m = FSL_EIS_MAS2_M; + + return (a->mas2 & ~m) == (b->mas2 & ~m); } static bool TEXT can_merge(const qoriq_mmu_entry *prev, const qoriq_mmu_entry *cur) { - bool can = false; - - if (prev->begin == cur->begin || prev->last >= cur->begin - 1) { - /* - * Here we can technically merge. We need a heuristic to - * prevent merges in case the MAS values differ and the boarder - * is reasonably well aligned. - */ - if ( - mas_equal(prev, cur) - || prev->last != cur->begin - 1 - || power_of_two(cur->begin) < 24 - ) { - can = true; - } - } - - return can; + return mas_compatible(prev, cur) + && (prev->begin == cur->begin || prev->last >= cur->begin - 1); } static void TEXT merge(qoriq_mmu_context *self) @@ -130,7 +116,7 @@ static void TEXT merge(qoriq_mmu_context *self) if (cur->last > prev->last) { prev->last = cur->last; - } + } for (j = i + 1; j < n; ++j) { entries [j - 1] = entries [j]; @@ -150,16 +136,72 @@ static void TEXT compact(qoriq_mmu_context *self) merge(self); } +static bool TEXT can_expand_down( + const qoriq_mmu_context *self, + const qoriq_mmu_entry *cur, + int i, + uintptr_t new_begin +) +{ + int j; + + for (j = 0; j < i; ++j) { + const qoriq_mmu_entry *before = &self->entries[j]; + + if ( + before->begin <= new_begin + && new_begin <= before->last + && !mas_compatible(before, cur) + ) { + return false; + } + } + + return true; +} + +static bool TEXT can_expand_up( + const qoriq_mmu_context *self, + const qoriq_mmu_entry *cur, + int i, + int n, + uintptr_t new_last +) +{ + int j; + + for (j = i + 1; j < n; ++j) { + const qoriq_mmu_entry *after = &self->entries[j]; + + if ( + after->begin <= new_last + && new_last <= after->last + && !mas_compatible(after, cur) + ) { + return false; + } + } + + return true; +} + static void TEXT align(qoriq_mmu_context *self, uintptr_t alignment) { - qoriq_mmu_entry *entries = self->entries; int n = self->count; - int i = 0; + int i; for (i = 0; i < n; ++i) { - qoriq_mmu_entry *cur = &entries [i]; - cur->begin &= ~(alignment - 1); - cur->last = alignment + (cur->last & ~(alignment - 1)) - 1; + qoriq_mmu_entry *cur = &self->entries[i]; + uintptr_t new_begin = cur->begin & ~(alignment - 1); + uintptr_t new_last = alignment + (cur->last & ~(alignment - 1)) - 1; + + if ( + can_expand_down(self, cur, i, new_begin) + && can_expand_up(self, cur, i, n, new_last) + ) { + cur->begin = new_begin; + cur->last = new_last; + } } } @@ -265,6 +307,8 @@ void TEXT qoriq_mmu_partition(qoriq_mmu_context *self, int max_count) { uintptr_t alignment = 4096; + sort(self); + do { align(self, alignment); partition(self); -- cgit v1.2.3