]> git.neil.brown.name Git - history.git/commitdiff
pre-2.1.99-3 2.1.99pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:20 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:20 +0000 (15:15 -0500)
There's a new pre-patch on ftp.kernel.org, that does:

 - the networking fixes that didn't get into 98 due to various mess-ups
 - mtrr patches are there by default
 - all the irq fixes we know of to date are there (and hopefully even the
   ne2000 things should work with the SELF-IPI change)
 - various documentation updates and bugfixes (the best way to know that a
   stable kernel is approaching is to notice that somebody starts to
   spellcheck the kernel - it has so far never failed)

in short, all known bugs should be fixed, but hey, what else is new?

                Linus

33 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/mtrr.txt [new file with mode: 0644]
arch/alpha/config.in
arch/alpha/lib/checksum.c
arch/alpha/lib/csum_partial_copy.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/Makefile
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/irq.c
arch/i386/kernel/mtrr.c [new file with mode: 0644]
arch/i386/kernel/smp.c
arch/ppc/config.in
arch/ppc/prep_defconfig
drivers/pci/Makefile
drivers/pci/pci.c
drivers/pci/quirks.c
include/asm-alpha/checksum.h
include/asm-i386/bugs.h
include/asm-i386/checksum.h
include/asm-i386/mtrr.h [new file with mode: 0644]
include/asm-i386/smp.h
include/asm-m68k/checksum.h
include/asm-ppc/checksum.h
include/asm-sparc/checksum.h
include/asm-sparc64/checksum.h
include/linux/proc_fs.h
include/linux/smp.h
kernel/kmod.c
net/ipv4/tcp_ipv4.c
net/netsyms.c

diff --git a/CREDITS b/CREDITS
index 05d1cb7ef9472f26dc11eba97be457483de52d40..662f569f0faa8d80602ac398daaa2f245fec37b5 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -568,6 +568,7 @@ N: Richard E. Gooch
 E: rgooch@atnf.csiro.au
 D: parent process death signal to children
 D: prctl() syscall
+D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's
 S: CSIRO Australia Telescope National Facility
 S: P.O. Box 76, Epping
 S: N.S.W., 2121
index 9b5846d92fb18276872e208ed6fd15d9e3e4f381..8bd1786ed79cf45a7efd6b2ac66472e84d5c2c4b 100644 (file)
@@ -19,7 +19,8 @@ need to bother doing so in the form of a diff, as this is generated by
 texinfo so a diff is useless anyway (though I can incorporate one by
 hand if you insist upon sending it that way ;-).
 
-   Check out http://www.cviog.uga.edu/Misc/info/LinuxBleed.html for an
+   Check out
+http://www.mindspring.com/~nunez/info/linux/LinuxBleed.html for an
 HTML-ized shopping list.
 
    For those of you in Europe,
@@ -32,7 +33,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: March 16. 1998
+Last updated: April 27, 1998
 Current Author: Chris Ricker (kaboom@gatech.edu).
 
 Current Minimal Requirements
@@ -46,14 +47,14 @@ running, the suggested command should tell you.
 - Gnu C                 2.7.2.3                 ; gcc --version
 - Binutils              2.8.1.0.1               ; ld -v
 - Linux C Library       5.4.44                  ; ls -l /lib/libc.so.*
-- Dynamic Linker (ld.so) 1.9.5                   ; ldd -v
+- Dynamic Linker (ld.so) 1.9.5                   ; ldd --version
 - Linux C++ Library     2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
 - Procps                1.2.5                   ; ps --version
-- Procinfo               0.13                    ; procinfo -v
+- Procinfo               13                      ; procinfo -v
 - Mount                  2.7l                    ; mount --version
 - Net-tools              1.41                    ; hostname -V
 - Loadlin                1.6a
-- Sh-utils               1.16                    ; expr --v
+- Sh-utils               1.16                    ; basename --v
 - Autofs                 0.3.11                  ; automount --version
 - NFS                    0.4.21                  ; showmount --version
 - Bash                   1.14.7                  ; bash -version
@@ -137,7 +138,11 @@ your system, you don't have to upgrade just so the kernel will work
 
    Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad
 Things while compiling your kernel, particularly if absurd
-optimizations (like -O9) are used.  Caveat emptor.
+optimizations (like -O9) are used.  Caveat emptor.  Currently, the only
+C compiler available in a binary distribution is egcs.  Version 1.0.2
+seems okay; if you have to have a binary, you may be successful using
+that.  In general, however, gcc-2.7.2.3 is known to be stable, while
+egcs and others have not been as thoroughly tested yet.
 
 Networking Changes
 ==================
@@ -163,8 +168,14 @@ presence.
    To run bootpd, you'll need to issue the following command:   echo 1
 >/proc/sys/net/ipv4/ip_boot_agent
 
+   Similar procedures are necessary to turn on other features.  If
+something appears broken, check the /proc/sys/net/ipv4/ directory.  "1"
+generally denotes enabled, while "0" generally denotes disabled.
+
    For support for new features like IPv6, upgrade to the latest
-net-tools.
+net-tools.  This will also fix other problems.  For example, the format
+of /proc/net/dev changed; as a result, an older ifconfig will
+incorrectly report errors.
 
 Memory
 ======
@@ -257,11 +268,11 @@ Binutils
 ========
 
 The 2.8.1.0.1 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.1.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.1.bin.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.1
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.1
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
 
 Gnu C
 =====
@@ -273,13 +284,26 @@ Installation notes:
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.3
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3
 
+The egcs-1.0.2 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-glibc.x86.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-libc5.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-glibc.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-libc5.x86.tar.gz
+Installation notes:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.2
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.2
+
+Gnu C 2.7.2.3 source:
+ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz
+ftp://sunsite.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz
+
 Linux C Library
 ===============
 
 The 5.4.44 release:
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.44.bin.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.44.bin.tar.gz
-Installation notes for 5.4.38:
+Installation notes for 5.4.44:
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.44
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.44
 
@@ -304,21 +328,20 @@ Modules utilities
 =================
 
 The 2.1.85 release:
-ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.85.tar.gz
 ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz
 
 Procps utilities
 ================
 
 The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.5.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.5.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.7.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.7.tgz
 
 Procinfo utilities
 ==================
 
-The 0.11 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.13.tar.gz
+The 13 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-13.tar.gz
 
 RPM utilities
 =============
@@ -337,8 +360,7 @@ DOSEMU
 ======
 
 The 0.66.7 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu0.66.7.tgz
-ftp://sunsite.unc.edu/pub/Linux/system/emulators/dosemu0.66.7.tgz
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.66.7.tgz
 
 Loadlin
 =======
@@ -376,8 +398,9 @@ ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz
 Net-tools
 =========
 
-The 1.432 release:
-ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.432.tar.gz
+The 1.45 release:
+ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.45.tar.gz
+http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.45.tar.gz
 
 Ypbind
 ======
@@ -396,7 +419,6 @@ Ncpfs
 
 The 2.1.1 release:
 ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz
-ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz
 
 Pcmcia-cs
 =========
index 649aa42484052f1db28dea9f8f434eed492824d9..81ce6afe176804a472a65ba1ba1001f5d4c32111 100644 (file)
@@ -1031,6 +1031,12 @@ CONFIG_PCI_DIRECT
   works. If both PCI BIOS and direct PCI access are enabled, the use
   of BIOS is preferred. If unsure, say Y.
 
+PCI quirks
+CONFIG_PCI_QUIRKS
+  If you have a broken BIOS, it may fail to set up the PCI bus in a
+  correct or optimal fashion. If your BIOS is fine you can say N here
+  for a very slightly smaller kernel. If unsure, say Y.
+
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
   This can improve access times for some hardware devices if you have
@@ -6436,6 +6442,28 @@ CONFIG_FT_FDC_MAX_RATE
   speed. If unsure, leave this disabled, i.e. leave it at 2000
   bits/sec.
 
+MTRR control and configuration
+CONFIG_MTRR
+  On Intel Pentium Pro systems the Memory Type Range Registers (MTRRs)
+  may be used to control processor access to memory ranges. This is
+  most useful when you have a video (VGA) card on the PCI
+  bus. Enabling write-combining allows PCI write transfers to be
+  combined into a larger transfer before bursting over the PCI
+  bus. This can increase performance of image write operations 2.5
+  times or more.
+  This option creates a /proc/mtrr file which may be used to manipulate
+  your MTRRs. Typically the X server should use this. This should have
+  a reasonably generic interface so that similar control registers on
+  other processors can be easily supported.
+  This option also fixes a problem with buggy SMP BIOSes which only
+  set the MTRRs for the boot CPU and not the secondary CPUs. This can
+  lead to all sorts of problems.
+  In general you should compile this into the kernel, rather than as a
+  loadable module, because the BIOS fix needs to be done early in the
+  boot sequence. If you compile this as a module, the BIOS fix will be
+  delayed until when you load the module. You do this at your own risk.
+  See Documentation/mtrr.txt for more information.
+
 Main CPU frequency, only for DEC alpha machine
 CONFIG_FT_ALPHA_CLOCK
   On some DEC Alpha machines the CPU clock frequency cannot be
