[coreboot-gerrit] Change in coreboot[master]: [WIP] cpu/x86/mtrr: Optimize hole carving strategy
Nico Huber (Code Review)
gerrit at coreboot.org
Sat Oct 7 16:49:31 CEST 2017
Nico Huber has uploaded this change for review. ( https://review.coreboot.org/21915
Change subject: [WIP] cpu/x86/mtrr: Optimize hole carving strategy
......................................................................
[WIP] cpu/x86/mtrr: Optimize hole carving strategy
For WB ranges with unaligned end, we try to align the range up and
carve a hole out of it which might reduce MTRR usage. Instead of
trying an arbitrary alignment, we choose an optimal one.
Change-Id: Iefb064ce8c4f293490a19dd46054b966c63bde44
Signed-off-by: Nico Huber <nico.h at gmx.de>
---
M src/cpu/x86/mtrr/mtrr.c
1 file changed, 84 insertions(+), 25 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/15/21915/1
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index c2c629c..82666fc 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -105,8 +105,6 @@
#define RANGE_TO_PHYS_ADDR(x) (((resource_t)(x)) << RANGE_SHIFT)
#define NUM_FIXED_MTRRS (NUM_FIXED_RANGES / RANGES_PER_FIXED_MTRR)
-/* The minimum alignment while handling variable MTRR ranges is 64MiB. */
-#define MTRR_MIN_ALIGN PHYS_TO_RANGE_ADDR(64 << 20)
/* Helpful constants. */
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
@@ -471,10 +469,63 @@
}
}
+static uint32_t optimize_var_mtrr_hole(const uint32_t base,
+ const uint32_t limit)
+{
+ /*
+ * With default type UC, we can potentially optimize a WB
+ * range with unaligned upper end, by aligning it up and
+ * carving the added "hole" out again.
+ *
+ * To optimize the upper end of the hole, we will predict
+ * how many MTRRs calc_var_mtrr_range() will spend for the
+ * hole and how many it will save us for the original range.
+ *
+ * We take two parameters, the upper end of the WB range as
+ * `base` of the hole and a `limit` how far we may align it
+ * up. As long as `base` is unaligned, calc_var_mtrr_range()
+ * would add MTRRs of the size of lowest significant bit set
+ * in `base` and add that size to `base`.
+ *
+ * We don't have to exercise all these additions. As we know
+ * the next MTRR to set will be at the position the carry of
+ * last addition takes. That is the closest 0 in a more sig-
+ * nificant position. So we account one MTRR for the least
+ * signifcant bit set in `base` plus one for each unset bit
+ * up to the new alignment.
+ *
+ * OTOH, for every bit that is flipped to zero in `base` due
+ * to the alignment, we save one MTRR for the original WB
+ * range. Minus one for the final carry bit.
+ */
+
+ int gain = -2; /* Minus one for the first addition and
+ minus one for the final carry bit. */
+ int best_gain = 0;
+ uint32_t bit, best_bit = 1;
+ const uint32_t last_bit = 1 << fms(base);
+
+ /* Count 1s that will flip as gain, 0s we have to force as loss. */
+ for (bit = 1 << fls(base); bit <= last_bit; bit <<= 1) {
+ if (ALIGN_UP(base, bit) > limit)
+ break;
+ if (base & bit) {
+ if (++gain > best_gain) {
+ best_gain = gain;
+ best_bit = bit;
+ }
+ } else {
+ --gain;
+ }
+ }
+
+ return ALIGN_UP(base, best_bit);
+}
+
static void calc_var_mtrrs_with_hole(struct var_mtrr_state *var_state,
struct range_entry *r)
{
- uint32_t a1, a2, b1, b2;
+ uint32_t a1, a2, b1, b2, b2_limit;
int mtrr_type;
struct range_entry *next;
@@ -482,11 +533,11 @@
* Determine MTRRs based on the following algorithm for the given entry:
* +------------------+ b2 = ALIGN_UP(end)
* | 0 or more bytes | <-- hole is carved out between b1 and b2
- * +------------------+ a2 = b1 = end
+ * +------------------+ a2 = b1 = original end
* | |
* +------------------+ a1 = begin
*
- * Thus, there are 3 sub-ranges to configure variable MTRRs for.
+ * Thus, there are up to 2 sub-ranges to configure variable MTRRs for.
*/
mtrr_type = range_entry_mtrr_type(r);
@@ -513,38 +564,46 @@
if (!var_state->above4gb && a2 > RANGE_4GB)
a2 = RANGE_4GB;
+ /* May carve out hole if type is WB, otherwise we are done. */
+ if (mtrr_type != MTRR_TYPE_WRBACK) {
+ calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ return;
+ }
+
next = memranges_next_entry(var_state->addr_space, r);
b1 = a2;
/* First check if a1 is >= 4GiB and the current entry is the last
* entry. If so perform an optimization of covering a larger range
- * defined by the base address' alignment. */
+ * by aligning up, at most to the next power of 2. */
if (a1 >= RANGE_4GB && next == NULL) {
- uint32_t addr_lsb;
+ uint32_t align;
- addr_lsb = fls(a1);
- b2 = (1 << addr_lsb) + a1;
- if (b2 >= a2) {
- calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
- return;
- }
- }
+ /* Find first alignment that doesn't overflow. */
+ align = 1 << fms(a2);
+ do {
+ b2 = ALIGN_UP(a2, align);
+ align >>= 1;
+ } while (b2 < a2);
- /* Handle the min alignment roundup case. */
- b2 = ALIGN_UP(a2, MTRR_MIN_ALIGN);
-
- /* Check against the next range. If the current range_entry is the
- * last entry then carving a hole is no problem. If the current entry
- * isn't the last entry then check that the last entry covers the
- * entire hole range with the default mtrr type. */
- if (next != NULL &&
- (range_entry_mtrr_type(next) != var_state->def_mtrr_type ||
- range_entry_end_mtrr_addr(next) < b2)) {
- calc_var_mtrr_range(var_state, a1, a2 - a1, mtrr_type);
+ calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
return;
}
+ /* Find the limit how far we may align up. */
+ if (next == NULL) {
+ b2_limit = ALIGN_UP(a2, 1 << fms(a2));
+ } else if (range_entry_mtrr_type(next) == var_state->def_mtrr_type) {
+ b2_limit = range_entry_end_mtrr_addr(next);
+ } else {
+ b2_limit = a2;
+ }
+ /* No bits above a1's alignment may change, it would double the cost. */
+ if (a1)
+ b2_limit = MIN(ALIGN_UP(a2 + 1, 1 << fls(a1)) - 1, b2_limit);
+ b2 = optimize_var_mtrr_hole(a2, b2_limit);
+
calc_var_mtrr_range(var_state, a1, b2 - a1, mtrr_type);
calc_var_mtrr_range(var_state, b1, b2 - b1, var_state->def_mtrr_type);
}
--
To view, visit https://review.coreboot.org/21915
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iefb064ce8c4f293490a19dd46054b966c63bde44
Gerrit-Change-Number: 21915
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h at gmx.de>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20171007/229b213d/attachment.html>
More information about the coreboot-gerrit
mailing list