Back to home page

OSCL-LXR

 
 

    


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  */