diff --git a/Documentation/mtrr.txt b/Documentation/mtrr.txt
new file mode 100644 (file)
index 0000000..4236cff
--- /dev/null
@@ -0,0 +1,225 @@
+MTRR (Memory Type Range Register) control
+17 Dec 1997
+Richard Gooch
+<rgooch@atnf.csiro.au>
+
+  On Intel Pentium Pro systems the Memory Type Range Registers (MTRRs)
+  may be used to control processor access to memory ranges. This is
+  most useful when you have a video (VGA) card on the PCI
+  bus. Enabling write-combining allows PCI write transfers to be
+  combined into a larger transfer before bursting over the PCI
+  bus. This can increase performance of image write operations 2.5
+  times or more.
+
+  The CONFIG_MTRR option creates a /proc/mtrr file which may be used
+  to manipulate your MTRRs. Typically the X server should use
+  this. This should have a reasonably generic interface so that
+  similar control registers on other processors can be easily
+  supported.
+
+
+There are two interfaces to /proc/mtrr: one is an ASCII interface
+which allows you to read and write. The other is an ioctl()
+interface. The ASCII interface is meant for administration. The
+ioctl() interface is meant for C programmes (i.e. the X server). The
+interfaces are described below, with sample commands and C code.
+
+===============================================================================
+Reading MTRRs from the shell:
+
+% cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size= 128MB: write-back, count=1
+reg01: base=0x08000000 ( 128MB), size=  64MB: write-back, count=1
+reg05: base=0x80000000 (2048MB), size=   4MB: write-combining, count=1
+===============================================================================
+Creating MTRRs from the shell:
+% echo "base=0x80000000 size=0x400000 type=write-combining" >! /proc/mtrr
+===============================================================================
+Removing MTRRs from the shell:
+% echo "disable=5" >! /proc/mtrr
+===============================================================================
+Reading MTRRs from a C programme using ioctl()'s:
+
+/*  mtrr-show.c
+
+    Source file for mtrr-show (example programme to show MTRRs using ioctl()'s)
+
+    Copyright (C) 1997  Richard Gooch
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+/*
+    This programme will use an ioctl() on /proc/mtrr to show the current MTRR
+    settings. This is an alternative to reading /proc/mtrr.
+
+
+    Written by      Richard Gooch   17-DEC-1997
+
+    Last updated by Richard Gooch   17-DEC-1997
+
+
+*/
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#define MTRR_NEED_STRINGS
+#include <linux/mtrr.h>
+
+#define TRUE 1
+#define FALSE 0
+#define ERRSTRING strerror (errno)
+
+
+int main ()
+{
+    int fd;
+    struct mtrr_gentry gentry;
+
+    if ( ( fd = open ("/proc/mtrr", O_RDONLY, 0) ) == -1 )
+    {
+       if (errno == ENOENT)
+       {
+           fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+                  stderr);
+           exit (1);
+       }
+       fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+       exit (2);
+    }
+    for (gentry.regnum = 0; ioctl (fd, MTRRIOC_GET_ENTRY, &gentry) == 0;
+        ++gentry.regnum)
+    {
+       if (gentry.size < 1)
+       {
+           fprintf (stderr, "Register: %u disabled\n", gentry.regnum);
+           continue;
+       }
+       fprintf (stderr, "Register: %u base: 0x%lx size: 0x%lx type: %s\n",
+                gentry.regnum, gentry.base, gentry.size,
+                mtrr_strings[gentry.type]);
+    }
+    if (errno == EINVAL) exit (0);
+    fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+    exit (3);
+}   /*  End Function main  */
+===============================================================================
+Creating MTRRs from a C programme using ioctl()'s:
+
+/*  mtrr-add.c
+
+    Source file for mtrr-add (example programme to add an MTRRs using ioctl())
+
+    Copyright (C) 1997  Richard Gooch
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+/*
+    This programme will use an ioctl() on /proc/mtrr to add an entry. The first
+    available mtrr is used. This is an alternative to writing /proc/mtrr.
+
+
+    Written by      Richard Gooch   17-DEC-1997
+
+    Last updated by Richard Gooch   17-DEC-1997
+
+
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#define MTRR_NEED_STRINGS
+#include <linux/mtrr.h>
+
+#define TRUE 1
+#define FALSE 0
+#define ERRSTRING strerror (errno)
+
+
+int main (int argc, char **argv)
+{
+    int fd;
+    struct mtrr_sentry sentry;
+
+    if (argc != 4)
+    {
+       fprintf (stderr, "Usage:\tmtrr-add base size type\n");
+       exit (1);
+    }
+    sentry.base = strtoul (argv[1], NULL, 0);
+    sentry.size = strtoul (argv[2], NULL, 0);
+    for (sentry.type = 0; sentry.type < MTRR_NUM_TYPES; ++sentry.type)
+    {
+       if (strcmp (argv[3], mtrr_strings[sentry.type]) == 0) break;
+    }
+    if (sentry.type >= MTRR_NUM_TYPES)
+    {
+       fprintf (stderr, "Illegal type: \"%s\"\n", argv[3]);
+       exit (2);
+    }
+    if ( ( fd = open ("/proc/mtrr", O_WRONLY, 0) ) == -1 )
+    {
+       if (errno == ENOENT)
+       {
+           fputs ("/proc/mtrr not found: not supported or you don't have a PPro?\n",
+                  stderr);
+           exit (3);
+       }
+       fprintf (stderr, "Error opening /proc/mtrr\t%s\n", ERRSTRING);
+       exit (4);
+    }
+    if (ioctl (fd, MTRRIOC_ADD_ENTRY, &sentry) == -1)
+    {
+       fprintf (stderr, "Error doing ioctl(2) on /dev/mtrr\t%s\n", ERRSTRING);
+       exit (5);
+    }
+    fprintf (stderr, "Sleeping for 5 seconds so you can see the new entry\n");
+    sleep (5);
+    close (fd);
+    fputs ("I've just closed /proc/mtrr so now the new entry should be gone\n",
+          stderr);
+}   /*  End Function main  */
+===============================================================================
index 7169a58ff2327ec1cace9e750921fb53d128ecdb..fc2546218ede5d930f723afe7ae0849434a609b4 100644 (file)
@@ -176,7 +176,8 @@ if [ "$CONFIG_PCI" = "y" ]; then
 #  if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
 #    bool 'VGA Console Support' CONFIG_VGA_CONSOLE
 #  fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'PCI quirks' CONFIG_PCI_QUIRKS
+  if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
   fi
   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
index f95b535ca4fca9bf9d594d06151568ca55948b9c..5165279f0da2098e8e86779d86c2039a893bf861 100644 (file)
@@ -37,6 +37,27 @@ unsigned short int csum_tcpudp_magic(unsigned long saddr,
                ((unsigned long) proto << 8));
 }
 
+unsigned int csum_tcpudp_nofold(unsigned long saddr,
+                                  unsigned long daddr,
+                                  unsigned short len,
+                                  unsigned short proto,
+                                  unsigned int sum)
+{
+       unsigned long result;
+
+       result = (saddr + daddr + sum +
+                 ((unsigned long) ntohs(len) << 16) +
+                 ((unsigned long) proto << 8));
+
+       /* Fold down to 32-bits so we don't loose in the typedef-less 
+          network stack.  */
+       /* 64 to 33 */
+       result = (result & 0xffffffff) + (result >> 32);
+       /* 33 to 32 */
+       result = (result & 0xffffffff) + (result >> 32);
+       return result;
+}
+
 /*
  * Do a 64-bit checksum on an arbitrary memory area..
  *
index 1328eeabadefb2d1eb9ee1d52d89b5aabf165552..7130813301d08ad78d87068ad2417e46b65d838d 100644 (file)
@@ -364,6 +364,12 @@ csum_partial_copy_from_user(const char *src, char *dst, int len,
        return do_csum_partial_copy_from_user(src, dst, len, sum, errp);
 }
 
+unsigned int
+csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
+{
+       return do_csum_partial_copy_from_user(src, dst, len, sum, NULL);
+}
+
 unsigned int
 csum_partial_copy (const char *src, char *dst, int len, unsigned int sum)
 {
index 3f3f3a20da23117973754d937fbc968e22aaf8b2..86c214a1e0a8a7d95b6ab2e2794363744533be1d 100644 (file)
@@ -17,6 +17,9 @@ choice 'Processor family' \
         Pentium/K5/5x86/6x86   CONFIG_M586     \
         PPro/K6/6x86MX         CONFIG_M686" Pentium
 bool 'Math emulation' CONFIG_MATH_EMULATION
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
+fi
 endmenu
 
 mainmenu_option next_comment
@@ -36,7 +39,8 @@ bool 'PCI support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
   bool '   PCI BIOS support' CONFIG_PCI_BIOS
   bool '   PCI direct access support' CONFIG_PCI_DIRECT
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool '   PCI quirks' CONFIG_PCI_QUIRKS
+  if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
   fi
   bool '   Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
index eff10066607403089bdaaa21d32d7b8286c24b12..ab1c622c7b042b10277a140c03a70e84727b1985 100644 (file)
@@ -15,7 +15,6 @@
 CONFIG_M586=y
 # CONFIG_M686 is not set
 # CONFIG_MATH_EMULATION is not set
-CONFIG_MAX_MEMSIZE=1024
 
 #
 # Loadable module support
@@ -31,6 +30,7 @@ CONFIG_NET=y
 CONFIG_PCI=y
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
+CONFIG_PCI_QUIRKS=y
 CONFIG_PCI_OLD_PROC=y
 # CONFIG_MCA is not set
 CONFIG_SYSVIPC=y
index ce1e6652db255dc1f2686b08c03f37f0a606800c..6f63d2c9714b8cd784a1235603e9a622038a9b7b 100644 (file)
@@ -21,6 +21,7 @@ O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o \
             ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o
 OX_OBJS  := i386_ksyms.o
+MX_OBJS  :=
 
 ifdef CONFIG_PCI
 O_OBJS += bios32.o
@@ -30,6 +31,14 @@ ifdef CONFIG_MCA
 O_OBJS += mca.o
 endif
 
+ifeq ($(CONFIG_MTRR),y)
+OX_OBJS += mtrr.o
+else
+  ifeq ($(CONFIG_MTRR),m)
+  MX_OBJS += mtrr.o
+  endif
+endif
+
 
 ifdef SMP
 
index a5ec92210f2a36d2d55951147ec32dd829bbd42f..66dec5fedcf339abf16e439aaf93250904221976 100644 (file)
@@ -82,6 +82,8 @@ EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(smp_message_pass);
+EXPORT_SYMBOL(mtrr_hook);
 #endif
 
 #ifdef CONFIG_MCA
index 95568c73ea8758c70e14d40a92ded8e787ae0201..268ed059468da319cb8ec6a754a5eaabe5010bb6 100644 (file)
@@ -240,6 +240,7 @@ BUILD_IRQ(23)
 BUILD_SMP_INTERRUPT(reschedule_interrupt)
 BUILD_SMP_INTERRUPT(invalidate_interrupt)
 BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
+BUILD_SMP_INTERRUPT(mtrr_interrupt)
 
 /*
  * every pentium local APIC has two 'local interrupts', with a
@@ -1106,6 +1107,9 @@ __initfunc(void init_IRQ(void))
        /* self generated IPI for local APIC timer */
        set_intr_gate(0x41, apic_timer_interrupt);
 
