Two MTRR patches

BOSZORMENYI Zoltan (zboszor@MOL.hu)
Fri, 13 Aug 1999 09:04:12 +0100


This is a multi-part message in MIME format.
--------------3269D82762A2B7F248EB38D2
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi!

Here are two MTRR patches.

The first one fixes an issue with Cyrix 6x86 and later
processors: ARR3 is in connection with a special SMM
(System Management) mode. The bootup state of the processor
looks like this:
- SMM is set active
- ARR3 is set somewhere between 640K-1M, its size is 32K
- ARR3 is not protected. There is a bit which makes ARR3
unchangable. When this bit is set, it can only be unset
with a processor reset.

In this state when I disable ARR3 (echo "disable=3" >/proc/mtrr)
and set it to somewhere else my processor locks up immediately.
Fortunately no one complained about this yet, maybe no one
is SO adventurous. :-) So the fix in cyrix_arr_init() is
that if it finds that ARR3 is not protected then it disables
SMM mode. This code was already in but I commented it out because
I was not sure that it really needs it. In the opposite case the
driver will notice it and writes a message about it on boot and
later it will refuse any attempt to delete or set ARR3.
There is an advantage of this: we can gain another free ARR for
free. Anyone can put 'echo "disable=3" >/proc/mtrr' in the
bootup scripts or there is a better solution: uncomment the line
in the middle of cyrix_arr_init() which does exactly this.

The other patch (incremental to the first) is built on rumours
and patch-2.2.11-ac3. :-) I have read on www.tomshardware.com
in the Athlon article that it uses the same MTRR architecture
as Intel and there is a little part in patch-2.2.11-ac3 which
tries to recognize the Athlon. It says that the Athlon uses 6 as
the processor family. From these I assume that the Athlon closely
mimics the behaviour of the Intel P6 family, in which assumption
I may be totally wrong! :-) So what this second patch does is that
it rearranges some switch() statements so it checks for AMD before
Intel and if the processor family is >= 6 then the code will
execute just like on Intel, otherwise it will execute the K6-II/III
code.

I would like to hear test reports from Athlon owners.
Usual disclaimers apply: don't expect it to work at first
and comments and patches are more than welcome.
I was only able to test that it compiles UP and SMP
since I have not even seen an Athlon-based machine.

If it works this way then there is a side-effect of this patch.
Since the driver does not play with SMP internals, just uses
its services, if (or rather WHEN) the SMP i386 code supports
SMP Athlon boards, the MTRR driver will immediately behave
properly on these beasts.

Linus, Alan: Please, DO NOT include any of these patches into
official kernels, as the MTRR driver is maintained by Richard
Gooch and (hopefully) he will give an official version number
at least for the first patch after I get enough test reports.
When Richard won't be as busy as now he will submit it officially.
Again: I provide these ONLY FOR TESTING.

Best regards,
Zoltan Boszormenyi

--
Microsoft: It's where you don't want to go today.
--------------3269D82762A2B7F248EB38D2
Content-Type: text/plain; charset=us-ascii;
 name="mtrr.c-arr3fix.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mtrr.c-arr3fix.diff"

--- mtrr.c.old Thu Jul 1 17:22:28 1999 +++ mtrr.c Thu Aug 12 19:08:47 1999 @@ -201,6 +201,18 @@ 19990512 Richard Gooch <rgooch@atnf.csiro.au> Minor cleanups. v1.35 + 19990707 Zoltan Boszormenyi <zboszor@mol.hu> + Check whether ARR3 is protected in cyrix_get_free_region() + and mtrr_del(). The code won't attempt to delete or change it + from now on if the BIOS protected ARR3. It silently skips ARR3 + in cyrix_get_free_region() or returns with an error code from + mtrr_del(). + 19990711 Zoltan Boszormenyi <zboszor@mol.hu> + Reset some bits in the CCRs in cyrix_arr_init() to disable SMM + if ARR3 isn't protected. This is needed because if SMM is active + and ARR3 isn't protected then deleting and setting ARR3 again + may lock up the processor. With SMM entirely disabled, it does + not happen. */ #include <linux/types.h> #include <linux/errno.h> @@ -309,6 +321,7 @@ unsigned long ccr3; }; +static int arr3_protected; /* Put the processor into a state where MTRRs can be safely set */ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) @@ -1030,6 +1043,7 @@ for (i = 0; i < 7; i++) { cyrix_get_arr (i, &lbase, &lsize, &ltype); + if ((i == 3) && arr3_protected) continue; if (lsize < 1) return i; } /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ @@ -1221,6 +1235,15 @@ printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } + if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) + { + if ((reg == 3) && arr3_protected) + { + spin_unlock (&main_lock); + printk ("mtrr: ARR3 cannot be changed\n"); + return -EINVAL; + } + } (*get_mtrr) (reg, &lbase, &lsize, &ltype); if (lsize < 1) { @@ -1585,22 +1608,22 @@ ccr[5] = getCx86 (CX86_CCR5); ccr[6] = getCx86 (CX86_CCR6); - if (ccr[3] & 1) + if (ccr[3] & 1) { ccrc[3] = 1; - else { + arr3_protected = 1; + } else { /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and * access to SMM memory through ARR3 (bit 7). */ -/* if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } -*/ + arr3_protected = 0; if (ccr[6] & 0x02) { ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */ setCx86 (CX86_CCR6, ccr[6]); } - /* Disable ARR3. */ + /* Disable ARR3. This is safe now that we disabled SMM. */ /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ } /* If we changed CCR1 in memory, change it in the processor, too. */

--------------3269D82762A2B7F248EB38D2 Content-Type: text/plain; charset=us-ascii; name="mtrr.c-Athlon.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mtrr.c-Athlon.diff"

--- mtrr.c-arr3fix Thu Aug 12 19:08:47 1999 +++ mtrr.c Thu Aug 12 19:14:51 1999 @@ -213,6 +213,11 @@ and ARR3 isn't protected then deleting and setting ARR3 again may lock up the processor. With SMM entirely disabled, it does not happen. + 19990812 Zoltan Boszormenyi <zboszor@mol.hu> + PRELIMINARY CHANGES!!! ONLY FOR TESTING!!! + Rearrange switch() statements so the driver accomodates to + the fact that the AMD Athlon handles its MTRRs the same way + as Intel does. */ #include <linux/types.h> #include <linux/errno.h> @@ -334,6 +339,8 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: + if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_CENTAUR: return; /*break;*/ @@ -357,6 +364,7 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: case X86_VENDOR_INTEL: /* Disable MTRRs, and set the default type to uncached */ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); @@ -378,6 +386,8 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: + if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_CENTAUR: __restore_flags (ctxt->flags); return; @@ -389,6 +399,7 @@ /* Restore MTRRdefType */ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: case X86_VENDOR_INTEL: wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); break; @@ -419,6 +430,9 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) return 2; /* pre-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & 0xff); @@ -429,9 +443,6 @@ /* and Centaur has 8 MCR's */ return 8; /*break;*/ - case X86_VENDOR_AMD: - return 2; - /*break;*/ } return 0; } /* End Function get_num_var_ranges */ @@ -443,12 +454,14 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); /*break;*/ case X86_VENDOR_CYRIX: - case X86_VENDOR_AMD: case X86_VENDOR_CENTAUR: return 1; /*break;*/ @@ -1076,6 +1089,20 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ + /* Apply the K6 block alignment and size rules + In order + o Uncached or gathering only + o 128K or bigger block + o Power of 2 block + o base suitably aligned to the power + */ + if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + (size & ~(size-1))-size || (base & (size-1))) + return -EINVAL; + break; + } /* else fall through */ case X86_VENDOR_INTEL: /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && @@ -1119,18 +1146,6 @@ return -EINVAL; } break; - case X86_VENDOR_AMD: - /* Apply the K6 block alignment and size rules - In order - o Uncached or gathering only - o 128K or bigger block - o Power of 2 block - o base suitably aligned to the power - */ - if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || - (size & ~(size-1))-size || (base & (size-1))) - return -EINVAL; - break; default: return -EINVAL; /*break;*/ @@ -1683,6 +1698,12 @@ printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ + get_mtrr = amd_get_mtrr; + set_mtrr_up = amd_set_mtrr_up; + break; + } /* else fall through */ case X86_VENDOR_INTEL: get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; @@ -1692,10 +1713,6 @@ set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; break; - case X86_VENDOR_AMD: - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - break; case X86_VENDOR_CENTAUR: get_mtrr = centaur_get_mcr; set_mtrr_up = centaur_set_mcr_up; @@ -1714,6 +1731,8 @@ mtrr_setup (); switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ case X86_VENDOR_INTEL: get_mtrr_state (&smp_mtrr_state); break; @@ -1750,6 +1769,9 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* Just for robustness: pre-Athlon CPUs cannot do SMP. */ + if (boot_cpu_data.x86 < 6) break; case X86_VENDOR_INTEL: intel_mtrr_init_secondary_cpu (); break; @@ -1775,6 +1797,8 @@ # ifdef __SMP__ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ case X86_VENDOR_INTEL: finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask);

--------------3269D82762A2B7F248EB38D2--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/