0001 .. SPDX-License-Identifier: GPL-2.0
0002
0003 =========================================
0004 MTRR (Memory Type Range Register) control
0005 =========================================
0006
0007 :Authors: - Richard Gooch <rgooch@atnf.csiro.au> - 3 Jun 1999
0008 - Luis R. Rodriguez <mcgrof@do-not-panic.com> - April 9, 2015
0009
0010
0011 Phasing out MTRR use
0012 ====================
0013
0014 MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by
0015 drivers on Linux is now completely phased out, device drivers should use
0016 arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on
0017 non-PAT systems while a no-op but equally effective on PAT enabled systems.
0018
0019 Even if Linux does not use MTRRs directly, some x86 platform firmware may still
0020 set up MTRRs early before booting the OS. They do this as some platform
0021 firmware may still have implemented access to MTRRs which would be controlled
0022 and handled by the platform firmware directly. An example of platform use of
0023 MTRRs is through the use of SMI handlers, one case could be for fan control,
0024 the platform code would need uncachable access to some of its fan control
0025 registers. Such platform access does not need any Operating System MTRR code in
0026 place other than mtrr_type_lookup() to ensure any OS specific mapping requests
0027 are aligned with platform MTRR setup. If MTRRs are only set up by the platform
0028 firmware code though and the OS does not make any specific MTRR mapping
0029 requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID.
0030
0031 For details refer to Documentation/x86/pat.rst.
0032
0033 .. tip::
0034 On Intel P6 family processors (Pentium Pro, Pentium II and later)
0035 the Memory Type Range Registers (MTRRs) may be used to control
0036 processor access to memory ranges. This is most useful when you have
0037 a video (VGA) card on a PCI or AGP bus. Enabling write-combining
0038 allows bus write transfers to be combined into a larger transfer
0039 before bursting over the PCI/AGP bus. This can increase performance
0040 of image write operations 2.5 times or more.
0041
0042 The Cyrix 6x86, 6x86MX and M II processors have Address Range
0043 Registers (ARRs) which provide a similar functionality to MTRRs. For
0044 these, the ARRs are used to emulate the MTRRs.
0045
0046 The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
0047 MTRRs. These are supported. The AMD Athlon family provide 8 Intel
0048 style MTRRs.
0049
0050 The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
0051 are supported.
0052
0053 The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
0054
0055 The CONFIG_MTRR option creates a /proc/mtrr file which may be used
0056 to manipulate your MTRRs. Typically the X server should use
0057 this. This should have a reasonably generic interface so that
0058 similar control registers on other processors can be easily
0059 supported.
0060
0061 There are two interfaces to /proc/mtrr: one is an ASCII interface
0062 which allows you to read and write. The other is an ioctl()
0063 interface. The ASCII interface is meant for administration. The
0064 ioctl() interface is meant for C programs (i.e. the X server). The
0065 interfaces are described below, with sample commands and C code.
0066
0067
0068 Reading MTRRs from the shell
0069 ============================
0070 ::
0071
0072 % cat /proc/mtrr
0073 reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
0074 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
0075
0076 Creating MTRRs from the C-shell::
0077
0078 # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
0079
0080 or if you use bash::
0081
0082 # echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
0083
0084 And the result thereof::
0085
0086 % cat /proc/mtrr
0087 reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
0088 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
0089 reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1
0090
0091 This is for video RAM at base address 0xf8000000 and size 4 megabytes. To
0092 find out your base address, you need to look at the output of your X
0093 server, which tells you where the linear framebuffer address is. A
0094 typical line that you may get is::
0095
0096 (--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
0097
0098 Note that you should only use the value from the X server, as it may
0099 move the framebuffer base address, so the only value you can trust is
0100 that reported by the X server.
0101
0102 To find out the size of your framebuffer (what, you don't actually
0103 know?), the following line will tell you::
0104
0105 (--) S3: videoram: 4096k
0106
0107 That's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
0108 A patch is being written for XFree86 which will make this automatic:
0109 in other words the X server will manipulate /proc/mtrr using the
0110 ioctl() interface, so users won't have to do anything. If you use a
0111 commercial X server, lobby your vendor to add support for MTRRs.
0112
0113
0114 Creating overlapping MTRRs
0115 ==========================
0116 ::
0117
0118 %echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
0119 %echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
0120
0121 And the results::
0122
0123 % cat /proc/mtrr
0124 reg00: base=0x00000000 ( 0MB), size= 64MB: write-back, count=1
0125 reg01: base=0xfb000000 (4016MB), size= 16MB: write-combining, count=1
0126 reg02: base=0xfb000000 (4016MB), size= 4kB: uncachable, count=1
0127
0128 Some cards (especially Voodoo Graphics boards) need this 4 kB area
0129 excluded from the beginning of the region because it is used for
0130 registers.
0131
0132 NOTE: You can only create type=uncachable region, if the first
0133 region that you created is type=write-combining.
0134
0135
0136 Removing MTRRs from the C-shel
0137 ==============================
0138 ::
0139
0140 % echo "disable=2" >! /proc/mtrr
0141
0142 or using bash::
0143
0144 % echo "disable=2" >| /proc/mtrr
0145
0146
0147 Reading MTRRs from a C program using ioctl()'s
0148 ==============================================
0149 ::
0150
0151 /* mtrr-show.c
0152
0153 Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
0154
0155 Copyright (C) 1997-1998 Richard Gooch
0156
0157 This program is free software; you can redistribute it and/or modify
0158 it under the terms of the GNU General Public License as published by
0159 the Free Software Foundation; either version 2 of the License, or
0160 (at your option) any later version.
0161
0162 This program is distributed in the hope that it will be useful,
0163 but WITHOUT ANY WARRANTY; without even the implied warranty of
0164 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0165 GNU General Public License for more details.
0166
0167 You should have received a copy of the GNU General Public License
0168 along with this program; if not, write to the Free Software
0169 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0170
0171 Richard Gooch may be reached by email at rgooch@atnf.csiro.au
0172 The postal address is:
0173 Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
0174 */
0175
0176 /*
0177 This program will use an ioctl() on /proc/mtrr to show the current MTRR
0178 settings. This is an alternative to reading /proc/mtrr.
0179
0180
0181 Written by Richard Gooch 17-DEC-1997
0182
0183 Last updated by Richard Gooch 2-MAY-1998
0184
0185
0186 */
0187 #include <stdio.h>
0188 #include <stdlib.h>
0189 #include <string.h>
0190 #include <sys/types.h>
0191 #include <sys/stat.h>
0192 #include <fcntl.h>
0193 #include <sys/ioctl.h>
0194 #include <errno.h>
0195 #include <asm/mtrr.h>
0196
0197 #define TRUE 1
0198 #define FALSE 0
0199 #define ERRSTRING strerror (errno)
0200
0201 static char *mtrr_strings[MTRR_NUM_TYPES] =
0202 {
0203 "uncachable", /* 0 */
0204 "write-combining", /* 1 */
0205 "?", /* 2 */
0206 "?", /* 3 */
0207 "write-through", /* 4 */
0208 "write-protect", /* 5 */
0209 "write-back", /* 6 */
0210 };
0211
0212 int main ()
0213 {
0214 int fd;
0215 struct mtrr_gentry gentry;
0216
0217 if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
0218 {
0219 if (errno == ENOENT)
0220 {
0221 fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
0222 stderr);
0223 exit (1);
0224 }
0225 fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
0226 exit (2);
0227 }
0228 for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
0229 ++gentry.regnum)
0230 {
0231 if (gentry.size < 1)
0232 {
0233 fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
0234 continue;
0235 }
0236 fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
0237 gentry.regnum, gentry.base, gentry.size,
0238 mtrr_strings[gentry.type]);
0239 }
0240 if (errno == EINVAL) exit (0);
0241 fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
0242 exit (3);
0243 } /* End Function main */
0244
0245
0246 Creating MTRRs from a C programme using ioctl()'s
0247 =================================================
0248 ::
0249
0250 /* mtrr-add.c
0251
0252 Source file for mtrr-add (example programme to add an MTRRs using ioctl())
0253
0254 Copyright (C) 1997-1998 Richard Gooch
0255
0256 This program is free software; you can redistribute it and/or modify
0257 it under the terms of the GNU General Public License as published by
0258 the Free Software Foundation; either version 2 of the License, or
0259 (at your option) any later version.
0260
0261 This program is distributed in the hope that it will be useful,
0262 but WITHOUT ANY WARRANTY; without even the implied warranty of
0263 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0264 GNU General Public License for more details.
0265
0266 You should have received a copy of the GNU General Public License
0267 along with this program; if not, write to the Free Software
0268 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0269
0270 Richard Gooch may be reached by email at rgooch@atnf.csiro.au
0271 The postal address is:
0272 Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
0273 */
0274
0275 /*
0276 This programme will use an ioctl() on /proc/mtrr to add an entry. The first
0277 available mtrr is used. This is an alternative to writing /proc/mtrr.
0278
0279
0280 Written by Richard Gooch 17-DEC-1997
0281
0282 Last updated by Richard Gooch 2-MAY-1998
0283
0284
0285 */
0286 #include <stdio.h>
0287 #include <string.h>
0288 #include <stdlib.h>
0289 #include <unistd.h>
0290 #include <sys/types.h>
0291 #include <sys/stat.h>
0292 #include <fcntl.h>
0293 #include <sys/ioctl.h>
0294 #include <errno.h>
0295 #include <asm/mtrr.h>
0296
0297 #define TRUE 1
0298 #define FALSE 0
0299 #define ERRSTRING strerror (errno)
0300
0301 static char *mtrr_strings[MTRR_NUM_TYPES] =
0302 {
0303 "uncachable", /* 0 */
0304 "write-combining", /* 1 */
0305 "?", /* 2 */
0306 "?", /* 3 */
0307 "write-through", /* 4 */
0308 "write-protect", /* 5 */
0309 "write-back", /* 6 */
0310 };
0311
0312 int main (int argc, char **argv)
0313 {
0314 int fd;
0315 struct mtrr_sentry sentry;
0316
0317 if (argc != 4)
0318 {
0319 fprintf (stderr, "Usage:\tmtrr-add base size type\n");
0320 exit (1);
0321 }
0322 sentry.base = strtoul (argv[1], NULL, 0);
0323 sentry.size = strtoul (argv[2], NULL, 0);
0324 for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
0325 {
0326 if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
0327 }
0328 if (sentry.type >= MTRR_NUM_TYPES)
0329 {
0330 fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
0331 exit (2);
0332 }
0333 if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
0334 {
0335 if (errno == ENOENT)
0336 {
0337 fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
0338 stderr);
0339 exit (3);
0340 }
0341 fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
0342 exit (4);
0343 }
0344 if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
0345 {
0346 fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
0347 exit (5);
0348 }
0349 fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
0350 sleep (5);
0351 close (fd);
0352 fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
0353 stderr);
0354 } /* End Function main */