+       /* IPI for MTRR control */
+       set_intr_gate(0x50, mtrr_interrupt);
+
 #endif 
        request_region(0x20,0x20,"pic1");
        request_region(0xa0,0x20,"pic2");
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
new file mode 100644 (file)
index 0000000..f2981c5
--- /dev/null
@@ -0,0 +1,1229 @@
+/*  Generic MTRR (Memory Type Range Register) driver.
+
+    Copyright (C) 1997-1998  Richard Gooch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+
+    Source: "Pentium Pro Family Developer's Manual, Volume 3:
+    Operating System Writer's Guide" (Intel document number 242692),
+    section 11.11.7
+
+    ChangeLog
+
+    Prehistory Martin Tischhäuser <martin@ikcbarka.fzk.de>
+              Initial register-setting code (from proform-1.0).
+    19971216   Richard Gooch <rgooch@atnf.csiro.au>
+               Original version for /proc/mtrr interface, SMP-safe.
+  v1.0
+    19971217   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix for ioctls()'s.
+              Added sample code in Documentation/mtrr.txt
+  v1.1
+    19971218   Richard Gooch <rgooch@atnf.csiro.au>
+               Disallow overlapping regions.
+    19971219   Jens Maurer <jmaurer@menuett.rhein-main.de>
+               Register-setting fixups.
+  v1.2
+    19971222   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.75.
+  v1.3
+    19971229   David Wragg <dpw@doc.ic.ac.uk>
+               Register-setting fixups and conformity with Intel conventions.
+    19971229   Richard Gooch <rgooch@atnf.csiro.au>
+               Cosmetic changes and wrote this ChangeLog ;-)
+    19980106   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.78.
+  v1.4
+    19980119   David Wragg <dpw@doc.ic.ac.uk>
+               Included passive-release enable code (elsewhere in PCI setup).
+  v1.5
+    19980131   Richard Gooch <rgooch@atnf.csiro.au>
+               Replaced global kernel lock with private spinlock.
+  v1.6
+    19980201   Richard Gooch <rgooch@atnf.csiro.au>
+               Added wait for other CPUs to complete changes.
+  v1.7
+    19980202   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix in definition of <set_mtrr> for UP.
+  v1.8
+    19980319   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixups for kernel 2.1.90.
+    19980323   Richard Gooch <rgooch@atnf.csiro.au>
+               Move SMP BIOS fixup before secondary CPUs call <calibrate_delay>
+  v1.9
+    19980325   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixed test for overlapping regions: confused by adjacent regions
+    19980326   Richard Gooch <rgooch@atnf.csiro.au>
+               Added wbinvd in <set_mtrr_prepare>.
+    19980401   Richard Gooch <rgooch@atnf.csiro.au>
+               Bug fix for non-SMP compilation.
+    19980418   David Wragg <dpw@doc.ic.ac.uk>
+               Fixed-MTRR synchronisation for SMP and use atomic operations
+              instead of spinlocks.
+    19980418   Richard Gooch <rgooch@atnf.csiro.au>
+              Differentiate different MTRR register classes for BIOS fixup.
+  v1.10
+    19980419   David Wragg <dpw@doc.ic.ac.uk>
+              Bug fix in variable MTRR synchronisation.
+  v1.11
+    19980419   Richard Gooch <rgooch@atnf.csiro.au>
+              Fixups for kernel 2.1.97.
+  v1.12
+    19980421   Richard Gooch <rgooch@atnf.csiro.au>
+              Safer synchronisation across CPUs when changing MTRRs.
+  v1.13
+    19980423   Richard Gooch <rgooch@atnf.csiro.au>
+              Bugfix for SMP systems without MTRR support.
+  v1.14
+    19980427   Richard Gooch <rgooch@atnf.csiro.au>
+              Trap calls to <mtrr_add> and <mtrr_del> on non-MTRR machines.
+  v1.15
+    19980427   Richard Gooch <rgooch@atnf.csiro.au>
+              Use atomic bitops for setting SMP change mask.
+  v1.16
+    19980428   Richard Gooch <rgooch@atnf.csiro.au>
+              Removed spurious diagnostic message.
+  v1.17
+    19980429   Richard Gooch <rgooch@atnf.csiro.au>
+              Moved register-setting macros into this file.
+              Moved setup code from init/main.c to i386-specific areas.
+  v1.18
+*/
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#define MTRR_NEED_STRINGS
+#include <asm/mtrr.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/smp_lock.h>
+#include <asm/atomic.h>
+#include <linux/smp.h>
+
+#define MTRR_VERSION            "1.18 (19980429)"
+
+#define TRUE  1
+#define FALSE 0
+
+#define X86_FEATURE_MTRR       0x1000          /* memory type registers */
+
+#define MTRRcap_MSR     0x0fe
+#define MTRRdefType_MSR 0x2ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define NUM_FIXED_RANGES 88
+#define MTRRfix64K_00000_MSR 0x250
+#define MTRRfix16K_80000_MSR 0x258
+#define MTRRfix16K_A0000_MSR 0x259
+#define MTRRfix4K_C0000_MSR 0x268
+#define MTRRfix4K_C8000_MSR 0x269
+#define MTRRfix4K_D0000_MSR 0x26a
+#define MTRRfix4K_D8000_MSR 0x26b
+#define MTRRfix4K_E0000_MSR 0x26c
+#define MTRRfix4K_E8000_MSR 0x26d
+#define MTRRfix4K_F0000_MSR 0x26e
+#define MTRRfix4K_F8000_MSR 0x26f
+
+#ifdef __SMP__
+#  define MTRR_CHANGE_MASK_FIXED     0x01
+#  define MTRR_CHANGE_MASK_VARIABLE  0x02
+#  define MTRR_CHANGE_MASK_DEFTYPE   0x04
+#endif
+
+/* In the processor's MTRR interface, the MTRR type is always held in
+   an 8 bit field: */
+typedef u8 mtrr_type;
+
+#define LINE_SIZE      80
+#define JIFFIE_TIMEOUT 100
+
+#ifdef __SMP__
+#  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
+#else
+#  define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE)
+#endif
+
+#ifndef CONFIG_PROC_FS
+#  define compute_ascii() while (0)
+#endif
+
+#ifdef CONFIG_PROC_FS
+static char *ascii_buffer = NULL;
+static unsigned int ascii_buf_bytes = 0;
+#endif
+static unsigned int *usage_table = NULL;
+#ifdef __SMP__
+static spinlock_t main_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+/*  Private functions  */
+#ifdef CONFIG_PROC_FS
+static void compute_ascii (void);
+#endif
+
+
+struct set_mtrr_context
+{
+    unsigned long flags;
+    unsigned long deftype_lo;
+    unsigned long deftype_hi;
+    unsigned long cr4val;
+};
+
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+                           : "=a" (val1), "=d" (val2) \
+                           : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+                         : /* no outputs */ \
+                         : "c" (msr), "a" (val1), "d" (val2))
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+                         : "=a" (low), "=d" (high) \
+                         : "c" (counter))
+
+
+/* Put the processor into a state where MTRRs can be safely set. */
+static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
+{
+    unsigned long tmp;
+
+    /* disable interrupts */
+    save_flags(ctxt->flags); cli();
+
+    /* save value of CR4 and clear Page Global Enable (bit 7) */
+    asm volatile ("movl  %%cr4, %0\n\t"
+                 "movl  %0, %1\n\t"
+                 "andb  $0x7f, %b1\n\t"
+                 "movl  %1, %%cr4\n\t"
+                  : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+
+    /* disable and flush caches. Note that wbinvd flushes the TLBs as
+       a side-effect. */
+    asm volatile ("movl  %%cr0, %0\n\t"
+                 "orl   $0x40000000, %0\n\t"
+                 "wbinvd\n\t"
+                 "movl  %0, %%cr0\n\t"
+                 "wbinvd\n\t"
+                 : "=r" (tmp) : : "memory");
+
+    /* disable MTRRs, and set the default type to uncached. */
+    rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+}   /*  End Function set_mtrr_prepare  */
+
+
+/* Restore the processor after a set_mtrr_prepare */
+static void set_mtrr_done(struct set_mtrr_context *ctxt)
+{
+    unsigned long tmp;
+
+    /* flush caches and TLBs */
+    asm volatile ("wbinvd" : : : "memory" );
+
+    /* restore MTRRdefType */
+    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+
+    /* enable caches */
+    asm volatile ("movl  %%cr0, %0\n\t"
+                 "andl  $0xbfffffff, %0\n\t"
+                 "movl  %0, %%cr0\n\t"
+                 : "=r" (tmp) : : "memory");
+
+    /* restore value of CR4 */
+    asm volatile ("movl  %0, %%cr4"
+                  : : "r" (ctxt->cr4val) : "memory");
+
+    /* re-enable interrupts (if enabled previously) */
+    restore_flags(ctxt->flags);
+}   /*  End Function set_mtrr_done  */
+
+
+/* this function returns the number of variable MTRRs */
+static unsigned int get_num_var_ranges (void)
+{
+    unsigned long config, dummy;
+
+    rdmsr(MTRRcap_MSR, config, dummy);
+    return (config & 0xff);
+}   /*  End Function get_num_var_ranges  */
+
+
+/* non-zero if we have the write-combining memory type. */
+static int have_wrcomb (void)
+{
+    unsigned long config, dummy;
+
+    rdmsr(MTRRcap_MSR, config, dummy);
+    return (config & (1<<10));
+}
+
+
+static void get_mtrr (unsigned int reg, unsigned long *base,
+                     unsigned long *size, mtrr_type *type)
+{
+    unsigned long dummy, mask_lo, base_lo;
+
+    rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
+    if ((mask_lo & 0x800) == 0) {
+       /* Invalid (i.e. free) range. */
+       *base = 0;
+       *size = 0;
+       *type = 0;
+       return;
+    }
+
+    rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy);
+
+    /* We ignore the extra address bits (32-35). If someone wants to
+       run x86 Linux on a machine with >4GB memory, this will be the
+       least of their problems. */
+
+    /* Clean up mask_lo so it gives the real address mask. */
+    mask_lo = (mask_lo & 0xfffff000UL);
+    
+    /* This works correctly if size is a power of two, i.e. a
+       contiguous range. */
+    *size = ~(mask_lo - 1);
+
+    *base = (base_lo & 0xfffff000UL);
+    *type = (base_lo & 0xff);
+}   /*  End Function get_mtrr  */
+
+
+static void set_mtrr_up (unsigned int reg, unsigned long base,
+                        unsigned long size, mtrr_type type, int do_safe)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+*/
+{
+    struct set_mtrr_context ctxt;
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    if (size == 0)
+    {
+       /* The invalid bit is kept in the mask, so we simply clear the
+          relevant mask register to disable a range. */
+       wrmsr (MTRRphysMask_MSR (reg), 0, 0);
+    }
+    else
+    {
+       wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
+       wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+    }
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function set_mtrr_up  */
+
+     
+#ifdef __SMP__
+
+struct mtrr_var_range
+{
+    unsigned long base_lo;
+    unsigned long base_hi;
+    unsigned long mask_lo;
+    unsigned long mask_hi;
+};
+
+
+/* Get the MSR pair relating to a var range. */
+__initfunc(static void get_mtrr_var_range (unsigned int index,
+                                          struct mtrr_var_range *vr))
+{
+    rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi);
+    rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi);
+}   /*  End Function get_mtrr_var_range  */
+
+
+/* Set the MSR pair relating to a var range. Returns TRUE if
+   changes are made. */
+__initfunc(static int set_mtrr_var_range_testing (unsigned int index,
+                                                 struct mtrr_var_range *vr))
+{
+    unsigned int lo, hi;
+    int changed = FALSE;
+    
+    rdmsr(MTRRphysBase_MSR(index), lo, hi); 
+
+    if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
+       || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
+       wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); 
+       changed = TRUE;
+    }
+
+    rdmsr(MTRRphysMask_MSR(index), lo, hi); 
+
+    if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
+       || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
+       wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); 
+       changed = TRUE;
+    }
+    
+    return changed;
+}
+
+
+__initfunc(static void get_fixed_ranges(mtrr_type *frs))
+{
+    unsigned long *p = (unsigned long *)frs;
+    int i;
+
+    rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+
+    for (i = 0; i < 2; i++)
+       rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
+    for (i = 0; i < 8; i++)
+       rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
+}
+
+
+__initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
+{
+    unsigned long *p = (unsigned long *)frs;
+    int changed = FALSE;
+    int i;
+    unsigned long lo, hi;
+
+    rdmsr(MTRRfix64K_00000_MSR, lo, hi);
+    if (p[0] != lo || p[1] != hi) {
+       wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+       changed = TRUE;
+    }
+
+    for (i = 0; i < 2; i++) {
+       rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
+       if (p[2 + i*2] != lo || p[3 + i*2] != hi) {
+           wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]);
+           changed = TRUE;
+       }
+    }
+
+    for (i = 0; i < 8; i++) {
+       rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
+       if (p[6 + i*2] != lo || p[7 + i*2] != hi) {
+           wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
+           changed = TRUE;
+       }
+    }
+
+    return changed;
+}
+
+
+struct mtrr_state
+{
+    unsigned int num_var_ranges;
+    struct mtrr_var_range *var_ranges;
+    mtrr_type fixed_ranges[NUM_FIXED_RANGES];
+    unsigned char enabled;
+    mtrr_type def_type;
+};
+
+
+/* Grab all of the mtrr state for this cpu into *state. */
+__initfunc(static void get_mtrr_state(struct mtrr_state *state))
+{
+    unsigned int nvrs, i;
+    struct mtrr_var_range *vrs;
+    unsigned long lo, dummy;
+
+    nvrs = state->num_var_ranges = get_num_var_ranges();
+    vrs = state->var_ranges 
+              = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL);
+    if (vrs == NULL)
+       nvrs = state->num_var_ranges = 0;
+
+    for (i = 0; i < nvrs; i++)
+       get_mtrr_var_range(i, &vrs[i]);
+    
+    get_fixed_ranges(state->fixed_ranges);
+
+    rdmsr(MTRRdefType_MSR, lo, dummy);
+    state->def_type = (lo & 0xff);
+    state->enabled = (lo & 0xc00) >> 10;
+}   /*  End Function get_mtrr_state  */
+
+
+/* Free resources associated with a struct mtrr_state */
+__initfunc(static void finalize_mtrr_state(struct mtrr_state *state))
+{
+    if (state->var_ranges) kfree (state->var_ranges);
+}   /*  End Function finalize_mtrr_state  */
+
+
+__initfunc(static unsigned long set_mtrr_state (struct mtrr_state *state,
+                                               struct set_mtrr_context *ctxt))
+/*  [SUMMARY] Set the MTRR state for this CPU.
+    <state> The MTRR state information to read.
+    <ctxt> Some relevant CPU context.
+    [NOTE] The CPU must already be in a safe state for MTRR changes.
+    [RETURNS] 0 if no changes made, else a mask indication what was changed.
+*/
+{
+    unsigned int i;
+    unsigned long change_mask = 0;
+
+    for (i = 0; i < state->num_var_ranges; i++)
+       if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
+           change_mask |= MTRR_CHANGE_MASK_VARIABLE;
+
+    if (set_fixed_ranges_testing(state->fixed_ranges))
+       change_mask |= MTRR_CHANGE_MASK_FIXED;
+    
+    /* set_mtrr_restore restores the old value of MTRRdefType,
+       so to set it we fiddle with the saved value. */
+    if ((ctxt->deftype_lo & 0xff) != state->def_type
+       || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
+    {
+       ctxt->deftype_lo |= (state->def_type | state->enabled << 10);
+       change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
+    }
+
+    return change_mask;
+}   /*  End Function set_mtrr_state  */
+
+static atomic_t undone_count;
+static void (*handler_func) (struct set_mtrr_context *ctxt, void *info);
+static void *handler_info;
+static volatile int wait_barrier_execute = FALSE;
+static volatile int wait_barrier_cache_enable = FALSE;
+
+static void sync_handler (void)
+/*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
+    [RETURNS] Nothing.
+*/
+{
+    struct set_mtrr_context ctxt;
+
+    set_mtrr_prepare (&ctxt);
+    /*  Notify master CPU that I'm at the barrier and then wait  */
+    atomic_dec (&undone_count);
+    while (wait_barrier_execute) barrier ();
+    /*  The master has cleared me to execute  */
+    (*handler_func) (&ctxt, handler_info);
+    /*  Notify master CPU that I've executed the function  */
+    atomic_dec (&undone_count);
+    /*  Wait for master to clear me to enable cache and return  */
+    while (wait_barrier_cache_enable) barrier ();
+    set_mtrr_done (&ctxt);
+}   /*  End Function sync_handler  */
+
+static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
+                                         void *info),
+                        void *info, int local)
+/*  [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled.
+    [PURPOSE] This function will synchronise all CPUs, flush and disable caches
+    on all CPUs, then call a specified function. When the specified function
+    finishes on all CPUs, caches are enabled on all CPUs.
+    <handler> The function to execute.
+    <info> An arbitrary information pointer which is passed to <<handler>>.
+    <local> If TRUE <<handler>> is executed locally.
+    [RETURNS] Nothing.
+*/
+{
+    unsigned long timeout;
+    struct set_mtrr_context ctxt;
+
+    mtrr_hook = sync_handler;
+    handler_func = handler;
+    handler_info = info;
+    wait_barrier_execute = TRUE;
+    wait_barrier_cache_enable = TRUE;
+    /*  Send a message to all other CPUs and wait for them to enter the
+       barrier  */
+    atomic_set (&undone_count, smp_num_cpus - 1);
+    smp_message_pass (MSG_ALL_BUT_SELF, MSG_MTRR_CHANGE, 0, 0);
+    /*  Wait for it to be done  */
+    timeout = jiffies + JIFFIE_TIMEOUT;
+    while ( (atomic_read (&undone_count) > 0) && (jiffies < timeout) )
+       barrier ();
+    if (atomic_read (&undone_count) > 0)
+    {
+       panic ("mtrr: timed out waiting for other CPUs\n");
+    }
+    mtrr_hook = NULL;
+    /*  All other CPUs should be waiting for the barrier, with their caches
+       already flushed and disabled. Prepare for function completion
+       notification  */
+    atomic_set (&undone_count, smp_num_cpus - 1);
+    /*  Flush and disable the local CPU's cache        and release the barier, which
+       should cause the other CPUs to execute the function. Also execute it
+       locally if required  */
+    set_mtrr_prepare (&ctxt);
+    wait_barrier_execute = FALSE;
+    if (local) (*handler) (&ctxt, info);
+    /*  Now wait for other CPUs to complete the function  */
+    while (atomic_read (&undone_count) > 0) barrier ();
+    /*  Now all CPUs should have finished the function. Release the barrier to
+       allow them to re-enable their caches and return from their interrupt,
+       then enable the local cache and return  */
+    wait_barrier_cache_enable = FALSE;
+    set_mtrr_done (&ctxt);
+    handler_func = NULL;
+    handler_info = NULL;
+}   /*  End Function do_all_cpus  */
+
+
+struct set_mtrr_data
+{
+    unsigned long smp_base;
+    unsigned long smp_size;
+    unsigned int smp_reg;
+    mtrr_type smp_type;
+};
+
+static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info)
+{
+    struct set_mtrr_data *data = info;
+
+    set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type,
+                FALSE);
+}   /*  End Function set_mtrr_handler  */
+
+static void set_mtrr_smp (unsigned int reg, unsigned long base,
+                         unsigned long size, mtrr_type type)
+{
+    struct set_mtrr_data data;
+
+    data.smp_reg = reg;
+    data.smp_base = base;
+    data.smp_size = size;
+    data.smp_type = type;
+    do_all_cpus (set_mtrr_handler, &data, TRUE);
+}   /*  End Function set_mtrr_smp  */
+
+
+/* A warning that is common to the module and non-module cases. */
+/* Some BIOS's are fucked and don't set all MTRRs the same! */
+#ifdef MODULE
+static void mtrr_state_warn (unsigned long mask)
+#else
+__initfunc(static void mtrr_state_warn (unsigned long mask))
+#endif
+{
+    if (!mask) return;
+    if (mask & MTRR_CHANGE_MASK_FIXED)
+       printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
+    if (mask & MTRR_CHANGE_MASK_VARIABLE)
+       printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
+    if (mask & MTRR_CHANGE_MASK_DEFTYPE)
+       printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+    printk ("mtrr: probably your BIOS does not setup all CPUs\n");
+}   /*  End Function mtrr_state_warn  */
+
+#ifdef MODULE
+/* As a module, copy the MTRR state using an IPI handler. */
+
+static volatile unsigned long smp_changes_mask = 0;
+
+static void copy_mtrr_state_handler (struct set_mtrr_context *ctxt, void *info)
+{
+    unsigned long mask, count;
+    struct mtrr_state *smp_mtrr_state = info;
+
+    mask = set_mtrr_state (smp_mtrr_state, ctxt);
+    /*  Use the atomic bitops to update the global mask  */
+    for (count = 0; count < sizeof mask * 8; ++count)
+    {
+       if (mask & 0x01) set_bit (count, &smp_changes_mask);
+       mask >>= 1;
+    }
+}   /*  End Function copy_mtrr_state_handler  */
+
+/* Copies the entire MTRR state of this cpu to all the others. */
+static void copy_mtrr_state (void)
+{
+    struct mtrr_state ms;
+    get_mtrr_state (&ms);
+    do_all_cpus (copy_mtrr_state_handler, &ms, FALSE);
+    finalize_mtrr_state (&ms);
+    mtrr_state_warn (smp_changes_mask);
+}   /*  End Function copy_mtrr_state  */
+
+#endif /* MODULE */
+#endif  /*  __SMP__  */
+
+static char *attrib_to_str (int x)
+{
+    return (x <= 6) ? mtrr_strings[x] : "?";
+}   /*  End Function attrib_to_str  */
+
+static void init_table (void)
+{
+    int i, max;
+
+    max = get_num_var_ranges ();
+    if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) )
+        == NULL )
+    {
+       printk ("mtrr: could not allocate\n");
+       return;
+    }
+    for (i = 0; i < max; i++) usage_table[i] = 1;
+#ifdef CONFIG_PROC_FS
+    if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL )
+    {
+       printk ("mtrr: could not allocate\n");
+       return;
+    }
+    ascii_buf_bytes = 0;
+    compute_ascii ();
+#endif
+}   /*  End Function init_table  */
+
+int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
+             char increment)
+/*  [SUMMARY] Add an MTRR entry.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    <type> The type of the new region.
+    <increment> If true and the region already exists, the usage count will be
+    incremented.
+    [RETURNS] The MTRR register on success, else a negative number indicating
+    the error code.
+    [NOTE] This routine uses a spinlock.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize, last;
+
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+    if ( (base & 0xfff) || (size & 0xfff) )
+    {
+       printk ("mtrr: size and base must be multiples of 4kB\n");
+       printk ("mtrr: size: %lx  base: %lx\n", size, base);
+       return -EINVAL;
+    }
+    if (base + size < 0x100000)
+    {
+       printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
+               base, size);
+       return -EINVAL;
+    }
+    /*  Check upper bits of base and last are equal and lower bits are 0 for
+       base and 1 for last  */
+    last = base + size - 1;
+    for (lbase = base; !(lbase & 1) && (last & 1);
+        lbase = lbase >> 1, last = last >> 1);
+    if (lbase != last)
+    {
+       printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+               base, size);
+       return -EINVAL;
+    }
+    if (type >= MTRR_NUM_TYPES)
+    {
+       printk ("mtrr: type: %u illegal\n", type);
+       return -EINVAL;
+    }
+    /*  If the type is WC, check that this processor supports it  */
+    if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
+    {
+        printk ("mtrr: your processor doesn't support write-combining\n");
+        return -ENOSYS;
+    }
+    increment = increment ? 1 : 0;
+    max = get_num_var_ranges ();
+    /*  Search for existing MTRR  */
+    spin_lock (&main_lock);
+    for (i = 0; i < max; ++i)
+    {
+       get_mtrr (i, &lbase, &lsize, &ltype);
+       if (base >= lbase + lsize) continue;
+       if ( (base < lbase) && (base + size <= lbase) ) continue;
+       /*  At this point we know there is some kind of overlap/enclosure  */
+       if ( (base < lbase) || (base + size > lbase + lsize) )
+       {
+           spin_unlock (&main_lock);
+           printk ("mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
+                   base, size, lbase, lsize);
+           return -EINVAL;
+       }
+       if (ltype != type)
+       {
+           spin_unlock (&main_lock);
+           printk ( "mtrr: type missmatch for %lx,%lx old: %s new: %s\n",
+                    base, size, attrib_to_str (ltype), attrib_to_str (type) );
+           return -EINVAL;
+       }
+       if (increment) ++usage_table[i];
+       compute_ascii ();
+       spin_unlock (&main_lock);
+       return i;
+    }
+    /*  Search for an empty MTRR  */
+    for (i = 0; i < max; ++i)
+    {
+       get_mtrr (i, &lbase, &lsize, &ltype);
+       if (lsize > 0) continue;
+       set_mtrr (i, base, size, type);
+       usage_table[i] = 1;
+       compute_ascii ();
+       spin_unlock (&main_lock);
+       return i;
+    }
+    spin_unlock (&main_lock);
+    printk ("mtrr: no more MTRRs available\n");
+    return -ENOSPC;
+}   /*  End Function mtrr_add  */
+
+int mtrr_del (int reg, unsigned long base, unsigned long size)
+/*  [SUMMARY] Delete MTRR/decrement usage count.
+    <reg> The register. If this is less than 0 then <<base>> and <<size>> must
+    be supplied.
+    <base> The base address of the region. This is ignored if <<reg>> is >= 0.
+    <size> The size of the region. This is ignored if <<reg>> is >= 0.
+    [RETURNS] The register on success, else a negative number indicating
+    the error code.
+    [NOTE] This routine uses a spinlock.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+    max = get_num_var_ranges ();
+    spin_lock (&main_lock);
+    if (reg < 0)
+    {
+       /*  Search for existing MTRR  */
+       for (i = 0; i < max; ++i)
+       {
+           get_mtrr (i, &lbase, &lsize, &ltype);
+           if ( (lbase == base) && (lsize == size) )
+           {
+               reg = i;
+               break;
+           }
+       }
+       if (reg < 0)
+       {
+           spin_unlock (&main_lock);
+           printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
+           return -EINVAL;
+       }
+    }
+    if (reg >= max)
+    {
+       spin_unlock (&main_lock);
+       printk ("mtrr: register: %d too big\n", reg);
+       return -EINVAL;
+    }
+    get_mtrr (reg, &lbase, &lsize, &ltype);
+    if (lsize < 1)
+    {
+       spin_unlock (&main_lock);
+       printk ("mtrr: MTRR %d not used\n", reg);
+       return -EINVAL;
+    }
+    if (usage_table[reg] < 1)
+    {
+       spin_unlock (&main_lock);
+       printk ("mtrr: reg: %d has count=0\n", reg);
+       return -EINVAL;
+    }
+    if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
+    compute_ascii ();
+    spin_unlock (&main_lock);
+    return reg;
+}   /*  End Function mtrr_del  */
+
+#ifdef CONFIG_PROC_FS
+
+static int mtrr_file_add (unsigned long base, unsigned long size,
+                         unsigned int type, char increment, struct file *file)
+{
+    int reg, max;
+    unsigned int *fcount = file->private_data;
+
+    max = get_num_var_ranges ();
+    if (fcount == NULL)
+    {
+       if ( ( fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL) ) == NULL )
+       {
+           printk ("mtrr: could not allocate\n");
+           return -ENOMEM;
+       }
+       memset (fcount, 0, max * sizeof *fcount);
+       file->private_data = fcount;
+    }
+    reg = mtrr_add (base, size, type, 1);
+    if (reg >= 0) ++fcount[reg];
+    return reg;
+}   /*  End Function mtrr_file_add  */
+
+static int mtrr_file_del (unsigned long base, unsigned long size,
+                         struct file *file)
+{
+    int reg;
+    unsigned int *fcount = file->private_data;
+
+    reg = mtrr_del (-1, base, size);
+    if (reg < 0) return reg;
+    if (fcount != NULL) --fcount[reg];
+    return reg;
+}   /*  End Function mtrr_file_del  */
+
+static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
+                         loff_t *ppos)
+{
+    if (*ppos >= ascii_buf_bytes) return 0;
+    if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos;
+    if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT;
+    *ppos += len;
+    return len;
+}   /*  End Function mtrr_read  */
+
+static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
+                          loff_t *ppos)
+/*  Format of control line:
+    "base=%lx size=%lx type=%s"     OR:
+    "disable=%d"
+*/
+{
+    int i, err;
+    unsigned long reg, base, size;
+    char *ptr;
+    char line[LINE_SIZE];
+
+    if ( !suser () ) return -EPERM;
+    /*  Can't seek (pwrite) on this device  */
+    if (ppos != &file->f_pos) return -ESPIPE;
+    memset (line, 0, LINE_SIZE);
+    if (len > LINE_SIZE) len = LINE_SIZE;
+    if ( copy_from_user (line, buf, len - 1) ) return -EFAULT;
+    ptr = line + strlen (line) - 1;
+    if (*ptr == '\n') *ptr = '\0';
+    if ( !strncmp (line, "disable=", 8) )
+    {
+       reg = simple_strtoul (line + 8, &ptr, 0);
+       err = mtrr_del (reg, 0, 0);
+       if (err < 0) return err;
+       return len;
+    }
+    if ( strncmp (line, "base=", 5) )
+    {
+       printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
+       return -EINVAL;
+    }
+    base = simple_strtoul (line + 5, &ptr, 0);
+    for (; isspace (*ptr); ++ptr);
+    if ( strncmp (ptr, "size=", 5) )
+    {
+       printk ("mtrr: no \"size=\" in line: \"%s\"\n", line);
+       return -EINVAL;
+    }
+    size = simple_strtoul (ptr + 5, &ptr, 0);
+    for (; isspace (*ptr); ++ptr);
+    if ( strncmp (ptr, "type=", 5) )
+    {
+       printk ("mtrr: no \"type=\" in line: \"%s\"\n", line);
+       return -EINVAL;
+    }
+    ptr += 5;
+    for (; isspace (*ptr); ++ptr);
+    for (i = 0; i < MTRR_NUM_TYPES; ++i)
+    {
+       if ( strcmp (ptr, mtrr_strings[i]) ) continue;
+       err = mtrr_add (base, size, i, 1);
+       if (err < 0) return err;
+       return len;
+    }
+    printk ("mtrr: illegal type: \"%s\"\n", ptr);
+    return -EINVAL;
+}   /*  End Function mtrr_write  */
+
+static int mtrr_ioctl (struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+    int err;
+    mtrr_type type;
+    struct mtrr_sentry sentry;
+    struct mtrr_gentry gentry;
+
+    switch (cmd)
+    {
+      default:
+       return -ENOIOCTLCMD;
+      case MTRRIOC_ADD_ENTRY:
+       if ( !suser () ) return -EPERM;
+       if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+           return -EFAULT;
+       err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file);
+       if (err < 0) return err;
+       break;
+      case MTRRIOC_SET_ENTRY:
+       if ( !suser () ) return -EPERM;
+       if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+           return -EFAULT;
+       err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
+       if (err < 0) return err;
+       break;
+      case MTRRIOC_DEL_ENTRY:
+       if ( !suser () ) return -EPERM;
+       if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+           return -EFAULT;
+       err = mtrr_file_del (sentry.base, sentry.size, file);
+       if (err < 0) return err;
+       break;
+      case MTRRIOC_GET_ENTRY:
+       if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
+           return -EFAULT;
+       if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
+       get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+       gentry.type = type;
+       if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
+            return -EFAULT;
+       break;
+    }
+    return 0;
+}   /*  End Function mtrr_ioctl  */
+
+static int mtrr_open (struct inode *ino, struct file *filep)
+{
+    MOD_INC_USE_COUNT;
+    return 0;
+}   /*  End Function mtrr_open  */
+
+static int mtrr_close (struct inode *ino, struct file *file)
+{
+    int i, max;
+    unsigned int *fcount = file->private_data;
+
+    MOD_DEC_USE_COUNT;
+    if (fcount == NULL) return 0;
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; ++i)
+    {
+       while (fcount[i] > 0)
+       {
+           if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i);
+           --fcount[i];
+       }
+    }
+    kfree (fcount);
+    file->private_data = NULL;
+    return 0;
+}   /*  End Function mtrr_close  */
+
+static struct file_operations mtrr_fops =
+{
+    NULL,        /*  Seek              */
+    mtrr_read,   /*  Read              */
+    mtrr_write,  /*  Write             */
+    NULL,        /*  Readdir           */
+    NULL,        /*  Poll              */
+    mtrr_ioctl,  /*  IOctl             */
+    NULL,        /*  MMAP              */
+    mtrr_open,   /*  Open              */
+    mtrr_close,  /*  Release           */
+    NULL,        /*  Fsync             */
+    NULL,        /*  Fasync            */
+    NULL,        /*  CheckMediaChange  */
+    NULL,        /*  Revalidate        */
+    NULL,        /*  Lock              */
+};
+
+static struct inode_operations proc_mtrr_inode_operations = {
+       &mtrr_fops,             /* default property file-ops */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL                    /* permission */
+};
+
+static struct proc_dir_entry proc_root_mtrr = {
+       PROC_MTRR, 4, "mtrr",
+       S_IFREG | S_IWUSR | S_IRUGO, 1, 0, 0,
+       0, &proc_mtrr_inode_operations
+};
+
+static void compute_ascii (void)
+{
+    char factor;
+    int i, max;
+    mtrr_type type;
+    unsigned long base, size;
+
+    ascii_buf_bytes = 0;
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; i++)
+    {
+       get_mtrr (i, &base, &size, &type);
+       if (size < 1) usage_table[i] = 0;
+       else
+       {
+           if (size < 0x100000)
+           {
+               /* 1MB */
+               factor = 'k';
+               size >>= 10;
+           }
+           else
+           {
+               factor = 'M';
+               size >>= 20;
+           }
+           sprintf
+               (ascii_buffer + ascii_buf_bytes,
+                "reg%02i: base=0x%08lx (%4liMB), size=%4li%cB: %s, count=%d\n",
+                i, base, base>>20, size, factor,
+                attrib_to_str (type), usage_table[i]);
+           ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
+       }
+    }
+    proc_root_mtrr.size = ascii_buf_bytes;
+}   /*  End Function compute_ascii  */
+
+#endif  /*  CONFIG_PROC_FS  */
+
+EXPORT_SYMBOL(mtrr_add);
+EXPORT_SYMBOL(mtrr_del);
+
+#if defined(__SMP__) && !defined(MODULE)
+
+static volatile unsigned long smp_changes_mask __initdata = 0;
+static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
+
+__initfunc(void mtrr_init_boot_cpu (void))
+{
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
+
+    get_mtrr_state (&smp_mtrr_state);
+}   /*  End Function mtrr_init_boot_cpu  */
+
+__initfunc(void mtrr_init_secondary_cpu (void))
+{
+    unsigned long mask, count;
+    struct set_mtrr_context ctxt;
+
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    /*  Note that this is not ideal, since the cache is only flushed/disabled
+       for this CPU while the MTRRs are changed, but changing this requires
+       more invasive changes to the way the kernel boots  */
+    set_mtrr_prepare (&ctxt);
+    mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
+    set_mtrr_done (&ctxt);
+    /*  Use the atomic bitops to update the global mask  */
+    for (count = 0; count < sizeof mask * 8; ++count)
+    {
+       if (mask & 0x01) set_bit (count, &smp_changes_mask);
+       mask >>= 1;
+    }
+}   /*  End Function mtrr_init_secondary_cpu  */
+
+#endif
+
+#ifdef MODULE
+int init_module (void)
+#else
+__initfunc(int mtrr_init(void))
+#endif
+{
+#  if !defined(__SMP__) || defined(MODULE) 
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
+    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
+#endif
+
+#  ifdef __SMP__
+#    ifdef MODULE
+    copy_mtrr_state ();
+#    else /* MODULE */
+    finalize_mtrr_state (&smp_mtrr_state);
+    mtrr_state_warn (smp_changes_mask);
+#    endif /* MODULE */
+#  endif /* __SMP__ */
+
+#  ifdef CONFIG_PROC_FS
+    proc_register (&proc_root, &proc_root_mtrr);
+#  endif
+
+    init_table ();
+    return 0;
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+#  ifdef CONFIG_PROC_FS
+    proc_unregister (&proc_root, PROC_MTRR);
+#  endif
+#    ifdef __SMP__
+    mtrr_hook = NULL;
+#    endif
+}
+#endif
index f5f92c2baf43f9008e1adfa5354559ae681ce434..b7c6ad7f25349272f964c212be9965692be9e7e3 100644 (file)
 #include <asm/smp.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_MTRR
+#  include <asm/mtrr.h>
+#endif
+
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
@@ -669,6 +673,10 @@ extern int cpu_idle(void * unused);
  */
 __initfunc(int start_secondary(void *unused))
 {
+#ifdef CONFIG_MTRR
+       /*  Must be done before calibration delay is computed  */
+       mtrr_init_secondary_cpu ();
+#endif
        smp_callin();
        while (!smp_commenced)
                barrier();
@@ -729,7 +737,7 @@ __initfunc(static void do_boot_cpu(int i))
        /* start_eip had better be page-aligned! */
        start_eip = setup_trampoline();
 
-       printk("Booting processor %d eip %lx", i, start_eip); /* So we see what's up   */
+       printk("Booting processor %d eip %lx\n", i, start_eip); /* So we see what's up   */
        stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
 
        /*
@@ -908,6 +916,10 @@ __initfunc(void smp_boot_cpus(void))
        int i;
        unsigned long cfg;
 
+#ifdef CONFIG_MTRR
+       /*  Must be done before other processors booted  */
+       mtrr_init_boot_cpu ();
+#endif
        /*
         *      Initialize the logical to physical cpu number mapping
         *      and the per-CPU profiling counter/multiplier
@@ -940,7 +952,7 @@ __initfunc(void smp_boot_cpus(void))
        {
                printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
                io_apic_irqs = 0;
-               return;
+               goto smp_done;
        }
 
        /*
@@ -1099,6 +1111,12 @@ __initfunc(void smp_boot_cpus(void))
         * go and set it up:
         */
        setup_IO_APIC();
+
+smp_done:
+#ifdef CONFIG_MTRR
+       /*  Must be done after other processors booted  */
+       mtrr_init ();
+#endif
 }
 
 
