Commit 6b6e62fd authored by Linus Torvalds's avatar Linus Torvalds

pre-2.1.99-3

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
parent 25eaf06c
......@@ -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
......
......@@ -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
=========
......
......@@ -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
......
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 */
===============================================================================
......@@ -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
......
......@@ -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..
*
......
......@@ -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)
{
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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");
......
/* 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 Tischhuser <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
......@@ -47,6 +47,10 @@
#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
......
......@@ -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
......
......@@ -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
......
......@@ -28,7 +28,7 @@ L_OBJS += oldproc.o
endif
endif
ifdef CONFIG_PCI_OPTIMIZE
ifdef CONFIG_PCI_QUIRKS
L_OBJS += quirks.o
endif
......
......@@ -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
......
......@@ -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);
}
}
}
......
......@@ -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
......
......@@ -14,6 +14,10 @@
#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
}
#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
......
/* 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 */
......@@ -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)
......
......@@ -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));
}
/*
......
......@@ -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
......
/* $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
......
/* $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
......
......@@ -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 {
......
......@@ -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
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment