summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /arch/i386
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/boot/bootsect.S25
-rw-r--r--arch/i386/boot/setup.S11
-rw-r--r--arch/i386/config.in7
-rw-r--r--arch/i386/defconfig23
-rw-r--r--arch/i386/kernel/Makefile10
-rw-r--r--arch/i386/kernel/acpi.c1
-rw-r--r--arch/i386/kernel/apic.c2
-rw-r--r--arch/i386/kernel/apm.c416
-rw-r--r--arch/i386/kernel/i386_ksyms.c7
-rw-r--r--arch/i386/kernel/i8259.c4
-rw-r--r--arch/i386/kernel/io_apic.c51
-rw-r--r--arch/i386/kernel/irq.c1
-rw-r--r--arch/i386/kernel/microcode.c266
-rw-r--r--arch/i386/kernel/mpparse.c5
-rw-r--r--arch/i386/kernel/mtrr.c316
-rw-r--r--arch/i386/kernel/pci-dma.c18
-rw-r--r--arch/i386/kernel/pci-i386.c2
-rw-r--r--arch/i386/kernel/pci-pc.c81
-rw-r--r--arch/i386/kernel/process.c22
-rw-r--r--arch/i386/kernel/setup.c2
-rw-r--r--arch/i386/kernel/smp.c11
-rw-r--r--arch/i386/mm/init.c25
22 files changed, 902 insertions, 404 deletions
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
index 4a9d59908..f345ea100 100644
--- a/arch/i386/boot/bootsect.S
+++ b/arch/i386/boot/bootsect.S
@@ -106,9 +106,8 @@ go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
pushw %ds
ldsw %fs:(%bx), %si # ds:si is source
movb $6, %cl # copy 12 bytes
- cld
pushw %di # di = 0x4000-12.
- rep
+ rep # don't need cld -> done on line 66
movsw
popw %di
popw %ds
@@ -140,20 +139,7 @@ load_setup:
jmp load_setup
ok_load_setup:
-# Get disk drive parameters, specifically nr of sectors/track.
-
-#if 0
-
-# bde - the Phoenix BIOS manual says function 0x08 only works for fixed
-# disks. It doesn't work for one of my BIOS's (1987 Award). It was
-# fatal not to check the error code.
-
- xorb %dl, %dl
- movb $0x08, %ah # AH=8 is get drive parameters
- int $0x13
- xorb %ch, %ch
-
-#else
+# Get disk drive parameters, specifically number of sectors/track.
# It seems that there is no BIOS call to get the number of sectors.
# Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
@@ -176,7 +162,6 @@ probe_loop:
movw $0x0201, %ax # service 2, 1 sector
int $0x13
jc probe_loop # try next value
-#endif
got_sectors:
movw $INITSEG, %ax
@@ -200,11 +185,11 @@ got_sectors:
# Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
# depending on the number of sectors we pretend to know we have.
- movw %cs:root_dev, %ax
+ movw root_dev, %ax
orw %ax, %ax
jne root_defined
- movw %cs:sectors, %bx
+ movw sectors, %bx
movw $0x0208, %ax # /dev/ps0 - 1.2Mb
cmpw $15, %bx
je root_defined
@@ -219,7 +204,7 @@ got_sectors:
movb $0, %al # /dev/fd0 - autodetect
root_defined:
- movw %ax, %cs:root_dev
+ movw %ax, root_dev
# After that (everything loaded), we jump to the setup-routine
# loaded directly after the bootblock:
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 1a08bc3ab..7c50d54a8 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -436,7 +436,7 @@ no_mca:
movw $0xAA, (0x1ff) # device present
no_psmouse:
-#ifdef CONFIG_APM
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
# Then check for an APM BIOS...
# %ds points to the bootsector
movw $0, 0x40 # version = 0 means no APM BIOS
@@ -455,7 +455,11 @@ no_psmouse:
xorw %bx, %bx
int $0x15 # ignore return code
movw $0x05303, %ax # 32 bit connect
- xorw %bx, %bx
+ xorl %ebx, %ebx
+ xorw %cx, %cx # paranoia :-)
+ xorw %dx, %dx # ...
+ xorl %esi, %esi # ...
+ xorw %di, %di # ...
int $0x15
jc no_32_apm_bios # Ack, error.
@@ -463,12 +467,13 @@ no_psmouse:
movl %ebx, (68) # BIOS entry point offset
movw %cx, (72) # BIOS 16 bit code segment
movw %dx, (74) # BIOS data segment
- movl %esi, (78) # BIOS code segment length
+ movl %esi, (78) # BIOS code segment lengths
movw %di, (82) # BIOS data segment length
# Redo the installation check as the 32 bit connect
# modifies the flags returned on some BIOSs
movw $0x05300, %ax # APM BIOS installation check
xorw %bx, %bx
+ xorw %cx, %cx # paranoia
int $0x15
jc apm_disconnect # error -> shouldn't happen
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 2377c24b7..e074ea81d 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -49,6 +49,10 @@ if [ "$CONFIG_MK7" = "y" ]; then
define_bool CONFIG_X86_USE_3DNOW y
fi
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+ tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+fi
+
choice 'High Memory Support' \
"off CONFIG_NOHIGHMEM \
4GB CONFIG_HIGHMEM4G \
@@ -144,7 +148,7 @@ if [ "$CONFIG_ACPI" != "n" ]; then
fi
fi
-bool 'Advanced Power Management BIOS support' CONFIG_APM
+tristate 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE
@@ -154,7 +158,6 @@ if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
- bool ' Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET
bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
fi
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index fcc962a11..4ca545255 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -27,6 +27,7 @@ CONFIG_X86_POPAD_OK=y
CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
+# CONFIG_MICROCODE is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
@@ -175,7 +176,6 @@ CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
# CONFIG_CHR_DEV_ST is not set
-CONFIG_ST_EXTRA_DEVS=2
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
@@ -238,6 +238,11 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_ULTRASTOR is not set
#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
# I2O device support
#
# CONFIG_I2O is not set
@@ -270,15 +275,15 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
# CONFIG_DE4X5 is not set
# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
-CONFIG_EEXPRESS_PRO100=y
+CONFIG_EEPRO100=y
# CONFIG_NE2K_PCI is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
@@ -324,7 +329,6 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_ARCNET_COM20020_CS is not set
# CONFIG_PCMCIA_3C575 is not set
# CONFIG_PCMCIA_TULIP is not set
-# CONFIG_PCMCIA_EPIC100 is not set
CONFIG_NET_PCMCIA_RADIO=y
CONFIG_PCMCIA_RAYCS=y
# CONFIG_PCMCIA_NETWAVE is not set
@@ -423,7 +427,7 @@ CONFIG_PCMCIA_SERIAL=y
#
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
@@ -442,20 +446,17 @@ CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 96be4dff6..3b7bb1258 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -40,6 +40,16 @@ else
endif
endif
+ifeq ($(CONFIG_PROC_FS),y)
+ifeq ($(CONFIG_MICROCODE),y)
+OX_OBJS += microcode.o
+else
+ ifeq ($(CONFIG_MICROCODE),m)
+ MX_OBJS += microcode.o
+ endif
+endif
+endif
+
ifeq ($(CONFIG_ACPI),y)
O_OBJS += acpi.o
else
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index 8ae8bc299..9bdd111d1 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -643,6 +643,7 @@ const static struct
{NULL,},
{acpi_init_piix4},
{acpi_init_via},
+ {acpi_init_via},
};
const static struct pci_device_id acpi_pci_tbl[] =
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index b8bca05c6..a5f72548f 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -3,6 +3,8 @@
*
* (c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
*
+ * Fixes
+ * Maciej W. Rozycki : Bits for genuine 82489DX timers
*/
#include <linux/config.h>
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 81a813b05..4ec5e7993 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* APM BIOS driver for Linux
- * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com)
*
* Initial development of this driver was funded by NEC Australia P/L
* and NEC Corporation
@@ -35,6 +35,8 @@
* Jan 1999, Version 1.9
* Oct 1999, Version 1.10
* Nov 1999, Version 1.11
+ * Jan 2000, Version 1.12
+ * Feb 2000, Version 1.13
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -54,7 +56,7 @@
* The new replacment for it is, but Linux doesn't yet support this.
* Alan Cox Linux 2.1.55
* 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
- * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
+ * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
* Dean Gaudet <dgaudet@arctic.org>.
* C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
* 1.5: Fix segment register reloading (in case of bad segments saved
@@ -110,6 +112,26 @@
* (reported by Panos Katsaloulis <teras@writeme.com>).
* Real mode power off patch (Walter Hofmann
* <Walter.Hofmann@physik.stud.uni-erlangen.de>).
+ * 1.12: Remove CONFIG_SMP as the compiler will optimize
+ * the code away anyway (smp_num_cpus == 1 in UP)
+ * noted by Artur Skawina <skawina@geocities.com>.
+ * Make power off under SMP work again.
+ * Fix thinko with initial engaging of BIOS.
+ * Make sure power off only happens on CPU 0
+ * (Paul "Rusty" Russell <rusty@linuxcare.com>).
+ * Do error notification to user mode if BIOS calls fail.
+ * Move entrypoint offset fix to ...boot/setup.S
+ * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>).
+ * Remove smp-power-off. SMP users must now specify
+ * "apm=power-off" on the kernel command line. Suggested
+ * by Jim Avera <jima@hal.com>, modified by Alan Cox
+ * <alan@lxorguk.ukuu.org.uk>.
+ * Register the /proc/apm entry even on SMP so that
+ * scripts that check for it before doing power off
+ * work (Jim Avera <jima@hal.com>).
+ * 1.13: Changes for new pm_ interfaces (Andy Henroid
+ * <andy_henroid@yahoo.com>).
+ * Modularize the code.
*
* APM 1.1 Reference:
*
@@ -145,13 +167,12 @@
#include <linux/apm_bios.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/pm.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/desc.h>
-#include <linux/pm.h>
-
extern unsigned long get_cmos_time(void);
extern void machine_real_restart(unsigned char *, int);
@@ -172,10 +193,10 @@ extern int (*console_blank_hook)(int);
* See Documentation/Config.help for the configuration options.
*
* Various options can be changed at boot time as follows:
+ * (We allow underscores for compatibility with the modules code)
* apm=on/off enable/disable APM
* [no-]debug log some debugging messages
- * [no-]power-off power off on shutdown
- * [no-]smp-power-off allow power off even for SMP
+ * [no-]power[-_]off power off on shutdown
*/
/* KNOWN PROBLEM MACHINES:
@@ -219,8 +240,8 @@ extern int (*console_blank_hook)(int);
/*
* Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
- * This patched by Chad Miller <cmiller@surfsouth.com>, orig code by David
- * Chen <chen@ctpa04.mit.edu>
+ * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
+ * David Chen <chen@ctpa04.mit.edu>
*/
#undef INIT_TIMER_AFTER_SUSPEND
@@ -237,7 +258,7 @@ extern int (*console_blank_hook)(int);
/*
* If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then
- * ignore suspend events for this amount of time
+ * ignore suspend events for this amount of time after a resume
*/
#define BOUNCE_INTERVAL (3 * HZ)
@@ -248,14 +269,40 @@ extern int (*console_blank_hook)(int);
__asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
/*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS 20
+
+/*
+ * The per-file APM data
+ */
+struct apm_user {
+ int magic;
+ struct apm_user * next;
+ int suser: 1;
+ int suspend_wait: 1;
+ int suspend_result;
+ int suspends_pending;
+ int standbys_pending;
+ int suspends_read;
+ int standbys_read;
+ int event_head;
+ int event_tail;
+ apm_event_t events[APM_MAX_EVENTS];
+};
+
+/*
+ * The magic number in apm_user
+ */
+#define APM_BIOS_MAGIC 0x4101
+
+/*
* Local variables
*/
static struct {
unsigned long offset;
unsigned short segment;
} apm_bios_entry;
-static int apm_enabled = 0;
-static int smp_hack = 0;
#ifdef CONFIG_APM_CPU_IDLE
static int clock_slowed = 0;
#endif
@@ -274,12 +321,19 @@ static int got_clock_diff = 0;
#endif
static int debug = 0;
static int apm_disabled = 0;
-static int power_off_enabled = 1;
+#ifdef CONFIG_SMP
+static int power_off = 0;
+#else
+static int power_off = 1;
+#endif
+static int exit_kapmd = 0;
+static int kapmd_running = 0;
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static struct apm_bios_struct * user_list = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+static struct apm_user * user_list = NULL;
-static char driver_version[] = "1.11"; /* no spaces */
+static char driver_version[] = "1.12"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
@@ -380,6 +434,10 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
__save_flags(flags);
APM_DO_CLI;
APM_DO_SAVE_SEGS;
+ /*
+ * N.B. We do NOT need a cld after the BIOS call
+ * because we always save and restore the flags.
+ */
__asm__ __volatile__(APM_DO_ZERO_SEGS
"pushl %%edi\n\t"
"pushl %%ebp\n\t"
@@ -413,10 +471,14 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
{
int cx, dx, si;
+ /*
+ * N.B. We do NOT need a cld after the BIOS call
+ * because we always save and restore the flags.
+ */
__asm__ __volatile__(APM_DO_ZERO_SEGS
"pushl %%edi\n\t"
"pushl %%ebp\n\t"
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t"
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
"setc %%bl\n\t"
"popl %%ebp\n\t"
"popl %%edi\n\t"
@@ -499,6 +561,7 @@ static void apm_do_busy(void)
}
}
+#if 0
extern int hlt_counter;
/*
@@ -543,48 +606,63 @@ static void apm_cpu_idle(void)
}
}
#endif
+#endif
+
+#ifdef CONFIG_SMP
+static int apm_magic(void * unused)
+{
+ while (1)
+ schedule();
+}
+#endif
static void apm_power_off(void)
{
+#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
+ unsigned char po_bios_call[] = {
+ 0xb8, 0x00, 0x10, /* movw $0x1000,ax */
+ 0x8e, 0xd0, /* movw ax,ss */
+ 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */
+ 0xb8, 0x07, 0x53, /* movw $0x5307,ax */
+ 0xbb, 0x01, 0x00, /* movw $0x0001,bx */
+ 0xb9, 0x03, 0x00, /* movw $0x0003,cx */
+ 0xcd, 0x15 /* int $0x15 */
+ };
+#endif
+
/*
- * smp_hack == 2 means that we would have enabled APM support
- * except there is more than one processor and so most of
- * the APM stuff is unsafe. We will still try power down
- * because is is useful to some people and they know what
- * they are doing because they booted with the smp-power-off
- * kernel option.
+ * This may be called on an SMP machine.
*/
- if (apm_enabled || (smp_hack == 2)) {
+#ifdef CONFIG_SMP
+ /* Some bioses don't like being called from CPU != 0 */
+ while (cpu_number_map[smp_processor_id()] != 0) {
+ kernel_thread(apm_magic, NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+ schedule();
+ }
+#endif
#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
- unsigned char po_bios_call[] = {
- 0xb8, 0x00, 0x10, /* movw $0x1000,ax */
- 0x8e, 0xd0, /* movw ax,ss */
- 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */
- 0xb8, 0x07, 0x53, /* movw $0x5307,ax */
- 0xbb, 0x01, 0x00, /* movw $0x0001,bx */
- 0xb9, 0x03, 0x00, /* movw $0x0003,cx */
- 0xcd, 0x15 /* int $0x15 */
- };
-
- machine_real_restart(po_bios_call, sizeof(po_bios_call));
+ machine_real_restart(po_bios_call, sizeof(po_bios_call));
#else
- (void) apm_set_power_state(APM_STATE_OFF);
+ (void) apm_set_power_state(APM_STATE_OFF);
#endif
- }
}
-#ifdef CONFIG_APM_DO_ENABLE
-static int __init apm_enable_power_management(void)
+static int apm_enable_power_management(int enable)
{
u32 eax;
+ if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+ return APM_NOT_ENGAGED;
if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
- 1, &eax))
+ enable, &eax))
return (eax >> 8) & 0xff;
- apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+ if (enable)
+ apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+ else
+ apm_bios_info.flags |= APM_BIOS_DISABLED;
return APM_SUCCESS;
}
-#endif
static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
{
@@ -632,12 +710,21 @@ static int apm_get_battery_status(u_short which, u_short *status,
}
#endif
-static int __init apm_engage_power_management(u_short device)
+static int apm_engage_power_management(u_short device, int enable)
{
u32 eax;
- if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, 1, &eax))
+ if ((enable == 0) && (device == APM_DEVICE_ALL)
+ && (apm_bios_info.flags & APM_BIOS_DISABLED))
+ return APM_DISABLED;
+ if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
return (eax >> 8) & 0xff;
+ if (device == APM_DEVICE_ALL) {
+ if (enable)
+ apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+ else
+ apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+ }
return APM_SUCCESS;
}
@@ -655,7 +742,6 @@ static void apm_error(char *str, int err)
}
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
-/* Called from console driver -- must make sure apm_enabled. */
static int apm_console_blank(int blank)
{
int error;
@@ -664,9 +750,13 @@ static int apm_console_blank(int blank)
state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
/* Blank the first display device */
error = set_power_state(0x100, state);
- if (error != APM_SUCCESS)
+ if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
/* try to blank them all instead */
error = set_power_state(0x1ff, state);
+ if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
+ /* try to blank device one instead */
+ error = set_power_state(0x101, state);
+ }
if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
return 1;
apm_error("set display", error);
@@ -674,20 +764,20 @@ static int apm_console_blank(int blank)
}
#endif
-static int queue_empty(struct apm_bios_struct * as)
+static int queue_empty(struct apm_user *as)
{
return as->event_head == as->event_tail;
}
-static apm_event_t get_queued_event(struct apm_bios_struct * as)
+static apm_event_t get_queued_event(struct apm_user *as)
{
as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
return as->events[as->event_tail];
}
-static void queue_event(apm_event_t event, struct apm_bios_struct *sender)
+static void queue_event(apm_event_t event, struct apm_user *sender)
{
- struct apm_bios_struct * as;
+ struct apm_user * as;
if (user_list == NULL)
return;
@@ -751,18 +841,11 @@ static void get_time_diff(void)
#endif
}
-static void suspend(void)
+static void reinit_timer(void)
{
- int err;
#ifdef INIT_TIMER_AFTER_SUSPEND
unsigned long flags;
-#endif
- get_time_diff();
- err = apm_set_power_state(APM_STATE_SUSPEND);
- if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))
- apm_error("suspend", err);
-#ifdef INIT_TIMER_AFTER_SUSPEND
save_flags(flags);
cli();
/* set the clock to 100 Hz */
@@ -774,7 +857,27 @@ static void suspend(void)
udelay(10);
restore_flags(flags);
#endif
+}
+
+static int suspend(void)
+{
+ int err;
+ int ret;
+ struct apm_user *as;
+
+ get_time_diff();
+ err = apm_set_power_state(APM_STATE_SUSPEND);
+ reinit_timer();
set_time();
+ ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
+ if (!ret)
+ apm_error("suspend", err);
+ for (as = user_list; as != NULL; as = as->next) {
+ as->suspend_wait = 0;
+ as->suspend_result = (ret ? 0 : -EIO);
+ }
+ wake_up_interruptible(&apm_suspend_waitqueue);
+ return ret;
}
static void standby(void)
@@ -806,15 +909,14 @@ static apm_event_t get_event(void)
return 0;
}
-static int send_event(apm_event_t event, apm_event_t undo,
- struct apm_bios_struct *sender)
+static int send_event(apm_event_t event, struct apm_user *sender)
{
switch (event) {
case APM_SYS_SUSPEND:
case APM_CRITICAL_SUSPEND:
case APM_USER_SUSPEND:
/* map all suspends to ACPI D3 */
- if (pm_send_request(PM_SUSPEND, (void*) 3)) {
+ if (pm_send_request(PM_SUSPEND, (void *)3)) {
if (apm_bios_info.version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
return 0;
@@ -823,11 +925,7 @@ static int send_event(apm_event_t event, apm_event_t undo,
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
/* map all resumes to ACPI D0 */
- if (pm_send_request(PM_RESUME, 0)) {
- if (apm_bios_info.version > 0x100)
- apm_set_power_state(APM_STATE_REJECT);
- return 0;
- }
+ (void) pm_send_request(PM_RESUME, (void *)0);
break;
}
@@ -864,7 +962,7 @@ static void check_events(void)
if (waiting_for_resume)
break;
#endif
- if (send_event(event, APM_STANDBY_RESUME, NULL)) {
+ if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
#endif
@@ -888,12 +986,12 @@ static void check_events(void)
if (waiting_for_resume)
break;
#endif
- if (send_event(event, APM_NORMAL_RESUME, NULL)) {
+ if (send_event(event, NULL)) {
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 1;
#endif
if (suspends_pending <= 0)
- suspend();
+ (void) suspend();
}
break;
@@ -908,13 +1006,13 @@ static void check_events(void)
ignore_bounce = 1;
#endif
set_time();
- send_event(event, 0, NULL);
+ send_event(event, NULL);
break;
case APM_CAPABILITY_CHANGE:
case APM_LOW_BATTERY:
case APM_POWER_STATUS_CHANGE:
- send_event(event, 0, NULL);
+ send_event(event, NULL);
break;
case APM_UPDATE_TIME:
@@ -922,7 +1020,7 @@ static void check_events(void)
break;
case APM_CRITICAL_SUSPEND:
- suspend();
+ (void) suspend();
break;
}
}
@@ -930,18 +1028,18 @@ static void check_events(void)
static void apm_event_handler(void)
{
- static int pending_count = 0;
+ static int pending_count = 4;
int err;
if ((standbys_pending > 0) || (suspends_pending > 0)) {
- if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+ if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) {
pending_count = 4;
err = apm_set_power_state(APM_STATE_BUSY);
if (err)
apm_error("busy", err);
}
} else
- pending_count = 0;
+ pending_count = 4;
check_events();
}
@@ -957,13 +1055,17 @@ static void apm_event_handler(void)
static void apm_mainloop(void)
{
DECLARE_WAITQUEUE(wait, current);
- apm_enabled = 1;
+
+ if (smp_num_cpus > 1)
+ return;
add_wait_queue(&apm_waitqueue, &wait);
current->state = TASK_INTERRUPTIBLE;
for (;;) {
/* Nothing to do, just sleep for the timeout */
schedule_timeout(APM_CHECK_TIMEOUT);
+ if (exit_kapmd)
+ break;
/*
* Ok, check all events, check for idle (and mark us sleeping
@@ -976,11 +1078,11 @@ static void apm_mainloop(void)
continue;
if (apm_do_idle()) {
unsigned long start = jiffies;
- do {
+ while (system_idle()) {
apm_do_idle();
if (jiffies - start > APM_CHECK_TIMEOUT)
break;
- } while (system_idle());
+ }
apm_do_busy();
apm_event_handler();
}
@@ -988,7 +1090,7 @@ static void apm_mainloop(void)
}
}
-static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
+static int check_apm_user(struct apm_user *as, const char *func)
{
if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
printk(KERN_ERR "apm: %s passed bad filp", func);
@@ -999,13 +1101,13 @@ static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
{
- struct apm_bios_struct * as;
+ struct apm_user * as;
int i;
apm_event_t event;
DECLARE_WAITQUEUE(wait, current);
as = fp->private_data;
- if (check_apm_bios_struct(as, "read"))
+ if (check_apm_user(as, "read"))
return -EIO;
if (count < sizeof(apm_event_t))
return -EINVAL;
@@ -1053,10 +1155,10 @@ repeat:
static unsigned int do_poll(struct file *fp, poll_table * wait)
{
- struct apm_bios_struct * as;
+ struct apm_user * as;
as = fp->private_data;
- if (check_apm_bios_struct(as, "select"))
+ if (check_apm_user(as, "poll"))
return 0;
poll_wait(fp, &apm_waitqueue, wait);
if (!queue_empty(as))
@@ -1067,11 +1169,11 @@ static unsigned int do_poll(struct file *fp, poll_table * wait)
static int do_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
- struct apm_bios_struct * as;
- int send_ok = 1;
+ struct apm_user * as;
+ DECLARE_WAITQUEUE(wait, current);
as = filp->private_data;
- if (check_apm_bios_struct(as, "ioctl"))
+ if (check_apm_user(as, "ioctl"))
return -EIO;
if (!as->suser)
return -EPERM;
@@ -1081,11 +1183,9 @@ static int do_ioctl(struct inode * inode, struct file *filp,
as->standbys_read--;
as->standbys_pending--;
standbys_pending--;
- }
- else
- send_ok = send_event(APM_USER_STANDBY,
- APM_STANDBY_RESUME, as);
- if (send_ok && (standbys_pending <= 0))
+ } else if (!send_event(APM_USER_STANDBY, as))
+ return -EAGAIN;
+ if (standbys_pending <= 0)
standby();
break;
case APM_IOC_SUSPEND:
@@ -1093,12 +1193,25 @@ static int do_ioctl(struct inode * inode, struct file *filp,
as->suspends_read--;
as->suspends_pending--;
suspends_pending--;
+ } else if (!send_event(APM_USER_SUSPEND, as))
+ return -EAGAIN;
+ if (suspends_pending <= 0) {
+ if (!suspend())
+ return -EIO;
+ } else {
+ as->suspend_wait = 1;
+ add_wait_queue(&apm_suspend_waitqueue, &wait);
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((as->suspend_wait == 0)
+ || signal_pending(current))
+ break;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&apm_suspend_waitqueue, &wait);
+ return as->suspend_result;
}
- else
- send_ok = send_event(APM_USER_SUSPEND,
- APM_NORMAL_RESUME, as);
- if (send_ok && (suspends_pending <= 0))
- suspend();
break;
default:
return -EINVAL;
@@ -1108,10 +1221,10 @@ static int do_ioctl(struct inode * inode, struct file *filp,
static int do_release(struct inode * inode, struct file * filp)
{
- struct apm_bios_struct * as;
+ struct apm_user * as;
as = filp->private_data;
- if (check_apm_bios_struct(as, "release"))
+ if (check_apm_user(as, "release"))
return 0;
filp->private_data = NULL;
if (as->standbys_pending > 0) {
@@ -1122,12 +1235,12 @@ static int do_release(struct inode * inode, struct file * filp)
if (as->suspends_pending > 0) {
suspends_pending -= as->suspends_pending;
if (suspends_pending <= 0)
- suspend();
+ (void) suspend();
}
if (user_list == as)
user_list = as->next;
else {
- struct apm_bios_struct * as1;
+ struct apm_user * as1;
for (as1 = user_list;
(as1 != NULL) && (as1->next != as);
@@ -1139,17 +1252,21 @@ static int do_release(struct inode * inode, struct file * filp)
as1->next = as->next;
}
kfree_s(as, sizeof(*as));
+ MOD_DEC_USE_COUNT;
return 0;
}
static int do_open(struct inode * inode, struct file * filp)
{
- struct apm_bios_struct * as;
+ struct apm_user * as;
- as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
+ MOD_INC_USE_COUNT;
+
+ as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
sizeof(*as));
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
as->magic = APM_BIOS_MAGIC;
@@ -1184,11 +1301,10 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
int time_units = -1;
char *units = "?";
- if (!apm_enabled)
- return 0;
p = buf;
- if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
+ if ((smp_num_cpus == 1) &&
+ !(error = apm_get_power_status(&bx, &cx, &dx))) {
ac_line_status = (bx >> 8) & 0xff;
battery_status = bx & 0xff;
if ((cx & 0xff) != 0xff)
@@ -1264,6 +1380,11 @@ static int apm(void *unused)
char * power_stat;
char * bat_stat;
+ kapmd_running = 1;
+
+ exit_files(current); /* daemonize doesn't do exit_files */
+ daemonize();
+
strcpy(current->comm, "kapmd");
sigfillset(&current->blocked);
@@ -1278,7 +1399,7 @@ static int apm(void *unused)
apm_bios_info.version = 0x100;
}
}
- if (debug) {
+ if (debug && (smp_num_cpus == 1)) {
printk(KERN_INFO "apm: Connection version %d.%d\n",
(apm_bios_info.version >> 8) & 0xff,
apm_bios_info.version & 0xff);
@@ -1328,32 +1449,51 @@ static int apm(void *unused)
* is booted with PM disabled but not in the docking station.
* Unfortunate ...
*/
- error = apm_enable_power_management();
+ error = apm_enable_power_management(1);
if (error) {
apm_error("enable power management", error);
return -1;
}
}
#endif
- if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0)
+ if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
&& (apm_bios_info.version > 0x0100)) {
- if (apm_engage_power_management(0x0001) == APM_SUCCESS)
- apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+ error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+ if (error) {
+ apm_error("engage power management", error);
+ return -1;
+ }
}
/* Install our power off handler.. */
- if (power_off_enabled)
+ if (power_off)
pm_power_off = apm_power_off;
#ifdef CONFIG_MAGIC_SYSRQ
sysrq_power_off = apm_power_off;
#endif
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
- console_blank_hook = apm_console_blank;
+ if (smp_num_cpus == 1)
+ console_blank_hook = apm_console_blank;
#endif
pm_active = 1;
apm_mainloop();
+
+ pm_active = 0;
+
+#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
+ if (smp_num_cpus == 1)
+ console_blank_hook = NULL;
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+ sysrq_power_off = NULL;
+#endif
+ if (power_off)
+ pm_power_off = NULL;
+
+ kapmd_running = 0;
+
return 0;
}
@@ -1371,10 +1511,9 @@ static int __init apm_setup(char *str)
str += 3;
if (strncmp(str, "debug", 5) == 0)
debug = !invert;
- if (strncmp(str, "power-off", 9) == 0)
- power_off_enabled = !invert;
- if (strncmp(str, "smp-power-off", 13) == 0)
- smp_hack = !invert;
+ if ((strncmp(str, "power-off", 9) == 0) ||
+ (strncmp(str, "power_off", 9) == 0))
+ power_off = !invert;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
@@ -1394,7 +1533,7 @@ static struct file_operations apm_bios_fops = {
static struct miscdevice apm_device = {
APM_MINOR_DEV,
- "apm",
+ "apm_bios",
&apm_bios_fops
};
@@ -1455,7 +1594,10 @@ static int __init apm_init(void)
printk(KERN_NOTICE "apm: disabled on user request.\n");
APM_INIT_ERROR_RETURN;
}
-
+ if ((smp_num_cpus > 1) && !power_off) {
+ printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+ APM_INIT_ERROR_RETURN;
+ }
if (PM_IS_ACTIVE()) {
printk(KERN_NOTICE "apm: overridden by ACPI.\n");
APM_INIT_ERROR_RETURN;
@@ -1472,9 +1614,6 @@ static int __init apm_init(void)
_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
apm_bios_entry.offset = apm_bios_info.offset;
-#ifdef CONFIG_APM_BAD_ENTRY_OFFSET
- apm_bios_entry.offset &= 0xffff;
-#endif
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
__va((unsigned long)apm_bios_info.cseg << 4));
@@ -1483,18 +1622,16 @@ static int __init apm_init(void)
set_base(gdt[APM_DS >> 3],
__va((unsigned long)apm_bios_info.dseg << 4));
#ifndef APM_RELAX_SEGMENTS
- if (apm_bios_info.version == 0x100)
+ if (apm_bios_info.version == 0x100) {
#endif
- {
/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
_set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
/* For some unknown machine. */
_set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
/* For the DEC Hinote Ultra CT475 (and others?) */
_set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
- }
#ifndef APM_RELAX_SEGMENTS
- else {
+ } else {
_set_limit((char *)&gdt[APM_CS >> 3],
(apm_bios_info.cseg_len - 1) & 0xffff);
_set_limit((char *)&gdt[APM_CS_16 >> 3],
@@ -1504,21 +1641,36 @@ static int __init apm_init(void)
}
#endif
-#ifdef CONFIG_SMP
+ create_proc_info_entry("apm", 0, NULL, apm_get_info);
+
+ kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+
if (smp_num_cpus > 1) {
- printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
- if (smp_hack)
- smp_hack = 2;
+ printk(KERN_NOTICE
+ "apm: disabled - APM is not SMP safe (power off active).\n");
APM_INIT_ERROR_RETURN;
}
-#endif
-
- create_proc_info_entry("apm", 0, 0, apm_get_info);
misc_register(&apm_device);
- kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
return 0;
}
-__initcall(apm_init);
+static void __exit apm_exit(void)
+{
+ misc_deregister(&apm_device);
+ remove_proc_entry("apm", NULL);
+ exit_kapmd = 1;
+ while (kapmd_running)
+ schedule();
+}
+
+module_init(apm_init);
+module_exit(apm_exit);
+
+MODULE_AUTHOR("Stephen Rothwell");
+MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Enable debug mode");
+
+EXPORT_NO_SYMBOLS;
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index f58e7485f..cad6ceb17 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -10,6 +10,7 @@
#include <linux/smp_lock.h>
#include <linux/pm.h>
#include <linux/pci.h>
+#include <linux/apm_bios.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -20,6 +21,7 @@
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/mmx.h>
+#include <asm/desc.h>
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(elf_fpregset_t *);
@@ -34,6 +36,8 @@ extern struct drive_info_struct drive_info;
EXPORT_SYMBOL(drive_info);
#endif
+extern unsigned long get_cmos_time(void);
+
/* platform dependent support */
EXPORT_SYMBOL(boot_cpu_data);
EXPORT_SYMBOL(EISA_bus);
@@ -51,6 +55,9 @@ EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(pm_idle);
EXPORT_SYMBOL(pm_power_off);
+EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(apm_bios_info);
+EXPORT_SYMBOL(gdt);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index c62e5c2d2..d54f9b503 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -311,7 +311,7 @@ spurious_8259A_irq:
}
}
-void init_8259A(int auto_eoi)
+void __init init_8259A(int auto_eoi)
{
unsigned long flags;
@@ -384,7 +384,7 @@ static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
#endif
-void init_ISA_irqs (void)
+void __init init_ISA_irqs (void)
{
int i;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 0037bebdd..75b2bfb9f 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -11,6 +11,9 @@
* Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>,
* further tested and cleaned up by Zach Brown <zab@redhat.com>
* and Ingo Molnar <mingo@redhat.com>
+ *
+ * Fixes
+ * Maciej W. Rozycki : Bits for genuine 82489DX APICs
*/
#include <linux/mm.h>
@@ -249,7 +252,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
best_guess = irq;
}
}
- return -1;
+ return best_guess;
}
/*
@@ -906,40 +909,6 @@ void disable_IO_APIC(void)
}
}
-static void __init setup_ioapic_default_id(void)
-{
- struct IO_APIC_reg_00 reg_00;
-
- /*
- * 'default' mptable configurations mean a hardwired setup,
- * 2 CPUs, 16 APIC registers. IO-APIC ID is usually set to 0,
- * setting it to ID 2 should be fine.
- */
-
- /*
- * Sanity check, is ID 2 really free? Every APIC in the
- * system must have a unique ID or we get lots of nice
- * 'stuck on smp_invalidate_needed IPI wait' messages.
- */
- if (phys_cpu_present_map & (1<<0x2))
- panic("APIC ID 2 already used");
-
- /*
- * Set the ID
- */
- *(int *)&reg_00 = io_apic_read(0, 0);
- printk("...changing IO-APIC physical APIC ID to 2...\n");
- reg_00.ID = 0x2;
- io_apic_write(0, 0, *(int *)&reg_00);
-
- /*
- * Sanity check
- */
- *(int *)&reg_00 = io_apic_read(0, 0);
- if (reg_00.ID != 0x2)
- panic("could not set ID");
-}
-
/*
* function to set the IO-APIC physical IDs based on the
* values stored in the MPC table.
@@ -967,6 +936,15 @@ static void __init setup_ioapic_ids_from_mpc (void)
printk("...changing IO-APIC physical APIC ID to %d ...",
mp_ioapics[apic].mpc_apicid);
+ /*
+ * Sanity check, is the ID really free? Every APIC in the
+ * system must have a unique ID or we get lots of nice
+ * 'stuck on smp_invalidate_needed IPI wait' messages.
+ */
+ if (phys_cpu_present_map & (1<<mp_ioapics[apic].mpc_apicid))
+ panic("APIC ID %d already used",
+ mp_ioapics[apic].mpc_apicid);
+
reg_00.ID = mp_ioapics[apic].mpc_apicid;
io_apic_write(apic, 0, *(int *)&reg_00);
@@ -1021,7 +999,6 @@ static void __init construct_default_ISA_mptable(void)
mp_irqs[0].mpc_dstirq = 2;
}
- setup_ioapic_default_id();
}
/*
@@ -1264,6 +1241,7 @@ static inline void check_timer(void)
/*
* get/set the timer IRQ vector:
*/
+ disable_8259A_irq(0);
vector = assign_irq_vector(0);
set_intr_gate(vector, interrupt[0]);
@@ -1390,7 +1368,6 @@ void IO_APIC_init_uniprocessor (void)
{
if (!smp_found_config)
return;
- phys_cpu_present_map = 0xff;
setup_local_APIC();
setup_IO_APIC();
setup_APIC_clocks();
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 6112ac036..9d4a81041 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -713,6 +713,7 @@ unsigned long probe_irq_on(void)
if (!(status & IRQ_WAITING)) {
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
+ continue;
}
if (i < 32)
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
new file mode 100644
index 000000000..26b6525d8
--- /dev/null
+++ b/arch/i386/kernel/microcode.c
@@ -0,0 +1,266 @@
+/*
+ * CPU Microcode Update interface for Linux
+ *
+ * Copyright (C) 2000 Tigran Aivazian
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to P6 family - PentiumPro, Pentium II, Pentium III etc.
+ *
+ * Reference: Section 8.10 of Volume III, Intel Pentium III Manual,
+ * Order Number 243192 or download from:
+ *
+ * http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ *
+ * 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.
+ *
+ * 1.0 16 February 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ * 1.01 18 February 2000, Tigran Aivazian <tigran@sco.com>
+ * Added read() support + cleanups.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/proc_fs.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+#define MICROCODE_VERSION "1.01"
+
+MODULE_DESCRIPTION("CPU (P6) microcode update driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
+EXPORT_NO_SYMBOLS;
+
+/* VFS interface */
+static int microcode_open(struct inode *, struct file *);
+static int microcode_release(struct inode *, struct file *);
+static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
+static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
+
+
+/* internal helpers to do the work */
+static int do_microcode_update(void);
+static void do_update_one(void *);
+
+/*
+ * Bits in microcode_status. (31 bits of room for future expansion)
+ */
+#define MICROCODE_IS_OPEN 0 /* set if /dev/microcode is in use */
+static unsigned long microcode_status = 0;
+
+/* the actual array of microcode blocks, each 2048 bytes */
+static struct microcode * microcode = NULL;
+static unsigned int microcode_num = 0;
+static char *mc_applied = NULL; /* holds an array of applied microcode blocks */
+
+static struct file_operations microcode_fops = {
+ read: microcode_read,
+ write: microcode_write,
+ open: microcode_open,
+ release: microcode_release,
+};
+
+static struct inode_operations microcode_inops = {
+ default_file_ops: &microcode_fops,
+};
+
+static struct proc_dir_entry *proc_microcode;
+
+static int __init microcode_init(void)
+{
+ int size;
+
+ proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver);
+ if (!proc_microcode) {
+ printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n");
+ return -ENOMEM;
+ }
+ proc_microcode->ops = &microcode_inops;
+ size = smp_num_cpus * sizeof(struct microcode);
+ mc_applied = kmalloc(size, GFP_KERNEL);
+ if (!mc_applied) {
+ remove_proc_entry("microcode", proc_root_driver);
+ printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
+ return -ENOMEM;
+ }
+ memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed
+ update makes this obvious */
+ printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
+ return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+ remove_proc_entry("microcode", proc_root_driver);
+ kfree(mc_applied);
+ printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
+
+/*
+ * We enforce only one user at a time here with open/close.
+ */
+static int microcode_open(struct inode *inode, struct file *file)
+{
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* one at a time, please */
+ if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
+ return -EBUSY;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int microcode_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+
+ clear_bit(MICROCODE_IS_OPEN, &microcode_status);
+ return 0;
+}
+
+/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one()
+ * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
+ * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
+ */
+struct update_req {
+ int err;
+ int slot;
+} update_req[NR_CPUS];
+
+static int do_microcode_update(void)
+{
+ int i, error = 0, err;
+ struct microcode *m;
+
+ if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0)
+ panic("do_microcode_update(): timed out waiting for other CPUs\n");
+ do_update_one((void *)update_req);
+
+ for (i=0; i<smp_num_cpus; i++) {
+ err = update_req[i].err;
+ error += err;
+ if (!err) {
+ m = (struct microcode *)mc_applied + i;
+ memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
+ }
+ }
+ return error ? -EIO : 0;
+}
+
+static void do_update_one(void *arg)
+{
+ struct update_req *req;
+ struct cpuinfo_x86 * c;
+ unsigned int pf = 0, val[2], rev, sig;
+ int i, cpu_num;
+
+ cpu_num = smp_processor_id();
+ c = cpu_data + cpu_num;
+ req = (struct update_req *)arg + cpu_num;
+ req->err = 1; /* be pessimistic */
+
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
+ return;
+
+ sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
+
+ if (c->x86_model >= 5) {
+ /* get processor flags from BBL_CR_OVRD MSR (0x17) */
+ rdmsr(0x17, val[0], val[1]);
+ pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ for (i=0; i<microcode_num; i++)
+ if (microcode[i].sig == sig && microcode[i].pf == pf &&
+ microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
+
+ rdmsr(0x8B, val[0], rev);
+ if (microcode[i].rev <= rev) {
+ printk(KERN_ERR
+ "microcode: CPU%d not 'upgrading' to earlier revision"
+ " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
+ } else {
+ int sum = 0;
+ struct microcode *m = &microcode[i];
+ unsigned int *sump = (unsigned int *)(m+1);
+
+ while (--sump >= (unsigned int *)m)
+ sum += *sump;
+ if (sum != 0) {
+ printk(KERN_ERR "microcode: CPU%d aborting, "
+ "bad checksum\n", cpu_num);
+ break;
+ }
+
+ wrmsr(0x79, (unsigned int)(m->bits), 0);
+ __asm__ __volatile__ ("cpuid");
+ rdmsr(0x8B, val[0], val[1]);
+
+ req->err = 0;
+ req->slot = i;
+ printk(KERN_ERR "microcode: CPU%d microcode updated "
+ "from revision %d to %d, date=%08x\n",
+ cpu_num, rev, val[1], m->date);
+ }
+ break;
+ }
+}
+
+static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
+{
+ size_t fsize = smp_num_cpus * sizeof(struct microcode);
+
+ if (!proc_microcode->size || *ppos >= fsize)
+ return 0; /* EOF */
+ if (*ppos + len > fsize)
+ len = fsize - *ppos;
+ if (copy_to_user(buf, mc_applied + *ppos, len))
+ return -EFAULT;
+ *ppos += len;
+ return len;
+}
+
+static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
+{
+ ssize_t ret;
+
+ if (len % sizeof(struct microcode) != 0) {
+ printk(KERN_ERR "microcode: can only write in N*%d bytes units\n",
+ sizeof(struct microcode));
+ return -EINVAL;
+ }
+ lock_kernel();
+ microcode_num = len/sizeof(struct microcode);
+ microcode = vmalloc(len);
+ if (!microcode) {
+ unlock_kernel();
+ return -ENOMEM;
+ }
+ if (copy_from_user(microcode, buf, len)) {
+ vfree(microcode);
+ unlock_kernel();
+ return -EFAULT;
+ }
+ ret = do_microcode_update();
+ if (!ret) {
+ proc_microcode->size = smp_num_cpus * sizeof(struct microcode);
+ ret = (ssize_t)len;
+ }
+ vfree(microcode);
+ unlock_kernel();
+ return ret;
+}
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 977dd18ba..81685d2f5 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -9,7 +9,7 @@
* Erich Boleyn : MP v1.4 and additional changes.
* Alan Cox : Added EBDA scanning
* Ingo Molnar : various cleanups and rewrites
- * Maciej W. Rozycki : Bits for genuine 82489DX timers
+ * Maciej W. Rozycki : Bits for genuine 82489DX APICs
*/
#include <linux/mm.h>
@@ -339,6 +339,8 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf)
* Now see if we need to read further.
*/
if (mpf->mpf_feature1 != 0) {
+ printk("Default MP configuration #%d\n", mpf->mpf_feature1);
+
/*
* local APIC has default address
*/
@@ -352,6 +354,7 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf)
nr_ioapics = 1;
mp_ioapics[0].mpc_apicaddr = 0xFEC00000;
+ mp_ioapics[0].mpc_apicid = 2;
/*
* Save the default type number, we
* need it later to set the IO-APIC
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 5caa4e477..a0a4ab851 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -1,6 +1,6 @@
/* Generic MTRR (Memory Type Range Register) driver.
- Copyright (C) 1997-1999 Richard Gooch
+ Copyright (C) 1997-2000 Richard Gooch
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -133,7 +133,7 @@
Fixed version numbering and history for v1.23 -> v1.24.
v1.26
19990118 Richard Gooch <rgooch@atnf.csiro.au>
- PLACEHOLDER.
+ Added devfs support.
v1.27
19990123 Richard Gooch <rgooch@atnf.csiro.au>
Changed locking to spin with reschedule.
@@ -178,7 +178,6 @@
Moved to linux/arch/i386/kernel/setup.c and
linux/include/asm-i386/bugs.h
19990228 Richard Gooch <rgooch@atnf.csiro.au>
- Added #ifdef CONFIG_DEVFS_FS
Added MTRRIOC_KILL_ENTRY ioctl(2)
Trap for counter underflow in <mtrr_file_del>.
Trap for 4 MiB aligned regions for PPro, stepping <= 7.
@@ -225,6 +224,10 @@
success.
19991008 Manfred Spraul <manfreds@colorfullife.com>
replaced spin_lock_reschedule() with a normal semaphore.
+ v1.36
+ 20000221 Richard Gooch <rgooch@atnf.csiro.au>
+ Compile fix if procfs and devfs not enabled.
+ Formatting changes.
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -241,6 +244,7 @@
#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#define MTRR_NEED_STRINGS
@@ -261,7 +265,7 @@
#include <asm/hardirq.h>
#include <linux/irq.h>
-#define MTRR_VERSION "1.35 (19990512)"
+#define MTRR_VERSION "1.36 (20000221)"
#define TRUE 1
#define FALSE 0
@@ -305,11 +309,15 @@ typedef u8 mtrr_type;
TRUE)
#endif
-#ifndef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)
+# define USERSPACE_INTERFACE
+#endif
+
+#ifndef USERSPACE_INTERFACE
# define compute_ascii() while (0)
#endif
-#ifdef CONFIG_PROC_FS
+#ifdef USERSPACE_INTERFACE
static char *ascii_buffer = NULL;
static unsigned int ascii_buf_bytes = 0;
#endif
@@ -317,7 +325,7 @@ static unsigned int *usage_table = NULL;
static DECLARE_MUTEX(main_lock);
/* Private functions */
-#ifdef CONFIG_PROC_FS
+#ifdef USERSPACE_INTERFACE
static void compute_ascii (void);
#endif
@@ -480,8 +488,9 @@ static void intel_get_mtrr (unsigned int reg, unsigned long *base,
unsigned long dummy, mask_lo, base_lo;
rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
- if ((mask_lo & 0x800) == 0) {
- /* Invalid (i.e. free) range. */
+ if ( (mask_lo & 0x800) == 0 )
+ {
+ /* Invalid (i.e. free) range */
*base = 0;
*size = 0;
*type = 0;
@@ -537,22 +546,26 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base,
*size = 0;
/* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
- if (reg < 7) {
- switch (rcr) {
- case 1: *type = MTRR_TYPE_UNCACHABLE; break;
- case 8: *type = MTRR_TYPE_WRBACK; break;
- case 9: *type = MTRR_TYPE_WRCOMB; break;
- case 24:
- default: *type = MTRR_TYPE_WRTHROUGH; break;
- }
- } else {
- switch (rcr) {
- case 0: *type = MTRR_TYPE_UNCACHABLE; break;
- case 8: *type = MTRR_TYPE_WRCOMB; break;
- case 9: *type = MTRR_TYPE_WRBACK; break;
- case 25:
- default: *type = MTRR_TYPE_WRTHROUGH; break;
- }
+ if (reg < 7)
+ {
+ switch (rcr)
+ {
+ case 1: *type = MTRR_TYPE_UNCACHABLE; break;
+ case 8: *type = MTRR_TYPE_WRBACK; break;
+ case 9: *type = MTRR_TYPE_WRCOMB; break;
+ case 24:
+ default: *type = MTRR_TYPE_WRTHROUGH; break;
+ }
+ } else
+ {
+ switch (rcr)
+ {
+ case 0: *type = MTRR_TYPE_UNCACHABLE; break;
+ case 8: *type = MTRR_TYPE_WRCOMB; break;
+ case 9: *type = MTRR_TYPE_WRBACK; break;
+ case 25:
+ default: *type = MTRR_TYPE_WRTHROUGH; break;
+ }
}
} /* End Function cyrix_get_arr */
@@ -653,20 +666,24 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
size &= 0x7fff; /* make sure arr_size <= 14 */
for(arr_size = 0; size; arr_size++, size >>= 1);
- if (reg<7) {
- switch (type) {
- case MTRR_TYPE_UNCACHABLE: arr_type = 1; break;
- case MTRR_TYPE_WRCOMB: arr_type = 9; break;
- case MTRR_TYPE_WRTHROUGH: arr_type = 24; break;
- default: arr_type = 8; break;
- }
- } else {
- switch (type) {
- case MTRR_TYPE_UNCACHABLE: arr_type = 0; break;
- case MTRR_TYPE_WRCOMB: arr_type = 8; break;
- case MTRR_TYPE_WRTHROUGH: arr_type = 25; break;
- default: arr_type = 9; break;
- }
+ if (reg<7)
+ {
+ switch (type) {
+ case MTRR_TYPE_UNCACHABLE: arr_type = 1; break;
+ case MTRR_TYPE_WRCOMB: arr_type = 9; break;
+ case MTRR_TYPE_WRTHROUGH: arr_type = 24; break;
+ default: arr_type = 8; break;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case MTRR_TYPE_UNCACHABLE: arr_type = 0; break;
+ case MTRR_TYPE_WRCOMB: arr_type = 8; break;
+ case MTRR_TYPE_WRTHROUGH: arr_type = 25; break;
+ default: arr_type = 9; break;
+ }
}
if (do_safe) set_mtrr_prepare (&ctxt);
@@ -779,16 +796,18 @@ static int __init set_mtrr_var_range_testing (unsigned int index,
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);
+ 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);
+ rdmsr (MTRRphysMask_MSR(index), lo, hi);
- if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
- || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
+ 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;
}
@@ -816,22 +835,27 @@ static int __init set_fixed_ranges_testing(mtrr_type *frs)
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]);
+ 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]);
+ 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) {
+ 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;
}
@@ -899,8 +923,8 @@ static unsigned long __init set_mtrr_state (struct mtrr_state *state,
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)
+ 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;
@@ -1010,7 +1034,7 @@ static void init_table (void)
return;
}
for (i = 0; i < max; i++) usage_table[i] = 1;
-#ifdef CONFIG_PROC_FS
+#ifdef USERSPACE_INTERFACE
if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL )
{
printk ("mtrr: could not allocate\n");
@@ -1053,11 +1077,14 @@ static int cyrix_get_free_region (unsigned long base, unsigned long size)
unsigned long lbase, lsize;
/* If we are to set up a region >32M then look at ARR7 immediately */
- if (size > 0x2000000UL) {
+ if (size > 0x2000000UL)
+ {
cyrix_get_arr (7, &lbase, &lsize, &ltype);
if (lsize < 1) return 7;
- /* else try ARR0-ARR6 first */
- } else {
+ /* Else try ARR0-ARR6 first */
+ }
+ else
+ {
for (i = 0; i < 7; i++)
{
cyrix_get_arr (i, &lbase, &lsize, &ltype);
@@ -1095,29 +1122,32 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
switch (boot_cpu_data.x86_vendor)
{
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */
- /* Apply the K6 block alignment and size rules
+ if (boot_cpu_data.x86 < 6)
+ { /* pre-Athlon CPUs */
+ /* Apply the K6 block alignment and size rules
In order
o Uncached or gathering only
o 128K or bigger block
o Power of 2 block
o base suitably aligned to the power
*/
- if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
- (size & ~(size-1))-size || (base & (size-1)))
- return -EINVAL;
+ if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+ (size & ~(size-1))-size || ( base & (size-1) ) )
+ return -EINVAL;
break;
- } /* else fall through */
+ }
+ /* Else fall through */
case X86_VENDOR_INTEL:
- /* Double check for Intel, we may run on Athlon. */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
- /* For Intel PPro stepping <= 7, must be 4 MiB aligned */
- if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
- (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
- {
- printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
- return -EINVAL;
- }
+ /* Double check for Intel, we may run on Athlon */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ {
+ /* For Intel PPro stepping <= 7, must be 4 MiB aligned */
+ if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+ (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) )
+ {
+ printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+ return -EINVAL;
+ }
}
/* Fall through */
case X86_VENDOR_CYRIX:
@@ -1232,7 +1262,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
max = get_num_var_ranges ();
- down(&main_lock);
+ down (&main_lock);
if (reg < 0)
{
/* Search for existing MTRR */
@@ -1254,15 +1284,15 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
}
if (reg >= max)
{
- up(&main_lock);
+ up (&main_lock);
printk ("mtrr: register: %d too big\n", reg);
return -EINVAL;
}
if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX)
{
- if ((reg == 3) && arr3_protected)
+ if ( (reg == 3) && arr3_protected )
{
- up(&main_lock);
+ up (&main_lock);
printk ("mtrr: ARR3 cannot be changed\n");
return -EINVAL;
}
@@ -1270,23 +1300,23 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
(*get_mtrr) (reg, &lbase, &lsize, &ltype);
if (lsize < 1)
{
- up(&main_lock);
+ up (&main_lock);
printk ("mtrr: MTRR %d not used\n", reg);
return -EINVAL;
}
if (usage_table[reg] < 1)
{
- up(&main_lock);
+ up (&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 ();
- up(&main_lock);
+ up (&main_lock);
return reg;
} /* End Function mtrr_del */
-#ifdef CONFIG_PROC_FS
+#ifdef USERSPACE_INTERFACE
static int mtrr_file_add (unsigned long base, unsigned long size,
unsigned int type, char increment, struct file *file)
@@ -1469,18 +1499,25 @@ static int mtrr_close (struct inode *ino, struct file *file)
static struct file_operations mtrr_fops =
{
- read: mtrr_read,
- write: mtrr_write,
- ioctl: mtrr_ioctl,
- release: mtrr_close,
+ read: mtrr_read,
+ write: mtrr_write,
+ ioctl: mtrr_ioctl,
+ release: mtrr_close,
};
-static struct inode_operations proc_mtrr_inode_operations = {
- &mtrr_fops, /* default property file-ops */
+# ifdef CONFIG_PROC_FS
+
+static struct inode_operations proc_mtrr_inode_operations =
+{
+ &mtrr_fops, /* default property file-ops */
};
static struct proc_dir_entry *proc_root_mtrr;
+# endif /* CONFIG_PROC_FS */
+
+static devfs_handle_t devfs_handle = NULL;
+
static void compute_ascii (void)
{
char factor;
@@ -1515,25 +1552,30 @@ static void compute_ascii (void)
ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
}
}
+ devfs_set_file_size (devfs_handle, ascii_buf_bytes);
+# ifdef CONFIG_PROC_FS
proc_root_mtrr->size = ascii_buf_bytes;
+# endif /* CONFIG_PROC_FS */
} /* End Function compute_ascii */
-#endif /* CONFIG_PROC_FS */
+#endif /* USERSPACE_INTERFACE */
EXPORT_SYMBOL(mtrr_add);
EXPORT_SYMBOL(mtrr_del);
#ifdef __SMP__
-typedef struct {
- unsigned long base;
- unsigned long size;
- mtrr_type type;
+typedef struct
+{
+ unsigned long base;
+ unsigned long size;
+ mtrr_type type;
} arr_state_t;
-arr_state_t arr_state[8] __initdata = {
- {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
- {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+arr_state_t arr_state[8] __initdata =
+{
+ {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+ {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
};
unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
@@ -1591,31 +1633,35 @@ static void __init cyrix_arr_init(void)
ccr[5] = getCx86 (CX86_CCR5);
ccr[6] = getCx86 (CX86_CCR6);
- if (ccr[3] & 1) {
- ccrc[3] = 1;
- arr3_protected = 1;
- } else {
- /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
- * access to SMM memory through ARR3 (bit 7).
- */
- if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
- if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
- if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
- arr3_protected = 0;
- if (ccr[6] & 0x02) {
- ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
- setCx86 (CX86_CCR6, ccr[6]);
- }
- /* Disable ARR3. This is safe now that we disabled SMM. */
- /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+ if (ccr[3] & 1)
+ {
+ ccrc[3] = 1;
+ arr3_protected = 1;
+ }
+ else
+ {
+ /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+ * access to SMM memory through ARR3 (bit 7).
+ */
+ if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+ if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+ if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+ arr3_protected = 0;
+ if (ccr[6] & 0x02) {
+ ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */
+ setCx86 (CX86_CCR6, ccr[6]);
+ }
+ /* Disable ARR3. This is safe now that we disabled SMM. */
+ /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
}
/* If we changed CCR1 in memory, change it in the processor, too. */
if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
/* Enable ARR usage by the processor */
- if (!(ccr[5] & 0x20)) {
- ccr[5] |= 0x20; ccrc[5] = 1;
- setCx86 (CX86_CCR5, ccr[5]);
+ if (!(ccr[5] & 0x20))
+ {
+ ccr[5] |= 0x20; ccrc[5] = 1;
+ setCx86 (CX86_CCR5, ccr[5]);
}
#ifdef __SMP__
@@ -1667,11 +1713,14 @@ static void __init mtrr_setup(void)
switch (boot_cpu_data.x86_vendor)
{
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */
- get_mtrr = amd_get_mtrr;
- set_mtrr_up = amd_set_mtrr_up;
- break;
- } /* else fall through */
+ if (boot_cpu_data.x86 < 6)
+ {
+ /* pre-Athlon CPUs */
+ get_mtrr = amd_get_mtrr;
+ set_mtrr_up = amd_set_mtrr_up;
+ break;
+ }
+ /* Else fall through */
case X86_VENDOR_INTEL:
get_mtrr = intel_get_mtrr;
set_mtrr_up = intel_set_mtrr_up;
@@ -1700,7 +1749,7 @@ void __init mtrr_init_boot_cpu(void)
switch (boot_cpu_data.x86_vendor)
{
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */
+ if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */
case X86_VENDOR_INTEL:
get_mtrr_state (&smp_mtrr_state);
break;
@@ -1738,7 +1787,7 @@ void __init mtrr_init_secondary_cpu(void)
switch (boot_cpu_data.x86_vendor)
{
case X86_VENDOR_AMD:
- /* Just for robustness: pre-Athlon CPUs cannot do SMP. */
+ /* Just for robustness: pre-Athlon CPUs cannot do SMP */
if (boot_cpu_data.x86 < 6) break;
case X86_VENDOR_INTEL:
intel_mtrr_init_secondary_cpu ();
@@ -1762,17 +1811,17 @@ void __init mtrr_init_secondary_cpu(void)
int __init mtrr_init(void)
{
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-# ifdef __SMP__
+#ifdef __SMP__
switch (boot_cpu_data.x86_vendor)
{
case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */
+ if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */
case X86_VENDOR_INTEL:
finalize_mtrr_state (&smp_mtrr_state);
mtrr_state_warn (smp_changes_mask);
break;
}
-# else /* __SMP__ */
+#else /* __SMP__ */
mtrr_setup ();
switch (boot_cpu_data.x86_vendor)
{
@@ -1783,12 +1832,17 @@ int __init mtrr_init(void)
centaur_mcr_init ();
break;
}
-# endif /* !__SMP__ */
+#endif /* !__SMP__ */
-# ifdef CONFIG_PROC_FS
- proc_root_mtrr = create_proc_entry("mtrr", S_IWUSR|S_IRUGO, &proc_root);
+#ifdef CONFIG_PROC_FS
+ proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
proc_root_mtrr->ops = &proc_mtrr_inode_operations;
-#endif
+#endif
+#ifdev CONFIG_DEVFS_FS
+ devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0,
+ S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
+ &mtrr_fops, NULL);
+#endif
init_table ();
return 0;
} /* End Function mtrr_init */
diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
index 18b203228..4bd1486fe 100644
--- a/arch/i386/kernel/pci-dma.c
+++ b/arch/i386/kernel/pci-dma.c
@@ -13,20 +13,6 @@
#include <linux/pci.h>
#include <asm/io.h>
-/* Pure 2^n version of get_order */
-extern __inline__ int __get_order(unsigned long size)
-{
- int order;
-
- size = (size-1) >> (PAGE_SHIFT-1);
- order = -1;
- do {
- size >>= 1;
- order++;
- } while (size);
- return order;
-}
-
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
{
@@ -35,7 +21,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
gfp |= GFP_DMA;
- ret = (void *)__get_free_pages(gfp, __get_order(size));
+ ret = (void *)__get_free_pages(gfp, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
@@ -47,5 +33,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
- free_pages((unsigned long)vaddr, __get_order(size));
+ free_pages((unsigned long)vaddr, get_order(size));
}
diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c
index ee2edca1e..6dd0a4306 100644
--- a/arch/i386/kernel/pci-i386.c
+++ b/arch/i386/kernel/pci-i386.c
@@ -132,7 +132,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size)
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
- if (size >= 0x100) {
+ if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index 590e01fd5..d5b2b0062 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -883,6 +883,18 @@ static void __init pci_fixup_i450nx(struct pci_dev *d)
}
}
+static void __init pci_fixup_i450gx(struct pci_dev *d)
+{
+ /*
+ * i450GX and i450KX -- Find and scan all secondary buses.
+ * (called separately for each PCI bridge found)
+ */
+ u8 busno;
+ pci_read_config_byte(d, 0x4a, &busno);
+ printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+ pci_scan_bus(busno, pci_root_ops, NULL);
+}
+
static void __init pci_fixup_rcc(struct pci_dev *d)
{
/*
@@ -954,6 +966,7 @@ static void __init pci_fixup_ide_trash(struct pci_dev *d)
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_HE, pci_fixup_rcc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_LE, pci_fixup_rcc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq },
@@ -1036,6 +1049,18 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
* table, but unfortunately we have to know the interrupt router chip.
*/
+/*
+ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
+ * Avoid using: 13, 14 and 15 (FP error and IDE).
+ * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse)
+ */
+static unsigned int pcibios_irq_mask = 0xfff8;
+
+static unsigned pcibios_irq_penalty[16] = {
+ 10000, 10000, 10000, 100, 100, 0, 0, 100,
+ 0, 0, 0, 0, 100, 1000, 1000, 1000
+};
+
static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign)
{
struct irq_info *q;
@@ -1043,6 +1068,7 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
int i, pirq, newirq;
u32 rtrid, mask;
u8 x;
+ char *msg = NULL;
pin--;
DBG("IRQ for %s(%d)", dev->slot_name, pin);
@@ -1066,10 +1092,15 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
return NULL;
}
DBG(" -> PIRQ %02x, mask %04x", pirq, mask);
- if (!assign || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- newirq = 0;
- else for(newirq = 13; newirq && !(mask & (1 << newirq)); newirq--)
- ;
+ newirq = 0;
+ if (assign && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+ for (i = 0; i < 16; i++) {
+ if (!(mask & pcibios_irq_mask & (1 << i)))
+ continue;
+ if (pcibios_irq_penalty[i] < pcibios_irq_penalty[newirq])
+ newirq = i;
+ }
+ }
if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
DBG(" -> router not found\n");
return NULL;
@@ -1094,27 +1125,30 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
pci_read_config_byte(router, pirq, &x);
if (x < 16) {
DBG(" -> [PIIX] %02x\n", x);
- dev->irq = x;
- return "PIIX";
+ newirq = x;
+ msg = "PIIX";
} else if (newirq) {
DBG(" -> [PIIX] set to %02x\n", newirq);
pci_write_config_byte(router, pirq, newirq);
- dev->irq = newirq;
- return "PIIX-NEW";
- }
- DBG(" -> [PIIX] sink\n");
- return NULL;
+ msg = "PIIX-NEW";
+ } else
+ DBG(" -> [PIIX] sink\n");
+ break;
case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
if (newirq && mask == (1 << newirq)) {
/* Only one IRQ available -> use it */
- dev->irq = newirq;
- return "guess";
+ msg = "guess";
}
- return NULL;
}
#undef ID
+
+ if (msg) {
+ dev->irq = newirq;
+ pcibios_irq_penalty[newirq]++;
+ }
+ return msg;
}
static void __init pcibios_fixup_irqs(void)
@@ -1134,6 +1168,18 @@ static void __init pcibios_fixup_irqs(void)
pcibios_irq_peer_trick(rtable);
pci_for_each_dev(dev) {
+ /*
+ * If the BIOS has set an out of range IRQ number, just ignore it.
+ * Also keep track of which IRQ's are already in use.
+ */
+ if (dev->irq >= 16) {
+ DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
+ dev->irq = 0;
+ }
+ pcibios_irq_penalty[dev->irq]++;
+ }
+
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
#if defined(CONFIG_X86_IO_APIC)
/*
@@ -1171,10 +1217,8 @@ static void __init pcibios_fixup_irqs(void)
}
#endif
/*
- * Fix out-of-range IRQ numbers and missing IRQs.
+ * Still no IRQ? Try to assign one...
*/
- if (dev->irq >= NR_IRQS)
- dev->irq = 0;
if (pin && !dev->irq && pirq_table) {
char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 0);
if (msg)
@@ -1280,6 +1324,9 @@ char * __init pcibios_setup(char *str)
} else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
return NULL;
+ } else if (!strncmp(str, "irqmask=", 8)) {
+ pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
+ return NULL;
}
return str;
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index c38e383e7..0f61ca543 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -48,16 +48,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
int hlt_counter=0;
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-
/*
* Powermanagement idle function, if any..
*/
@@ -68,6 +58,16 @@ void (*pm_idle)(void) = NULL;
*/
void (*pm_power_off)(void) = NULL;
+void disable_hlt(void)
+{
+ hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+ hlt_counter--;
+}
+
/*
* We use this if we don't have any better
* idle routine..
@@ -293,7 +293,7 @@ void machine_real_restart(unsigned char *code, int length)
void machine_restart(char * __unused)
{
-#if __SMP__
+#if CONFIG_SMP
/*
* Stop all CPUs and turn off local APICs and the IO-APIC, so
* other OSs see a clean IRQ state.
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index e72f95160..cd2a3d8af 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -1515,7 +1515,7 @@ unsigned long cpu_initialized = 0;
* and IDT. We reload them nevertheless, this function acts as a
* 'CPU state barrier', nothing should get across.
*/
-void cpu_init (void)
+void __init cpu_init (void)
{
int nr = smp_processor_id();
struct tss_struct * t = &init_tss[nr];
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 0b585513f..12f193c71 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -103,7 +103,7 @@
/* The 'big kernel lock' */
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
-struct tlb_state cpu_tlbstate[NR_CPUS];
+struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }};
/*
* the following functions deal with sending IPIs between CPUs.
@@ -347,12 +347,7 @@ asmlinkage void smp_invalidate_interrupt (void)
__flush_tlb_one(flush_va);
} else
leave_mm(cpu);
- } else {
- extern void show_stack (void *);
- printk("hm #1: %p, %p.\n", flush_mm, cpu_tlbstate[cpu].active_mm);
- show_stack(NULL);
}
- __flush_tlb();
ack_APIC_irq();
clear_bit(cpu, &flush_cpumask);
}
@@ -382,7 +377,7 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
* Temporarily this turns IRQs off, so that lockups are
* detected by the NMI watchdog.
*/
- spin_lock_irq(&tlbstate_lock);
+ spin_lock(&tlbstate_lock);
flush_mm = mm;
flush_va = va;
@@ -398,7 +393,7 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
flush_mm = NULL;
flush_va = 0;
- spin_unlock_irq(&tlbstate_lock);
+ spin_unlock(&tlbstate_lock);
}
void flush_tlb_current_task(void)
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 4ef25674f..c3991b056 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -307,27 +307,30 @@ static void __init pagetable_init(void)
pmd_t *pmd;
pte_t *pte;
int i, j, k;
- unsigned long vaddr;
- unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
+ unsigned long vaddr, end;
- pgd_base = swapper_pg_dir;
+ end = (unsigned long)__va(max_low_pfn*PAGE_SIZE) - 1;
- vaddr = PAGE_OFFSET;
- i = __pgd_offset(vaddr);
+ i = __pgd_offset(PAGE_OFFSET);
+ pgd_base = swapper_pg_dir;
pgd = pgd_base + i;
- for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) {
+ for (; i < PTRS_PER_PGD; pgd++, i++) {
vaddr = i*PGDIR_SIZE;
+ if (vaddr >= end)
+ break;
#if CONFIG_X86_PAE
- pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE);
set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
#else
pmd = (pmd_t *)pgd;
#endif
if (pmd != pmd_offset(pgd, 0))
BUG();
- for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) {
+ for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
+ if (vaddr >= end)
+ break;
if (cpu_has_pse) {
unsigned long __pe;
@@ -349,10 +352,10 @@ static void __init pagetable_init(void)
if (pte != pte_offset(pmd, 0))
BUG();
- for (k = 0;
- (k < PTRS_PER_PTE) && (vaddr <= end);
- pte++, k++) {
+ for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
+ if (vaddr >= end)
+ break;
*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
}
}