@@ -1189,6 +1207,10 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
                        irq = 0x40;
                        break;
 
+               case MSG_MTRR_CHANGE:
+                       irq = 0x50;
+                       break;
+
                default:
                        printk("Unknown SMP message %d\n", msg);
                        return;
@@ -1487,6 +1509,14 @@ asmlinkage void smp_stop_cpu_interrupt(void)
        for  (;;) ;
 }
 
+void (*mtrr_hook) (void) = NULL;
+
+asmlinkage void smp_mtrr_interrupt(void)
+{
+       ack_APIC_irq ();
+       if (mtrr_hook) (*mtrr_hook) ();
+}
+
 /*
  * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
  * per second. We assume that the caller has already set up the local
index 47bdd99871064842068f35d7e5aa3c60aa22401a..4ab631988825348ac3b877fb2fb8a4511eac7eb5 100644 (file)
@@ -48,7 +48,10 @@ else
   define_bool CONFIG_PCI y
 fi
 if [ "$CONFIG_PREP" = "y" ]; then
-  bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+  bool 'PCI quirks' CONFIG_PCI_QUIRKS
+  if [ "$CONFIG_PCI_QUIRKS" = "y" ]; then
+    bool '   PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+  fi
 fi
 bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 bool 'Networking support' CONFIG_NET
index 21d7e07f621a6f5e1d22fab233abddba4e594cda..a323e652e17b57fa1da143bc9513b45417d9669d 100644 (file)
@@ -23,6 +23,7 @@ CONFIG_MODULES=y
 CONFIG_MODVERSIONS=y
 CONFIG_KERNELD=y
 CONFIG_PCI=y
+# CONFIG_PCI_QUIRKS is not set
 # CONFIG_PCI_OPTIMIZE is not set
 CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
index ba587264500e3e63ecf5d1910418b7f4fb50d5ec..2d663640e37eba4b1af27c1d4c1f22b080b0c2ee 100644 (file)
@@ -28,7 +28,7 @@ L_OBJS   += oldproc.o
 endif
 endif
 
-ifdef CONFIG_PCI_OPTIMIZE
+ifdef CONFIG_PCI_QUIRKS
 L_OBJS   += quirks.o
 endif
 
index 001c6b34c4d33691e730658dc0252a84e9034f7c..f944e1fd5d9bbd50df5eef3bbe00d22adcc2d835 100644 (file)
@@ -319,7 +319,7 @@ __initfunc(void pci_init(void))
        /* give BIOS a chance to apply platform specific fixes: */
        pcibios_fixup();
 
