xref: /OK3568_Linux_fs/kernel/Documentation/x86/mtrr.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun=========================================
4*4882a593SmuzhiyunMTRR (Memory Type Range Register) control
5*4882a593Smuzhiyun=========================================
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun:Authors: - Richard Gooch <rgooch@atnf.csiro.au> - 3 Jun 1999
8*4882a593Smuzhiyun          - Luis R. Rodriguez <mcgrof@do-not-panic.com> - April 9, 2015
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun
11*4882a593SmuzhiyunPhasing out MTRR use
12*4882a593Smuzhiyun====================
13*4882a593Smuzhiyun
14*4882a593SmuzhiyunMTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by
15*4882a593Smuzhiyundrivers on Linux is now completely phased out, device drivers should use
16*4882a593Smuzhiyunarch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on
17*4882a593Smuzhiyunnon-PAT systems while a no-op but equally effective on PAT enabled systems.
18*4882a593Smuzhiyun
19*4882a593SmuzhiyunEven if Linux does not use MTRRs directly, some x86 platform firmware may still
20*4882a593Smuzhiyunset up MTRRs early before booting the OS. They do this as some platform
21*4882a593Smuzhiyunfirmware may still have implemented access to MTRRs which would be controlled
22*4882a593Smuzhiyunand handled by the platform firmware directly. An example of platform use of
23*4882a593SmuzhiyunMTRRs is through the use of SMI handlers, one case could be for fan control,
24*4882a593Smuzhiyunthe platform code would need uncachable access to some of its fan control
25*4882a593Smuzhiyunregisters. Such platform access does not need any Operating System MTRR code in
26*4882a593Smuzhiyunplace other than mtrr_type_lookup() to ensure any OS specific mapping requests
27*4882a593Smuzhiyunare aligned with platform MTRR setup. If MTRRs are only set up by the platform
28*4882a593Smuzhiyunfirmware code though and the OS does not make any specific MTRR mapping
29*4882a593Smuzhiyunrequests mtrr_type_lookup() should always return MTRR_TYPE_INVALID.
30*4882a593Smuzhiyun
31*4882a593SmuzhiyunFor details refer to :doc:`pat`.
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun.. tip::
34*4882a593Smuzhiyun  On Intel P6 family processors (Pentium Pro, Pentium II and later)
35*4882a593Smuzhiyun  the Memory Type Range Registers (MTRRs) may be used to control
36*4882a593Smuzhiyun  processor access to memory ranges. This is most useful when you have
37*4882a593Smuzhiyun  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
38*4882a593Smuzhiyun  allows bus write transfers to be combined into a larger transfer
39*4882a593Smuzhiyun  before bursting over the PCI/AGP bus. This can increase performance
40*4882a593Smuzhiyun  of image write operations 2.5 times or more.
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun  The Cyrix 6x86, 6x86MX and M II processors have Address Range
43*4882a593Smuzhiyun  Registers (ARRs) which provide a similar functionality to MTRRs. For
44*4882a593Smuzhiyun  these, the ARRs are used to emulate the MTRRs.
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
47*4882a593Smuzhiyun  MTRRs. These are supported.  The AMD Athlon family provide 8 Intel
48*4882a593Smuzhiyun  style MTRRs.
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun  The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These
51*4882a593Smuzhiyun  are supported.
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun  The VIA Cyrix III and VIA C3 CPUs offer 8 Intel style MTRRs.
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
56*4882a593Smuzhiyun  to manipulate your MTRRs. Typically the X server should use
57*4882a593Smuzhiyun  this. This should have a reasonably generic interface so that
58*4882a593Smuzhiyun  similar control registers on other processors can be easily
59*4882a593Smuzhiyun  supported.
60*4882a593Smuzhiyun
61*4882a593SmuzhiyunThere are two interfaces to /proc/mtrr: one is an ASCII interface
62*4882a593Smuzhiyunwhich allows you to read and write. The other is an ioctl()
63*4882a593Smuzhiyuninterface. The ASCII interface is meant for administration. The
64*4882a593Smuzhiyunioctl() interface is meant for C programs (i.e. the X server). The
65*4882a593Smuzhiyuninterfaces are described below, with sample commands and C code.
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun
68*4882a593SmuzhiyunReading MTRRs from the shell
69*4882a593Smuzhiyun============================
70*4882a593Smuzhiyun::
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun  % cat /proc/mtrr
73*4882a593Smuzhiyun  reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
74*4882a593Smuzhiyun  reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
75*4882a593Smuzhiyun
76*4882a593SmuzhiyunCreating MTRRs from the C-shell::
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun  # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
79*4882a593Smuzhiyun
80*4882a593Smuzhiyunor if you use bash::
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun  # echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr
83*4882a593Smuzhiyun
84*4882a593SmuzhiyunAnd the result thereof::
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun  % cat /proc/mtrr
87*4882a593Smuzhiyun  reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
88*4882a593Smuzhiyun  reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
89*4882a593Smuzhiyun  reg02: base=0xf8000000 (3968MB), size=   4MB: write-combining, count=1
90*4882a593Smuzhiyun
91*4882a593SmuzhiyunThis is for video RAM at base address 0xf8000000 and size 4 megabytes. To
92*4882a593Smuzhiyunfind out your base address, you need to look at the output of your X
93*4882a593Smuzhiyunserver, which tells you where the linear framebuffer address is. A
94*4882a593Smuzhiyuntypical line that you may get is::
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun  (--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
97*4882a593Smuzhiyun
98*4882a593SmuzhiyunNote that you should only use the value from the X server, as it may
99*4882a593Smuzhiyunmove the framebuffer base address, so the only value you can trust is
100*4882a593Smuzhiyunthat reported by the X server.
101*4882a593Smuzhiyun
102*4882a593SmuzhiyunTo find out the size of your framebuffer (what, you don't actually
103*4882a593Smuzhiyunknow?), the following line will tell you::
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun  (--) S3: videoram:  4096k
106*4882a593Smuzhiyun
107*4882a593SmuzhiyunThat's 4 megabytes, which is 0x400000 bytes (in hexadecimal).
108*4882a593SmuzhiyunA patch is being written for XFree86 which will make this automatic:
109*4882a593Smuzhiyunin other words the X server will manipulate /proc/mtrr using the
110*4882a593Smuzhiyunioctl() interface, so users won't have to do anything. If you use a
111*4882a593Smuzhiyuncommercial X server, lobby your vendor to add support for MTRRs.
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun
114*4882a593SmuzhiyunCreating overlapping MTRRs
115*4882a593Smuzhiyun==========================
116*4882a593Smuzhiyun::
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun  %echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
119*4882a593Smuzhiyun  %echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
120*4882a593Smuzhiyun
121*4882a593SmuzhiyunAnd the results::
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun  % cat /proc/mtrr
124*4882a593Smuzhiyun  reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
125*4882a593Smuzhiyun  reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
126*4882a593Smuzhiyun  reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
127*4882a593Smuzhiyun
128*4882a593SmuzhiyunSome cards (especially Voodoo Graphics boards) need this 4 kB area
129*4882a593Smuzhiyunexcluded from the beginning of the region because it is used for
130*4882a593Smuzhiyunregisters.
131*4882a593Smuzhiyun
132*4882a593SmuzhiyunNOTE: You can only create type=uncachable region, if the first
133*4882a593Smuzhiyunregion that you created is type=write-combining.
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun
136*4882a593SmuzhiyunRemoving MTRRs from the C-shel
137*4882a593Smuzhiyun==============================
138*4882a593Smuzhiyun::
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun  % echo "disable=2" >! /proc/mtrr
141*4882a593Smuzhiyun
142*4882a593Smuzhiyunor using bash::
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun  % echo "disable=2" >| /proc/mtrr
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun
147*4882a593SmuzhiyunReading MTRRs from a C program using ioctl()'s
148*4882a593Smuzhiyun==============================================
149*4882a593Smuzhiyun::
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun  /*  mtrr-show.c
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun      Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun      Copyright (C) 1997-1998  Richard Gooch
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun      This program is free software; you can redistribute it and/or modify
158*4882a593Smuzhiyun      it under the terms of the GNU General Public License as published by
159*4882a593Smuzhiyun      the Free Software Foundation; either version 2 of the License, or
160*4882a593Smuzhiyun      (at your option) any later version.
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun      This program is distributed in the hope that it will be useful,
163*4882a593Smuzhiyun      but WITHOUT ANY WARRANTY; without even the implied warranty of
164*4882a593Smuzhiyun      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165*4882a593Smuzhiyun      GNU General Public License for more details.
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun      You should have received a copy of the GNU General Public License
168*4882a593Smuzhiyun      along with this program; if not, write to the Free Software
169*4882a593Smuzhiyun      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun      Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
172*4882a593Smuzhiyun      The postal address is:
173*4882a593Smuzhiyun        Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
174*4882a593Smuzhiyun  */
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun  /*
177*4882a593Smuzhiyun      This program will use an ioctl() on /proc/mtrr to show the current MTRR
178*4882a593Smuzhiyun      settings. This is an alternative to reading /proc/mtrr.
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun      Written by      Richard Gooch   17-DEC-1997
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun      Last updated by Richard Gooch   2-MAY-1998
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun  */
187*4882a593Smuzhiyun  #include <stdio.h>
188*4882a593Smuzhiyun  #include <stdlib.h>
189*4882a593Smuzhiyun  #include <string.h>
190*4882a593Smuzhiyun  #include <sys/types.h>
191*4882a593Smuzhiyun  #include <sys/stat.h>
192*4882a593Smuzhiyun  #include <fcntl.h>
193*4882a593Smuzhiyun  #include <sys/ioctl.h>
194*4882a593Smuzhiyun  #include <errno.h>
195*4882a593Smuzhiyun  #include <asm/mtrr.h>
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun  #define TRUE 1
198*4882a593Smuzhiyun  #define FALSE 0
199*4882a593Smuzhiyun  #define ERRSTRING strerror (errno)
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun  static char *mtrr_strings[MTRR_NUM_TYPES] =
202*4882a593Smuzhiyun  {
203*4882a593Smuzhiyun      "uncachable",               /* 0 */
204*4882a593Smuzhiyun      "write-combining",          /* 1 */
205*4882a593Smuzhiyun      "?",                        /* 2 */
206*4882a593Smuzhiyun      "?",                        /* 3 */
207*4882a593Smuzhiyun      "write-through",            /* 4 */
208*4882a593Smuzhiyun      "write-protect",            /* 5 */
209*4882a593Smuzhiyun      "write-back",               /* 6 */
210*4882a593Smuzhiyun  };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun  int main ()
213*4882a593Smuzhiyun  {
214*4882a593Smuzhiyun      int fd;
215*4882a593Smuzhiyun      struct mtrr_gentry gentry;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun      if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
218*4882a593Smuzhiyun      {
219*4882a593Smuzhiyun    if (errno == ENOENT)
220*4882a593Smuzhiyun    {
221*4882a593Smuzhiyun        fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
222*4882a593Smuzhiyun        stderr);
223*4882a593Smuzhiyun        exit (1);
224*4882a593Smuzhiyun    }
225*4882a593Smuzhiyun    fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
226*4882a593Smuzhiyun    exit (2);
227*4882a593Smuzhiyun      }
228*4882a593Smuzhiyun      for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
229*4882a593Smuzhiyun    ++gentry.regnum)
230*4882a593Smuzhiyun      {
231*4882a593Smuzhiyun    if (gentry.size < 1)
232*4882a593Smuzhiyun    {
233*4882a593Smuzhiyun        fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
234*4882a593Smuzhiyun        continue;
235*4882a593Smuzhiyun    }
236*4882a593Smuzhiyun    fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
237*4882a593Smuzhiyun      gentry.regnum, gentry.base, gentry.size,
238*4882a593Smuzhiyun      mtrr_strings[gentry.type]);
239*4882a593Smuzhiyun      }
240*4882a593Smuzhiyun      if (errno == EINVAL) exit (0);
241*4882a593Smuzhiyun      fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
242*4882a593Smuzhiyun      exit (3);
243*4882a593Smuzhiyun  }   /*  End Function main  */
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun
246*4882a593SmuzhiyunCreating MTRRs from a C programme using ioctl()'s
247*4882a593Smuzhiyun=================================================
248*4882a593Smuzhiyun::
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun  /*  mtrr-add.c
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun      Source file for mtrr-add (example programme to add an MTRRs using ioctl())
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun      Copyright (C) 1997-1998  Richard Gooch
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun      This program is free software; you can redistribute it and/or modify
257*4882a593Smuzhiyun      it under the terms of the GNU General Public License as published by
258*4882a593Smuzhiyun      the Free Software Foundation; either version 2 of the License, or
259*4882a593Smuzhiyun      (at your option) any later version.
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun      This program is distributed in the hope that it will be useful,
262*4882a593Smuzhiyun      but WITHOUT ANY WARRANTY; without even the implied warranty of
263*4882a593Smuzhiyun      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
264*4882a593Smuzhiyun      GNU General Public License for more details.
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun      You should have received a copy of the GNU General Public License
267*4882a593Smuzhiyun      along with this program; if not, write to the Free Software
268*4882a593Smuzhiyun      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun      Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
271*4882a593Smuzhiyun      The postal address is:
272*4882a593Smuzhiyun        Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
273*4882a593Smuzhiyun  */
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun  /*
276*4882a593Smuzhiyun      This programme will use an ioctl() on /proc/mtrr to add an entry. The first
277*4882a593Smuzhiyun      available mtrr is used. This is an alternative to writing /proc/mtrr.
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun      Written by      Richard Gooch   17-DEC-1997
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun      Last updated by Richard Gooch   2-MAY-1998
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun  */
286*4882a593Smuzhiyun  #include <stdio.h>
287*4882a593Smuzhiyun  #include <string.h>
288*4882a593Smuzhiyun  #include <stdlib.h>
289*4882a593Smuzhiyun  #include <unistd.h>
290*4882a593Smuzhiyun  #include <sys/types.h>
291*4882a593Smuzhiyun  #include <sys/stat.h>
292*4882a593Smuzhiyun  #include <fcntl.h>
293*4882a593Smuzhiyun  #include <sys/ioctl.h>
294*4882a593Smuzhiyun  #include <errno.h>
295*4882a593Smuzhiyun  #include <asm/mtrr.h>
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun  #define TRUE 1
298*4882a593Smuzhiyun  #define FALSE 0
299*4882a593Smuzhiyun  #define ERRSTRING strerror (errno)
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun  static char *mtrr_strings[MTRR_NUM_TYPES] =
302*4882a593Smuzhiyun  {
303*4882a593Smuzhiyun      "uncachable",               /* 0 */
304*4882a593Smuzhiyun      "write-combining",          /* 1 */
305*4882a593Smuzhiyun      "?",                        /* 2 */
306*4882a593Smuzhiyun      "?",                        /* 3 */
307*4882a593Smuzhiyun      "write-through",            /* 4 */
308*4882a593Smuzhiyun      "write-protect",            /* 5 */
309*4882a593Smuzhiyun      "write-back",               /* 6 */
310*4882a593Smuzhiyun  };
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun  int main (int argc, char **argv)
313*4882a593Smuzhiyun  {
314*4882a593Smuzhiyun      int fd;
315*4882a593Smuzhiyun      struct mtrr_sentry sentry;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun      if (argc != 4)
318*4882a593Smuzhiyun      {
319*4882a593Smuzhiyun    fprintf (stderr, "Usage:\tmtrr-add base size type\n");
320*4882a593Smuzhiyun    exit (1);
321*4882a593Smuzhiyun      }
322*4882a593Smuzhiyun      sentry.base = strtoul (argv[1], NULL, 0);
323*4882a593Smuzhiyun      sentry.size = strtoul (argv[2], NULL, 0);
324*4882a593Smuzhiyun      for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
325*4882a593Smuzhiyun      {
326*4882a593Smuzhiyun    if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
327*4882a593Smuzhiyun      }
328*4882a593Smuzhiyun      if (sentry.type >= MTRR_NUM_TYPES)
329*4882a593Smuzhiyun      {
330*4882a593Smuzhiyun    fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
331*4882a593Smuzhiyun    exit (2);
332*4882a593Smuzhiyun      }
333*4882a593Smuzhiyun      if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
334*4882a593Smuzhiyun      {
335*4882a593Smuzhiyun    if (errno == ENOENT)
336*4882a593Smuzhiyun    {
337*4882a593Smuzhiyun        fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
338*4882a593Smuzhiyun        stderr);
339*4882a593Smuzhiyun        exit (3);
340*4882a593Smuzhiyun    }
341*4882a593Smuzhiyun    fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
342*4882a593Smuzhiyun    exit (4);
343*4882a593Smuzhiyun      }
344*4882a593Smuzhiyun      if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
345*4882a593Smuzhiyun      {
346*4882a593Smuzhiyun    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
347*4882a593Smuzhiyun    exit (5);
348*4882a593Smuzhiyun      }
349*4882a593Smuzhiyun      fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
350*4882a593Smuzhiyun      sleep (5);
351*4882a593Smuzhiyun      close (fd);
352*4882a593Smuzhiyun      fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
353*4882a593Smuzhiyun      stderr);
354*4882a593Smuzhiyun  }   /*  End Function main  */
355