-#ifdef CONFIG_PCI_OPTIMIZE
+#ifdef CONFIG_PCI_QUIRKS
        pci_quirks_init();
 #endif
 
index 1c2cc969d3400f2769ff53efae9df55254854bc7..3c340cbdefa7efd2b24a4a13b0d05fc77f713fa0 100644 (file)
@@ -19,6 +19,8 @@
 
 #undef DEBUG
 
+#ifdef CONFIG_PCI_OPTIMIZE
+
 /*
  *     The PCI Bridge Optimization -- Some BIOS'es are too lazy
  *     and are unable to turn on several features which can burst
@@ -103,35 +105,87 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos))
        }
 }
 
+#endif
+
+
+/* Deal with broken BIOS'es that neglect to enable passive release,
+   which can cause problems in combination with the 82441FX/PPro MTRRs */
+__initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg))
+{
+       struct pci_dev *piix3;
+       unsigned char dlc;
+
+       /* We have to make sure a particular bit is set in the PIIX3
+          ISA bridge, so we have to go out and find it. */
+       for (piix3 = pci_devices; ; piix3 = piix3->next) {
+               if (!piix3)
+                       return;
+
+               if (piix3->vendor == PCI_VENDOR_ID_INTEL
+                   && piix3->device == PCI_DEVICE_ID_INTEL_82371SB_0)
+                       break;
+       }       
+
+       pcibios_read_config_byte(piix3->bus->number, piix3->devfn, 0x82, &dlc);
+
+       if (!(dlc & 1<<1)) {
+               printk("PIIX3: Enabling Passive Release\n");
+               dlc |= 1<<1;
+               pcibios_write_config_byte(piix3->bus->number, piix3->devfn, 
+                                         0x82, dlc);
+       }
+}
+
+
+typedef void (*quirk_handler)(struct pci_dev *, int);
+
 /*
- * Table of quirk handler functions
+ * Mpping from quirk handler functions to names.
  */
 
-#define Q_BRIDGE 0
-
-struct quirk_type {
-       void (*handler)(struct pci_dev *, int);
+struct quirk_name {
+       quirk_handler handler;
        char *name;
 };
 
-static struct quirk_type quirk_types[] __initdata = {
+static struct quirk_name quirk_names[] __initdata = {
+#ifdef CONFIG_PCI_OPTIMIZE
        { quirk_bridge,         "Bridge optimization" },
+#endif
+       { quirk_passive_release, "Passive release enable" },
 };
 
+
+static inline char *get_quirk_name(quirk_handler handler)
+{
+       int i;
+
+       for (i = 0; i < sizeof(quirk_names)/sizeof(quirk_names[0]); i++)
+               if (handler == quirk_names[i].handler)
+                       return quirk_names[i].name;
+
+       return NULL;
+}
+  
+
 /*
  * Mapping from PCI vendor/device ID pairs to quirk function types and arguments
  */
 
 struct quirk_info {
        unsigned short vendor, device;
-       unsigned short quirk, arg;
+       quirk_handler handler;
+       unsigned short arg;
 };
 
 static struct quirk_info quirk_list[] __initdata = {
-       { PCI_VENDOR_ID_DEC,    PCI_DEVICE_ID_DEC_BRD,          Q_BRIDGE,       0x00 },
-       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8891A,      Q_BRIDGE,       0x01 },
-       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82424,      Q_BRIDGE,       0x00 },
-       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82434,      Q_BRIDGE,       0x00 }
+#ifdef CONFIG_PCI_OPTIMIZE
+       { PCI_VENDOR_ID_DEC,    PCI_DEVICE_ID_DEC_BRD,          quirk_bridge,   0x00 },
+       { PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8891A,      quirk_bridge,   0x01 },
+       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82424,      quirk_bridge,   0x00 },
+       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82434,      quirk_bridge,   0x00 },
+#endif
+       { PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82441,      quirk_passive_release,  0x00 },
 };
 
 __initfunc(void pci_quirks_init(void))
@@ -146,11 +200,10 @@ __initfunc(void pci_quirks_init(void))
                for(i=0; i<sizeof(quirk_list)/sizeof(quirk_list[0]); i++) {
                        struct quirk_info *q = quirk_list + i;
                        if (q->vendor == d->vendor && q->device == d->device) {
-                               struct quirk_type *t = quirk_types + q->quirk;
                                printk("PCI: %02x:%02x [%04x/%04x]: %s (%02x)\n",
                                       d->bus->number, d->devfn, d->vendor, d->device,
-                                      t->name, q->arg);
-                               t->handler(d, q->arg);
+                                      get_quirk_name(q->handler), q->arg);
+                               q->handler(d, q->arg);
                        }
                }
        }
index 6cf76c5a7efa2915c753ed6f9f5ae2fd0f387fe3..2f6b82e6c7e2bec1f6d5d805046711d3c1caccea 100644 (file)
@@ -18,6 +18,10 @@ extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
                                           unsigned short proto,
                                           unsigned int sum);
 
+unsigned int csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
+                               unsigned short len, unsigned short proto,
+                               unsigned int sum);
+
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
@@ -55,6 +59,9 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int
  */
 unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
 
+unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum);
+
+
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
index d947f77332cfc932b3ac3cc66b0ef2662a7821ed..af144354f6d7825d3eb67603ca55e98e500bab5b 100644 (file)
 #include <linux/config.h>
 #include <asm/processor.h>
 
+#ifdef CONFIG_MTRR
+#  include <asm/mtrr.h>
+#endif
+
 #define CONFIG_BUGi386
 
 __initfunc(static void no_halt(char *s, int *ints))
@@ -236,4 +240,10 @@ __initfunc(static void check_bugs(void))
        check_amd_k6();
        check_pentium_f00f();
        system_utsname.machine[1] = '0' + boot_cpu_data.x86;
+#if !defined(__SMP__) && defined(CONFIG_MTRR)
+       /*  Must be done after other processors booted: at this point we are
+           called before SMP initialisation, so this is for the non-SMP case
+           only. The SMP case is handled in arch/i386/kernel/smp.c  */
+       mtrr_init ();
+#endif
 }
index 284a30ee4bcef30e8c43561b113ab7d09526def8..4d7a66fdf888f0f4336120dcb55f4ecd7015b25a 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _I386_CHECKSUM_H
 #define _I386_CHECKSUM_H
 
+
 /*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
@@ -44,6 +45,12 @@ unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
        return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, dst_err_ptr);
 }
 
+#if 0
+
+/* Not used at the moment. It is difficult to imagine for what purpose
+   it can be used :-) Please, do not forget to verify_area before it --ANK
+ */
+
 /*
  * This combination is currently not used, but possible:
  */
@@ -56,6 +63,7 @@ unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
 
        return csum_partial_copy_generic ( src, dst, len, sum, src_err_ptr, err_ptr);
 }
+#endif
 
 /*
  * These are the old (and unsafe) way of doing checksums, a warning message will be
@@ -121,16 +129,12 @@ static inline unsigned int csum_fold(unsigned int sum)
        return (~sum) >> 16;
 }
  
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-
-static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
                                                   unsigned long daddr,
                                                   unsigned short len,
                                                   unsigned short proto,
-                                                  unsigned int sum) {
+                                                  unsigned int sum) 
+{
     __asm__("
        addl %1, %0
        adcl %2, %0
@@ -139,8 +143,22 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
        "
        : "=r" (sum)
        : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
-       return csum_fold(sum);
+    return sum;
 }
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum) 
+{
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
new file mode 100644 (file)
index 0000000..da61bf5
--- /dev/null
@@ -0,0 +1,102 @@
+/*  Generic MTRR (Memory Type Range Register) ioctls.
+
+    Copyright (C) 1997-1998  Richard Gooch
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
+    The postal address is:
+      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+#ifndef _LINUX_MTRR_H
+#define _LINUX_MTRR_H
+
+#include <linux/ioctl.h>
+
+#define        MTRR_IOCTL_BASE 'M'
+
+struct mtrr_sentry
+{
+    unsigned long base;    /*  Base address     */
+    unsigned long size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+struct mtrr_gentry
+{
+    unsigned int regnum;   /*  Register number  */
+    unsigned long base;    /*  Base address     */
+    unsigned long size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+/*  These are the various ioctls  */
+#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry)
+#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry)
+#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry)
+#define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
+
+/*  These are the region types  */
+#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_WRCOMB     1
+/*#define MTRR_TYPE_         2*/
+/*#define MTRR_TYPE_         3*/
+#define MTRR_TYPE_WRTHROUGH  4
+#define MTRR_TYPE_WRPROT     5
+#define MTRR_TYPE_WRBACK     6
+#define MTRR_NUM_TYPES       7
+
+#ifdef MTRR_NEED_STRINGS
+static char *mtrr_strings[MTRR_NUM_TYPES] =
+{
+    "uncachable",               /* 0 */
+    "write-combining",          /* 1 */
+    "?",                        /* 2 */
+    "?",                        /* 3 */
+    "write-through",            /* 4 */
+    "write-protect",            /* 5 */
+    "write-back",               /* 6 */
+};
+#endif
+
+#ifdef __KERNEL__
+
+/*  The following functions are for use by other drivers  */
+# if defined(CONFIG_MTRR) || defined(CONFIG_MTRR_MODULE)
+extern int mtrr_add (unsigned long base, unsigned long size,
+                    unsigned int type, char increment);
+extern int mtrr_del (int reg, unsigned long base, unsigned long size);
+#  else
+static __inline__ int mtrr_add (unsigned long base, unsigned long size,
+                               unsigned int type, char increment)
+{
+    return -ENODEV;
+}
+static __inline__ mtrr_del (int reg, unsigned long base, unsigned long size)
+{
+    return -ENODEV;
+}
+#  endif
+
+/*  The following functions are for initialisation: don't use them!  */
+extern int mtrr_init (void);
+#  if defined(__SMP__) && defined(CONFIG_MTRR)
+extern void mtrr_init_boot_cpu (void);
+extern void mtrr_init_secondary_cpu (void);
+#  endif
+
+#endif
+
+#endif  /*  _LINUX_MTRR_H  */
index e73d3b1c18099c48e0dc506999ed3c4c0d5735c3..96c2d2764632ea7feebb3cb7973ae90ff2691de7 100644 (file)
@@ -168,6 +168,7 @@ extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
 extern unsigned long ipi_count;
 extern void smp_invalidate_rcv(void);          /* Process an NMI */
 extern void smp_local_timer_interrupt(struct pt_regs * regs);
+extern void (*mtrr_hook) (void);
 extern void setup_APIC_clock (void);
 extern volatile int __cpu_logical_map[NR_CPUS];
 extern inline int cpu_logical_map(int cpu)
index 64adc2a4e359929b8b8d48dd8a9108efc0a4f22b..8b7f9d16208b706e6834eb9ea5fa0b776d747138 100644 (file)
@@ -87,8 +87,8 @@ static inline unsigned int csum_fold(unsigned int sum)
  * returns a 16-bit checksum, already complemented
  */
 
-static inline unsigned short int
-csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+static inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
                  unsigned short proto, unsigned int sum)
 {
        __asm__ ("addl  %1,%0\n\t"
@@ -99,7 +99,14 @@ csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
                 : "=&d" (sum), "=&d" (saddr)
                 : "0" (daddr), "1" (saddr), "d" (len + proto),
                   "d"(sum));
-       return csum_fold(sum);
+       return sum;
+}
+
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+                 unsigned short proto, unsigned int sum)
+{
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
 }
 
 /*
index 1395cb0aae1a874429d333c688410a1a30a88fb0..1c18664bc22d0190d2dbaf7ea9a9ca5833ceedf2 100644 (file)
@@ -34,6 +34,9 @@ extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
 #define csum_partial_copy_from_user(src, dst, len, sum, errp)  \
        csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
 
+/* FIXME: this needs to be written to really do no check -- Cort */
+#define csum_partial_copy_nocheck(src, dst, len, sum)  \
+       csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)     
 /*
  * Old versions which ignore errors.
  */
@@ -69,6 +72,27 @@ static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
        return csum_fold(csum_partial(buff, len, 0));
 }
 
+/*
+ * FIXME: I swiped this one from the sparc and made minor modifications.
+ * It may not be correct.  -- Cort
+ */
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum) 
+{
+    __asm__("
+       add %0,%0,%1
+       add %0,%0,%2
+       add %0,%0,%0
+       addi %0,%0,0
+       "
+       : "=r" (sum)
+       : "r" (daddr), "r"(saddr), "r"((ntohs(len)<<16)+proto*256), "0"(sum));
+    return sum;
+}
+
 /*
  * This is a version of ip_compute_csum() optimized for IP headers,
  * which always checksum on 4 octet boundaries.  ihl is the number
index 85311970c19fa145e75034d77ef62826157a8dbd..90bb1976a342ff4268bee61cc6cd45bec08218a6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.27 1997/04/11 00:42:18 davem Exp $ */
+/* $Id: checksum.h,v 1.28 1998/04/17 02:37:25 davem Exp $ */
 #ifndef __SPARC_CHECKSUM_H
 #define __SPARC_CHECKSUM_H
 
@@ -158,10 +158,22 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
        return sum;
 }
 
-/* computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
+/* Fold a partial checksum without adding pseudo headers. */
+extern __inline__ unsigned int csum_fold(unsigned int sum)
+{
+       unsigned int tmp;
+
+       __asm__ __volatile__("addcc\t%0, %1, %1\n\t"
+                            "srl\t%1, 16, %1\n\t"
+                            "addx\t%1, %%g0, %1\n\t"
+                            "xnor\t%%g0, %1, %0"
+                            : "=&r" (sum), "=r" (tmp)
+                            : "0" (sum), "1" (sum<<16)
+                            : "cc");
+       return sum;
+}
+
+extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
                                                   unsigned long daddr,
                                                   unsigned int len,
                                                   unsigned short proto,
@@ -171,11 +183,6 @@ extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
                             "addxcc\t%2, %0, %0\n\t"
                             "addxcc\t%3, %0, %0\n\t"
                             "addx\t%0, %%g0, %0\n\t"
-                            "sll\t%0, 16, %1\n\t"
-                            "addcc\t%1, %0, %0\n\t"
-                            "srl\t%0, 16, %0\n\t"
-                            "addx\t%0, %%g0, %0\n\t"
-                            "xnor\t%%g0, %0, %0"
                             : "=r" (sum), "=r" (saddr)
                             : "r" (daddr), "r" ((proto<<16)+len), "0" (sum),
                               "1" (saddr)
@@ -183,19 +190,17 @@ extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
        return sum;
 }
 
-/* Fold a partial checksum without adding pseudo headers. */
-extern __inline__ unsigned int csum_fold(unsigned int sum)
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum) 
 {
-       unsigned int tmp;
-
-       __asm__ __volatile__("addcc\t%0, %1, %1\n\t"
-                            "srl\t%1, 16, %1\n\t"
-                            "addx\t%1, %%g0, %1\n\t"
-                            "xnor\t%%g0, %1, %0"
-                            : "=&r" (sum), "=r" (tmp)
-                            : "0" (sum), "1" (sum<<16)
-                            : "cc");
-       return sum;
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
index bb32044c05df78611109e3e9dac554d11438bd59..e3da2651a29bd6e919ac21be5351b9a0b9b63316 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.10 1997/08/09 18:09:03 jj Exp $ */
+/* $Id: checksum.h,v 1.11 1998/04/17 02:37:22 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -116,10 +116,23 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
        return sum;
 }
 
-/* computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
+/* Fold a partial checksum without adding pseudo headers. */
+extern __inline__ unsigned short csum_fold(unsigned int sum)
+{
+       unsigned int tmp;
+
+       __asm__ __volatile__("
+       addcc           %0, %1, %1
+       srl             %1, 16, %1
+       addc            %1, %%g0, %1
+       xnor            %%g0, %1, %0
+"      : "=&r" (sum), "=r" (tmp)
+       : "0" (sum), "1" (sum<<16)
+       : "cc");
+       return (sum & 0xffff);
+}
+
+extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
                                                   unsigned long daddr,
                                                   unsigned int len,
                                                   unsigned short proto,
@@ -130,31 +143,23 @@ extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
        addccc          %2, %0, %0
        addccc          %3, %0, %0
        addc            %0, %%g0, %0
-       sll             %0, 16, %1
-       addcc           %1, %0, %0
-       srl             %0, 16, %0
-       addc            %0, %%g0, %0
-       xnor            %%g0, %0, %0
 "      : "=r" (sum), "=r" (saddr)
        : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)
        : "cc");
-       return (sum & 0xffff);
+       return sum;
 }
 
-/* Fold a partial checksum without adding pseudo headers. */
-extern __inline__ unsigned short csum_fold(unsigned int sum)
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+                                                  unsigned long daddr,
+                                                  unsigned short len,
+                                                  unsigned short proto,
+                                                  unsigned int sum) 
 {
-       unsigned int tmp;
-
-       __asm__ __volatile__("
-       addcc           %0, %1, %1
-       srl             %1, 16, %1
-       addc            %1, %%g0, %1
-       xnor            %%g0, %1, %0
-"      : "=&r" (sum), "=r" (tmp)
-       : "0" (sum), "1" (sum<<16)
-       : "cc");
-       return (sum & 0xffff);
+       return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
index 47a2423102b93c996f5e76906ba19dba3dec185c..87f6de8def5505c564ac4c9972a6c671672656c0 100644 (file)
@@ -49,7 +49,8 @@ enum root_directory_inos {
        PROC_SLABINFO,
        PROC_PARPORT,
        PROC_PPC_HTAB,
-       PROC_SOUND
+       PROC_SOUND,
+       PROC_MTRR, /* whether enabled or not */
 };
 
 enum pid_directory_inos {
index 1a8d71f588b1bf7f9caa2c16b6eee55af2213e7e..ed3e0d31d8e3fef75a04d90bfa563cfb45d3508c 100644 (file)
@@ -47,7 +47,8 @@ extern volatile int smp_msg_id;
 #define MSG_STOP_CPU           0x0002  /* Sent to shut down slave CPU's
                                         * when rebooting
                                         */
-#define MSG_RESCHEDULE         0x0003  /* Reschedule request from master CPU */
+#define MSG_RESCHEDULE         0x0003  /* Reschedule request from master CPU*/
+#define MSG_MTRR_CHANGE         0x0004  /* Change MTRR */
 
 #else
 
index 7c57b1af51db03490fe3f1c6d83662437d9eb7ee..cfdf357e6afb5e674727d9c1e3f73abc93832050 100644 (file)
@@ -41,17 +41,13 @@ use_init_file_context(void) {
        current->fs = task_init->fs;
        current->fs->count++;
 
-       /* don't use the user's files, use init's files instead */
-       exit_files(current);    /* current->files->count--; */
-       current->files = task_init->files;
-       current->files->count++;
-
        unlock_kernel();
 }
 
 static int exec_modprobe(void * module_name)
 {
        char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
+       int i;
 
        use_init_file_context();
 
@@ -66,6 +62,10 @@ static int exec_modprobe(void * module_name)
        flush_signal_handlers(current);
        spin_unlock_irq(&current->sigmask_lock);
 
+       for (i = 0; i < current->files->max_fds; i++ ) {
+           if (current->files->fd[i]) close(i);
+       }
+
        set_fs(KERNEL_DS);      /* Allow execve args to be in kernel space. */
        current->uid = current->euid = 0;
        if (execve(modprobe_path, argv, envp) < 0) {
@@ -87,7 +87,7 @@ int request_module(const char * module_name)
        int waitpid_result;
 
        pid = kernel_thread(exec_modprobe, (void*) module_name,
-                           CLONE_FS | CLONE_FILES | SIGCHLD);
+                           CLONE_FS | SIGCHLD);
        if (pid < 0) {
                printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
                return pid;
index f901aa2bdbf94b3f68be3545b1e18edc7475ad33..db0748e872da2db737889c56902311d284d470f7 100644 (file)
@@ -894,11 +894,11 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
        memset(&arg, 0, sizeof arg); 
        arg.iov[0].iov_base = (unsigned char *)&rth; 
        arg.iov[0].iov_len  = sizeof rth;
-       arg.csum = csum_tcpudp_magic(skb->nh.iph->daddr, 
-                               skb->nh.iph->saddr, /*XXX*/
-                               sizeof(struct tcphdr),
-                               IPPROTO_TCP,
-                               0); 
+       arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, 
+                                     skb->nh.iph->saddr, /*XXX*/
+                                     sizeof(struct tcphdr),
+                                     IPPROTO_TCP,
+                                     0); 
        arg.n_iov = 1;
        arg.csumoffset = offsetof(struct tcphdr, check) / sizeof(u16); 
 
index f61d4763f9b097a4f12e611d47bd2615732af19a..8aa08310c335bccbc2a68dd165e5940a7b344fa7 100644 (file)
@@ -17,6 +17,7 @@
 #include <net/neighbour.h>
 #include <net/snmp.h>
 
+#ifdef CONFIG_INET
 #include <linux/ip.h>
 #include <linux/etherdevice.h>
 #include <linux/fddidevice.h>
@@ -34,7 +35,6 @@
 #include <linux/mroute.h>
 #include <linux/igmp.h>
 
-#ifdef CONFIG_INET
 extern struct net_proto_family inet_family_ops;
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -421,14 +421,12 @@ EXPORT_SYMBOL(ip_acct_output);
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
+EXPORT_SYMBOL(arp_find);
 EXPORT_SYMBOL(n_tty_ioctl);
 EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(kill_fasync);
-#ifdef CONFIG_INET
-EXPORT_SYMBOL(arp_find);
 EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
-#endif
 EXPORT_SYMBOL(dev_mc_delete);
 
 EXPORT_SYMBOL(if_port_text);
@@ -444,14 +442,13 @@ EXPORT_SYMBOL(dlci_ioctl_hook);
 #endif
 
 /* Packet scheduler modules want these. */
-#ifdef CONFIG_NET_SCHED
 EXPORT_SYMBOL(qdisc_destroy);
 EXPORT_SYMBOL(qdisc_reset);
 EXPORT_SYMBOL(qdisc_restart);
 EXPORT_SYMBOL(qdisc_head);
 EXPORT_SYMBOL(qdisc_create_dflt);
-EXPORT_SYMBOL(pfifo_qdisc_ops);
 EXPORT_SYMBOL(noop_qdisc);
+#ifdef CONFIG_NET_SCHED
 EXPORT_SYMBOL(register_qdisc);
 EXPORT_SYMBOL(unregister_qdisc);
 EXPORT_SYMBOL(qdisc_get_rtab);