summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-01-10 05:27:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-01-10 05:27:25 +0000
commitc9c06167e7933d93a6e396174c68abf242294abb (patch)
treed9a8bb30663e9a3405a1ef37ffb62bc14b9f019f /arch/i386
parentf79e8cc3c34e4192a3e5ef4cc9c6542fdef703c0 (diff)
Merge with Linux 2.4.0-test12.
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/boot/setup.S12
-rw-r--r--arch/i386/config.in2
-rw-r--r--arch/i386/defconfig53
-rw-r--r--arch/i386/kernel/apic.c118
-rw-r--r--arch/i386/kernel/apm.c188
-rw-r--r--arch/i386/kernel/dmi_scan.c182
-rw-r--r--arch/i386/kernel/head.S2
-rw-r--r--arch/i386/kernel/i386_ksyms.c2
-rw-r--r--arch/i386/kernel/irq.c2
-rw-r--r--arch/i386/kernel/microcode.c122
-rw-r--r--arch/i386/kernel/mtrr.c378
-rw-r--r--arch/i386/kernel/pci-irq.c128
-rw-r--r--arch/i386/kernel/process.c4
-rw-r--r--arch/i386/kernel/setup.c59
-rw-r--r--arch/i386/kernel/smpboot.c8
-rw-r--r--arch/i386/kernel/traps.c12
-rw-r--r--arch/i386/mm/init.c8
17 files changed, 941 insertions, 339 deletions
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 0da4e866e..c52b170ec 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -825,10 +825,18 @@ bootsect_panic_mess:
#
# Some machines have delusions that the keyboard buffer is always full
# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads. With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
empty_8042:
pushl %ecx
- movl $0x00FFFFFF, %ecx
+ movl $100000, %ecx
empty_8042_loop:
decl %ecx
@@ -867,7 +875,7 @@ gettime:
# Delay is needed after doing I/O
delay:
- jmp .+2 # jmp $+2
+ outb %al,$0x80
ret
# Descriptor tables
diff --git a/arch/i386/config.in b/arch/i386/config.in
index d6c63a8b8..87fc106f8 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -140,7 +140,7 @@ if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
fi
tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
-tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE
tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 9f8625c6e..bdcf8cf6b 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -649,20 +649,15 @@ CONFIG_USB_UHCI_ALT=y
# CONFIG_USB_OHCI is not set
#
-# USB Devices
+# USB Device Class drivers
#
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_SCANNER is not set
# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_BLUETOOTH is not set
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_USS720 is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# USB Human Interface Devices (HID)
@@ -673,6 +668,44 @@ CONFIG_USB_STORAGE=y
#
#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PLUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_NET1080 is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB misc drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
# Kernel hacking
#
# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index fc54896f8..4179c8f13 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -220,66 +220,19 @@ void __init setup_local_APIC (void)
BUG();
/*
- * Set up LVT0, LVT1:
- *
- * set up through-local-APIC on the BP's LINT0. This is not
- * strictly necessery in pure symmetric-IO mode, but sometimes
- * we delegate interrupts to the 8259A.
- */
- /*
- * TODO: set up through-local-APIC from through-I/O-APIC? --macro
- */
- value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
- if (!smp_processor_id() && (pic_mode || !value)) {
- value = APIC_DM_EXTINT;
- printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
- } else {
- value = APIC_DM_EXTINT | APIC_LVT_MASKED;
- printk("masked ExtINT on CPU#%d\n", smp_processor_id());
- }
- apic_write_around(APIC_LVT0, value);
-
- /*
- * only the BP should see the LINT1 NMI signal, obviously.
+ * Intel recommends to set DFR, LDR and TPR before enabling
+ * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
+ * document number 292116). So here it goes...
*/
- if (!smp_processor_id())
- value = APIC_DM_NMI;
- else
- value = APIC_DM_NMI | APIC_LVT_MASKED;
- if (!APIC_INTEGRATED(ver)) /* 82489DX */
- value |= APIC_LVT_LEVEL_TRIGGER;
- apic_write_around(APIC_LVT1, value);
-
- if (APIC_INTEGRATED(ver)) { /* !82489DX */
- maxlvt = get_maxlvt();
- if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
- apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- printk("ESR value before enabling vector: %08lx\n", value);
-
- value = ERROR_APIC_VECTOR; // enables sending errors
- apic_write_around(APIC_LVTERR, value);
- /*
- * spec says clear errors after enabling vector.
- */
- if (maxlvt > 3)
- apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- printk("ESR value after enabling vector: %08lx\n", value);
- } else
- printk("No ESR for 82489DX.\n");
/*
- * Set Task Priority to 'accept all'. We never change this
- * later on.
+ * Put the APIC into flat delivery mode.
+ * Must be "all ones" explicitly for 82489DX.
*/
- value = apic_read(APIC_TASKPRI);
- value &= ~APIC_TPRI_MASK;
- apic_write_around(APIC_TASKPRI, value);
+ apic_write_around(APIC_DFR, 0xffffffff);
/*
- * Set up the logical destination ID and put the
- * APIC into flat delivery mode.
+ * Set up the logical destination ID.
*/
value = apic_read(APIC_LDR);
value &= ~APIC_LDR_MASK;
@@ -287,9 +240,12 @@ void __init setup_local_APIC (void)
apic_write_around(APIC_LDR, value);
/*
- * Must be "all ones" explicitly for 82489DX.
+ * Set Task Priority to 'accept all'. We never change this
+ * later on.
*/
- apic_write_around(APIC_DFR, 0xffffffff);
+ value = apic_read(APIC_TASKPRI);
+ value &= ~APIC_TPRI_MASK;
+ apic_write_around(APIC_TASKPRI, value);
/*
* Now that we are all set up, enable the APIC
@@ -326,6 +282,56 @@ void __init setup_local_APIC (void)
*/
value |= SPURIOUS_APIC_VECTOR;
apic_write_around(APIC_SPIV, value);
+
+ /*
+ * Set up LVT0, LVT1:
+ *
+ * set up through-local-APIC on the BP's LINT0. This is not
+ * strictly necessery in pure symmetric-IO mode, but sometimes
+ * we delegate interrupts to the 8259A.
+ */
+ /*
+ * TODO: set up through-local-APIC from through-I/O-APIC? --macro
+ */
+ value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
+ if (!smp_processor_id() && (pic_mode || !value)) {
+ value = APIC_DM_EXTINT;
+ printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
+ } else {
+ value = APIC_DM_EXTINT | APIC_LVT_MASKED;
+ printk("masked ExtINT on CPU#%d\n", smp_processor_id());
+ }
+ apic_write_around(APIC_LVT0, value);
+
+ /*
+ * only the BP should see the LINT1 NMI signal, obviously.
+ */
+ if (!smp_processor_id())
+ value = APIC_DM_NMI;
+ else
+ value = APIC_DM_NMI | APIC_LVT_MASKED;
+ if (!APIC_INTEGRATED(ver)) /* 82489DX */
+ value |= APIC_LVT_LEVEL_TRIGGER;
+ apic_write_around(APIC_LVT1, value);
+
+ if (APIC_INTEGRATED(ver)) { /* !82489DX */
+ maxlvt = get_maxlvt();
+ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
+ apic_write(APIC_ESR, 0);
+ value = apic_read(APIC_ESR);
+ printk("ESR value before enabling vector: %08lx\n", value);
+
+ value = ERROR_APIC_VECTOR; // enables sending errors
+ apic_write_around(APIC_LVTERR, value);
+ /*
+ * spec says clear errors after enabling vector.
+ */
+ if (maxlvt > 3)
+ apic_write(APIC_ESR, 0);
+ value = apic_read(APIC_ESR);
+ printk("ESR value after enabling vector: %08lx\n", value);
+ } else
+ printk("No ESR for 82489DX.\n");
}
void __init init_apic_mappings(void)
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index dc47528cd..9703e3304 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -37,6 +37,7 @@
* Nov 1999, Version 1.11
* Jan 2000, Version 1.12
* Feb 2000, Version 1.13
+ * Nov 2000, Version 1.14
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -144,6 +145,9 @@
* <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
* Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore
* interval is now configurable.
+ * 1.14: Make connection version persist across module unload/load.
+ * Enable and engage power management earlier.
+ * Disengage power management on module unload.
*
* APM 1.1 Reference:
*
@@ -344,9 +348,9 @@ static int kapmd_running;
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user * user_list = NULL;
+static struct apm_user * user_list;
-static char driver_version[] = "1.13"; /* no spaces */
+static char driver_version[] = "1.14"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
@@ -527,7 +531,7 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
&dummy, &dummy))
return (eax >> 8) & 0xff;
*event = ebx;
- if (apm_bios_info.version < 0x0102)
+ if (apm_info.connection_version < 0x0102)
*info = ~0; /* indicate info not valid */
else
*info = ecx;
@@ -559,7 +563,7 @@ static int apm_do_idle(void)
#ifdef ALWAYS_CALL_BUSY
clock_slowed = 1;
#else
- clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+ clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
#endif
return 1;
}
@@ -670,15 +674,15 @@ static int apm_enable_power_management(int enable)
{
u32 eax;
- if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+ if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
return APM_NOT_ENGAGED;
if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
enable, &eax))
return (eax >> 8) & 0xff;
if (enable)
- apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+ apm_info.bios.flags &= ~APM_BIOS_DISABLED;
else
- apm_bios_info.flags |= APM_BIOS_DISABLED;
+ apm_info.bios.flags |= APM_BIOS_DISABLED;
return APM_SUCCESS;
}
#endif
@@ -691,6 +695,8 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
u32 edx;
u32 dummy;
+ if (apm_info.get_power_status_broken)
+ return APM_32_UNSUPPORTED;
if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
&eax, &ebx, &ecx, &edx, &dummy))
return (eax >> 8) & 0xff;
@@ -710,7 +716,7 @@ static int apm_get_battery_status(u_short which, u_short *status,
u32 edx;
u32 esi;
- if (apm_bios_info.version < 0x0102) {
+ if (apm_info.connection_version < 0x0102) {
/* pretend we only have one battery. */
if (which != 1)
return APM_BAD_DEVICE;
@@ -734,15 +740,15 @@ static int apm_engage_power_management(u_short device, int enable)
u32 eax;
if ((enable == 0) && (device == APM_DEVICE_ALL)
- && (apm_bios_info.flags & APM_BIOS_DISABLED))
+ && (apm_info.bios.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;
+ apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
else
- apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+ apm_info.bios.flags |= APM_BIOS_DISENGAGED;
}
return APM_SUCCESS;
}
@@ -890,7 +896,7 @@ static int send_event(apm_event_t event)
printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );
return 0;
}
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
return 0;
}
@@ -993,13 +999,13 @@ static void check_events(void)
case APM_USER_SUSPEND:
#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
break;
#endif
case APM_SYS_SUSPEND:
if (ignore_bounce) {
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
break;
}
@@ -1064,7 +1070,7 @@ static void apm_event_handler(void)
int err;
if ((standbys_pending > 0) || (suspends_pending > 0)) {
- if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+ if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
pending_count = 4;
if (debug)
printk(KERN_DEBUG "apm: setting state busy\n");
@@ -1334,7 +1340,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
unsigned short bx;
unsigned short cx;
unsigned short dx;
- unsigned short error;
+ int error;
unsigned short ac_line_status = 0xff;
unsigned short battery_status = 0xff;
unsigned short battery_flag = 0xff;
@@ -1351,7 +1357,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
if ((cx & 0xff) != 0xff)
percentage = cx & 0xff;
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version > 0x100) {
battery_flag = (cx >> 8) & 0xff;
if (dx != 0xffff) {
units = (dx & 0x8000) ? "min" : "sec";
@@ -1399,9 +1405,9 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
driver_version,
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff,
- apm_bios_info.flags,
+ (apm_info.bios.version >> 8) & 0xff,
+ apm_info.bios.version & 0xff,
+ apm_info.bios.flags,
ac_line_status,
battery_status,
battery_flag,
@@ -1417,7 +1423,7 @@ static int apm(void *unused)
unsigned short bx;
unsigned short cx;
unsigned short dx;
- unsigned short error;
+ int error;
char * power_stat;
char * bat_stat;
@@ -1429,22 +1435,53 @@ static int apm(void *unused)
sigfillset(&current->blocked);
current->tty = NULL; /* get rid of controlling tty */
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version == 0) {
+ apm_info.connection_version = apm_info.bios.version;
+ if (apm_info.connection_version > 0x100) {
+ /*
+ * We only support BIOSs up to version 1.2
+ */
+ if (apm_info.connection_version > 0x0102)
+ apm_info.connection_version = 0x0102;
+ error = apm_driver_version(&apm_info.connection_version);
+ if (error != APM_SUCCESS) {
+ apm_error("driver version", error);
+ /* Fall back to an APM 1.0 connection. */
+ apm_info.connection_version = 0x100;
+ }
+ }
+ }
+
+ if (debug)
+ printk(KERN_INFO "apm: Connection version %d.%d\n",
+ (apm_info.connection_version >> 8) & 0xff,
+ apm_info.connection_version & 0xff);
+
+#ifdef CONFIG_APM_DO_ENABLE
+ if (apm_info.bios.flags & APM_BIOS_DISABLED) {
/*
- * We only support BIOSs up to version 1.2
+ * This call causes my NEC UltraLite Versa 33/C to hang if it
+ * is booted with PM disabled but not in the docking station.
+ * Unfortunate ...
*/
- if (apm_bios_info.version > 0x0102)
- apm_bios_info.version = 0x0102;
- if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
- /* Fall back to an APM 1.0 connection. */
- apm_bios_info.version = 0x100;
+ error = apm_enable_power_management(1);
+ if (error) {
+ apm_error("enable power management", error);
+ return -1;
+ }
+ }
+#endif
+
+ if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
+ && (apm_info.connection_version > 0x0100)) {
+ error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+ if (error) {
+ apm_error("engage power management", error);
+ return -1;
}
}
- 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);
+ if (debug && (smp_num_cpus == 1)) {
error = apm_get_power_status(&bx, &cx, &dx);
if (error)
printk(KERN_INFO "apm: power status not available\n");
@@ -1469,7 +1506,7 @@ static int apm(void *unused)
printk("unknown\n");
else
printk("%d%%\n", cx & 0xff);
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version > 0x100) {
printk(KERN_INFO
"apm: battery flag 0x%02x, battery life ",
(cx >> 8) & 0xff);
@@ -1483,29 +1520,6 @@ static int apm(void *unused)
}
}
-#ifdef CONFIG_APM_DO_ENABLE
- if (apm_bios_info.flags & APM_BIOS_DISABLED) {
- /*
- * This call causes my NEC UltraLite Versa 33/C to hang if it
- * is booted with PM disabled but not in the docking station.
- * Unfortunate ...
- */
- 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)
- && (apm_bios_info.version > 0x0100)) {
- 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)
pm_power_off = apm_power_off;
@@ -1584,17 +1598,19 @@ static struct miscdevice apm_device = {
*/
static int __init apm_init(void)
{
- if (apm_bios_info.version == 0) {
+ struct proc_dir_entry *apm_proc;
+
+ if (apm_info.bios.version == 0) {
printk(KERN_INFO "apm: BIOS not found.\n");
return -ENODEV;
}
printk(KERN_INFO
"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
- ((apm_bios_info.version >> 8) & 0xff),
- (apm_bios_info.version & 0xff),
- apm_bios_info.flags,
+ ((apm_info.bios.version >> 8) & 0xff),
+ (apm_info.bios.version & 0xff),
+ apm_info.bios.flags,
driver_version);
- if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+ if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
printk(KERN_INFO "apm: no 32 bit BIOS support\n");
return -ENODEV;
}
@@ -1603,23 +1619,23 @@ static int __init apm_init(void)
* Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
* but is reportedly a 1.0 BIOS.
*/
- if (apm_bios_info.version == 0x001)
- apm_bios_info.version = 0x100;
+ if (apm_info.bios.version == 0x001)
+ apm_info.bios.version = 0x100;
/* BIOS < 1.2 doesn't set cseg_16_len */
- if (apm_bios_info.version < 0x102)
- apm_bios_info.cseg_16_len = 0; /* 64k */
+ if (apm_info.bios.version < 0x102)
+ apm_info.bios.cseg_16_len = 0; /* 64k */
if (debug) {
printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
- apm_bios_info.cseg, apm_bios_info.offset,
- apm_bios_info.cseg_16, apm_bios_info.dseg);
- if (apm_bios_info.version > 0x100)
+ apm_info.bios.cseg, apm_info.bios.offset,
+ apm_info.bios.cseg_16, apm_info.bios.dseg);
+ if (apm_info.bios.version > 0x100)
printk(" cseg len %x, dseg len %x",
- apm_bios_info.cseg_len,
- apm_bios_info.dseg_len);
- if (apm_bios_info.version > 0x101)
- printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
+ apm_info.bios.cseg_len,
+ apm_info.bios.dseg_len);
+ if (apm_info.bios.version > 0x101)
+ printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
printk("\n");
}
@@ -1647,16 +1663,16 @@ static int __init apm_init(void)
__va((unsigned long)0x40 << 4));
_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
- apm_bios_entry.offset = apm_bios_info.offset;
+ apm_bios_entry.offset = apm_info.bios.offset;
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
- __va((unsigned long)apm_bios_info.cseg << 4));
+ __va((unsigned long)apm_info.bios.cseg << 4));
set_base(gdt[APM_CS_16 >> 3],
- __va((unsigned long)apm_bios_info.cseg_16 << 4));
+ __va((unsigned long)apm_info.bios.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
- __va((unsigned long)apm_bios_info.dseg << 4));
+ __va((unsigned long)apm_info.bios.dseg << 4));
#ifndef APM_RELAX_SEGMENTS
- if (apm_bios_info.version == 0x100) {
+ if (apm_info.bios.version == 0x100) {
#endif
/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
_set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
@@ -1667,15 +1683,17 @@ static int __init apm_init(void)
#ifndef APM_RELAX_SEGMENTS
} else {
_set_limit((char *)&gdt[APM_CS >> 3],
- (apm_bios_info.cseg_len - 1) & 0xffff);
+ (apm_info.bios.cseg_len - 1) & 0xffff);
_set_limit((char *)&gdt[APM_CS_16 >> 3],
- (apm_bios_info.cseg_16_len - 1) & 0xffff);
+ (apm_info.bios.cseg_16_len - 1) & 0xffff);
_set_limit((char *)&gdt[APM_DS >> 3],
- (apm_bios_info.dseg_len - 1) & 0xffff);
+ (apm_info.bios.dseg_len - 1) & 0xffff);
}
#endif
- create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ if (apm_proc)
+ SET_MODULE_OWNER(apm_proc);
kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
@@ -1692,6 +1710,14 @@ static int __init apm_init(void)
static void __exit apm_exit(void)
{
+ int error;
+
+ if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
+ && (apm_info.connection_version > 0x0100)) {
+ error = apm_engage_power_management(APM_DEVICE_ALL, 0);
+ if (error)
+ apm_error("disengage power management", error);
+ }
misc_deregister(&apm_device);
remove_proc_entry("apm", NULL);
#ifdef CONFIG_MAGIC_SYSRQ
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
new file mode 100644
index 000000000..b439568c1
--- /dev/null
+++ b/arch/i386/kernel/dmi_scan.c
@@ -0,0 +1,182 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/apm_bios.h>
+#include <asm/io.h>
+
+struct dmi_header
+{
+ u8 type;
+ u8 length;
+ u16 handle;
+};
+
+static char * __init dmi_string(struct dmi_header *dm, u8 s)
+{
+ u8 *bp=(u8 *)dm;
+ bp+=dm->length;
+ s--;
+ while(s>0)
+ {
+ bp+=strlen(bp);
+ bp++;
+ s--;
+ }
+ return bp;
+}
+
+static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
+{
+ u8 *buf;
+ struct dmi_header *dm;
+ u8 *data;
+ int i=1;
+ int last = 0;
+
+ buf = ioremap(base, len);
+ if(buf==NULL)
+ return -1;
+
+ data = buf;
+ while(i<num && (data - buf) < len)
+ {
+ dm=(struct dmi_header *)data;
+ if(dm->type < last)
+ break;
+ last = dm->type;
+ decode(dm);
+ data+=dm->length;
+ while(*data || data[1])
+ data++;
+ data+=2;
+ i++;
+ }
+ iounmap(buf);
+ return 0;
+}
+
+
+int __init dmi_iterate(void (*decode)(struct dmi_header *))
+{
+ unsigned char buf[20];
+ long fp=0xE0000L;
+ fp -= 16;
+
+ while( fp < 0xFFFFF)
+ {
+ fp+=16;
+ isa_memcpy_fromio(buf, fp, 20);
+ if(memcmp(buf, "_DMI_", 5)==0)
+ {
+ u16 num=buf[13]<<8|buf[12];
+ u16 len=buf[7]<<8|buf[6];
+ u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+
+ printk(KERN_INFO "DMI %d.%d present.\n",
+ buf[14]>>4, buf[14]&0x0F);
+ printk(KERN_INFO "%d structures occupying %d bytes.\n",
+ buf[13]<<8|buf[12],
+ buf[7]<<8|buf[6]);
+ printk(KERN_INFO "DMI table at 0x%08X.\n",
+ buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]);
+ if(dmi_table(base,len, num, decode)==0)
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * Process a DMI table entry. Right now all we care about are the BIOS
+ * and machine entries. For 2.4 we should pull the smbus controller info
+ * out of here.
+ */
+
+static void __init dmi_decode(struct dmi_header *dm)
+{
+ u8 *data = (u8 *)dm;
+ char *p;
+
+ switch(dm->type)
+ {
+ case 0:
+ p=dmi_string(dm,data[4]);
+
+ if(*p && *p!=' ')
+ {
+ printk("BIOS Vendor: %s\n", p);
+ printk("BIOS Version: %s\n",
+ dmi_string(dm, data[5]));
+ printk("BIOS Release: %s\n",
+ dmi_string(dm, data[8]));
+ }
+
+ /*
+ * Check for clue free BIOS implementations who use
+ * the following QA technique
+ *
+ * [ Write BIOS Code ]<------
+ * | ^
+ * < Does it Compile >----N--
+ * |Y ^
+ * < Does it Boot Win98 >-N--
+ * |Y
+ * [Ship It]
+ *
+ * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e)
+ * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000)
+ */
+
+ if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0)
+ {
+ if(strcmp(dmi_string(dm, data[5]), "A04")==0
+ && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0)
+ {
+ apm_info.get_power_status_broken = 1;
+ printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+ }
+ }
+ break;
+ case 1:
+ p=dmi_string(dm,data[4]);
+
+ if(*p && *p!=' ')
+ {
+ printk("System Vendor: %s.\n",p);
+ printk("Product Name: %s.\n",
+ dmi_string(dm, data[5]));
+ printk("Version %s.\n",
+ dmi_string(dm, data[6]));
+ printk("Serial Number %s.\n",
+ dmi_string(dm, data[7]));
+ }
+ break;
+ case 2:
+ p=dmi_string(dm,data[4]);
+
+ if(*p && *p!=' ')
+ {
+ printk("Board Vendor: %s.\n",p);
+ printk("Board Name: %s.\n",
+ dmi_string(dm, data[5]));
+ printk("Board Version: %s.\n",
+ dmi_string(dm, data[6]));
+ }
+ break;
+ case 3:
+ p=dmi_string(dm,data[8]);
+ if(*p && *p!=' ')
+ printk("Asset Tag: %s.\n", p);
+ break;
+ }
+}
+
+static int __init dmi_scan_machine(void)
+{
+ return dmi_iterate(dmi_decode);
+}
+
+module_init(dmi_scan_machine);
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index fdb488a15..c74b80135 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -119,12 +119,12 @@ startup_32:
/*
* Clear BSS first so that there are no surprises...
+ * No need to cld as DF is already clear from cld above...
*/
xorl %eax,%eax
movl $ SYMBOL_NAME(__bss_start),%edi
movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
- cld
rep
stosb
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 3de4a76d1..071b3991a 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -68,7 +68,7 @@ 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(apm_info);
EXPORT_SYMBOL(gdt);
EXPORT_SYMBOL_NOVERS(__down_failed);
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 92ddd01f5..cf6878787 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -179,7 +179,7 @@ int get_irq_list(char *buf)
#ifdef CONFIG_SMP
unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile int global_irq_lock;
+unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */
extern void show_stack(unsigned long* esp);
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 5f9925495..f0a88c20e 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -4,13 +4,13 @@
* Copyright (C) 2000 Tigran Aivazian
*
* This driver allows to upgrade microcode on Intel processors
- * belonging to P6 family - PentiumPro, Pentium II,
- * Pentium III, Xeon etc.
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
*
- * Reference: Section 8.10 of Volume III, Intel Pentium III Manual,
- * Order Number 243192 or free download from:
+ * Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual,
+ * Order Number 245472 or free download from:
*
- * http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ * http://developer.intel.com/design/pentium4/manuals/245472.htm
*
* For more information, go to http://www.urbanmyth.org/microcode
*
@@ -44,6 +44,9 @@
* to be 0 on my machine which is why it worked even when I
* disabled update by the BIOS)
* Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>
+ * Intel Pentium 4 processor support and bugfixes.
*/
#include <linux/init.h>
@@ -58,12 +61,20 @@
#include <asm/uaccess.h>
#include <asm/processor.h>
-#define MICROCODE_VERSION "1.07"
+#define MICROCODE_VERSION "1.08"
-MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
+MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
EXPORT_NO_SYMBOLS;
+#define MICRO_DEBUG 0
+
+#if MICRO_DEBUG
+#define printf(x...) printk(##x)
+#else
+#define printf(x...)
+#endif
+
/* VFS interface */
static int microcode_open(struct inode *, struct file *);
static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
@@ -81,6 +92,7 @@ static unsigned int microcode_num; /* number of chunks in microcode */
static char *mc_applied; /* array of applied microcode blocks */
static unsigned int mc_fsize; /* file size of /dev/cpu/microcode */
+/* we share file_operations between misc and devfs mechanisms */
static struct file_operations microcode_fops = {
owner: THIS_MODULE,
read: microcode_read,
@@ -99,23 +111,27 @@ static devfs_handle_t devfs_handle;
static int __init microcode_init(void)
{
- int error = 0;
+ int error;
- if (misc_register(&microcode_dev) < 0) {
+ error = misc_register(&microcode_dev);
+ if (error)
printk(KERN_WARNING
"microcode: can't misc_register on minor=%d\n",
MICROCODE_MINOR);
- error = 1;
- }
+
devfs_handle = devfs_register(NULL, "cpu/microcode",
DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR,
&microcode_fops, NULL);
if (devfs_handle == NULL && error) {
printk(KERN_ERR "microcode: failed to devfs_register()\n");
- return -EINVAL;
+ goto out;
}
- printk(KERN_INFO "P6 Microcode Update Driver v%s\n", MICROCODE_VERSION);
- return 0;
+ printk(KERN_INFO
+ "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n",
+ MICROCODE_VERSION);
+
+out:
+ return error;
}
static void __exit microcode_exit(void)
@@ -124,12 +140,12 @@ static void __exit microcode_exit(void)
devfs_unregister(devfs_handle);
if (mc_applied)
kfree(mc_applied);
- printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n",
+ printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n",
MICROCODE_VERSION);
}
-module_init(microcode_init);
-module_exit(microcode_exit);
+module_init(microcode_init)
+module_exit(microcode_exit)
static int microcode_open(struct inode *unused1, struct file *unused2)
{
@@ -175,18 +191,19 @@ static void do_update_one(void *unused)
unsigned int pf = 0, val[2], rev, sig;
int i,found=0;
- req->err = 1; /* assume the worst */
+ req->err = 1; /* assume update will fail on this cpu */
- if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 != 6){
- printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num);
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+ test_bit(X86_FEATURE_IA64, &c->x86_capability)){
+ printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
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]);
+ if ((c->x86_model >= 5) || (c->x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
pf = 1 << ((val[1] >> 18) & 7);
}
@@ -195,9 +212,28 @@ static void do_update_one(void *unused)
microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
found=1;
- wrmsr(0x8B, 0, 0);
+
+ printf("Microcode\n");
+ printf(" Header Revision %d\n",microcode[i].hdrver);
+ printf(" Date %x/%x/%x\n",
+ ((microcode[i].date >> 24 ) & 0xff),
+ ((microcode[i].date >> 16 ) & 0xff),
+ (microcode[i].date & 0xFFFF));
+ printf(" Type %x Family %x Model %x Stepping %x\n",
+ ((microcode[i].sig >> 12) & 0x3),
+ ((microcode[i].sig >> 8) & 0xf),
+ ((microcode[i].sig >> 4) & 0xf),
+ ((microcode[i].sig & 0xf)));
+ printf(" Checksum %x\n",microcode[i].cksum);
+ printf(" Loader Revision %x\n",microcode[i].ldrver);
+ printf(" Processor Flags %x\n\n",microcode[i].pf);
+
+ /* trick, to work even if there was no prior update by the BIOS */
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
- rdmsr(0x8B, val[0], rev);
+
+ /* get current (on-cpu) revision into rev (ignore val[0]) */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
if (microcode[i].rev < rev) {
printk(KERN_ERR
"microcode: CPU%d not 'upgrading' to earlier revision"
@@ -219,13 +255,20 @@ static void do_update_one(void *unused)
break;
}
- wrmsr(0x79, (unsigned int)(m->bits), 0);
+ /* write microcode via MSR 0x79 */
+ wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
+
+ /* serialize */
__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
- rdmsr(0x8B, val[0], val[1]);
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ /* notify the caller of success on this cpu */
req->err = 0;
req->slot = i;
- printk(KERN_ERR "microcode: CPU%d updated from revision "
+
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
"%d to %d, date=%08x\n",
cpu_num, rev, val[1], m->date);
}
@@ -239,18 +282,21 @@ static void do_update_one(void *unused)
static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
{
- if (*ppos >= mc_fsize)
- return 0;
+ ssize_t ret = 0;
+
down_read(&microcode_rwsem);
+ if (*ppos >= mc_fsize)
+ goto out;
if (*ppos + len > mc_fsize)
len = mc_fsize - *ppos;
- if (copy_to_user(buf, mc_applied + *ppos, len)) {
- up_read(&microcode_rwsem);
- return -EFAULT;
- }
+ ret = -EFAULT;
+ if (copy_to_user(buf, mc_applied + *ppos, len))
+ goto out;
*ppos += len;
+ ret = len;
+out:
up_read(&microcode_rwsem);
- return len;
+ return ret;
}
static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
@@ -267,8 +313,8 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l
mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
GFP_KERNEL);
if (!mc_applied) {
- printk(KERN_ERR "microcode: out of memory for saved microcode\n");
up_write(&microcode_rwsem);
+ printk(KERN_ERR "microcode: out of memory for saved microcode\n");
return -ENOMEM;
}
}
@@ -307,10 +353,12 @@ static int microcode_ioctl(struct inode *inode, struct file *file,
case MICROCODE_IOCFREE:
down_write(&microcode_rwsem);
if (mc_applied) {
+ int bytes = smp_num_cpus * sizeof(struct microcode);
+
devfs_set_file_size(devfs_handle, 0);
kfree(mc_applied);
mc_applied = NULL;
- printk(KERN_INFO "microcode: freed %d bytes\n", mc_fsize);
+ printk(KERN_INFO "microcode: freed %d bytes\n", bytes);
mc_fsize = 0;
up_write(&microcode_rwsem);
return 0;
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 47c83f58e..60764e3cd 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -480,12 +480,14 @@ static int have_wrcomb (void)
}
} /* End Function have_wrcomb */
+static u32 size_or_mask, size_and_mask;
+
static void intel_get_mtrr (unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- unsigned long dummy, mask_lo, base_lo;
+ unsigned long mask_lo, mask_hi, base_lo, base_hi;
- rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
+ rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);
if ( (mask_lo & 0x800) == 0 )
{
/* Invalid (i.e. free) range */
@@ -495,20 +497,17 @@ static void intel_get_mtrr (unsigned int reg, unsigned long *base,
return;
}
- rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy);
+ rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
- /* 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. */
+ /* Work out the shifted address mask. */
+ mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT)
+ | mask_lo >> PAGE_SHIFT;
- /* 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);
+ *size = -mask_lo;
+ *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+ *type = base_lo & 0xff;
} /* End Function intel_get_mtrr */
static void cyrix_get_arr (unsigned int reg, unsigned long *base,
@@ -533,13 +532,13 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base,
/* Enable interrupts if it was enabled previously */
__restore_flags (flags);
shift = ((unsigned char *) base)[1] & 0x0f;
- *base &= 0xfffff000UL;
+ *base >>= PAGE_SHIFT;
/* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
* Note: shift==0xf means 4G, this is unsupported.
*/
if (shift)
- *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+ *size = (reg < 7 ? 0x1UL : 0x40UL) << shift;
else
*size = 0;
@@ -576,7 +575,7 @@ static void amd_get_mtrr (unsigned int reg, unsigned long *base,
/* Upper dword is region 1, lower is region 0 */
if (reg == 1) low = high;
/* The base masks off on the right alignment */
- *base = low & 0xFFFE0000;
+ *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
*type = 0;
if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
if (low & 2) *type = MTRR_TYPE_WRCOMB;
@@ -601,7 +600,7 @@ static void amd_get_mtrr (unsigned int reg, unsigned long *base,
* *128K ...
*/
low = (~low) & 0x1FFFC;
- *size = (low + 4) << 15;
+ *size = (low + 4) << (15 - PAGE_SHIFT);
return;
} /* End Function amd_get_mtrr */
@@ -614,8 +613,8 @@ static struct
static void centaur_get_mcr (unsigned int reg, unsigned long *base,
unsigned long *size, mtrr_type *type)
{
- *base = centaur_mcr[reg].high & 0xfffff000;
- *size = (~(centaur_mcr[reg].low & 0xfffff000))+1;
+ *base = centaur_mcr[reg].high >> PAGE_SHIFT;
+ *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
*type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */
} /* End Function centaur_get_mcr */
@@ -645,8 +644,10 @@ static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
}
else
{
- wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
- wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+ wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,
+ (base & size_and_mask) >> (32 - PAGE_SHIFT));
+ wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,
+ (-size & size_and_mask) >> (32 - PAGE_SHIFT));
}
if (do_safe) set_mtrr_done (&ctxt);
} /* End Function intel_set_mtrr_up */
@@ -660,7 +661,9 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
/* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
- size >>= (reg < 7 ? 12 : 18);
+ if (reg >= 7)
+ size >>= 6;
+
size &= 0x7fff; /* make sure arr_size <= 14 */
for(arr_size = 0; size; arr_size++, size >>= 1);
@@ -685,6 +688,7 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
}
if (do_safe) set_mtrr_prepare (&ctxt);
+ base <<= PAGE_SHIFT;
setCx86(arr, ((unsigned char *) &base)[3]);
setCx86(arr+1, ((unsigned char *) &base)[2]);
setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
@@ -704,34 +708,36 @@ static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
[RETURNS] Nothing.
*/
{
- u32 low, high;
+ u32 regs[2];
struct set_mtrr_context ctxt;
if (do_safe) set_mtrr_prepare (&ctxt);
/*
* Low is MTRR0 , High MTRR 1
*/
- rdmsr (0xC0000085, low, high);
+ rdmsr (0xC0000085, regs[0], regs[1]);
/*
* Blank to disable
*/
if (size == 0)
- *(reg ? &high : &low) = 0;
+ regs[reg] = 0;
else
- /* Set the register to the base (already shifted for us), the
- type (off by one) and an inverted bitmask of the size
- The size is the only odd bit. We are fed say 512K
- We invert this and we get 111 1111 1111 1011 but
- if you subtract one and invert you get the desired
- 111 1111 1111 1100 mask
- */
- *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+ /* Set the register to the base, the type (off by one) and an
+ inverted bitmask of the size The size is the only odd
+ bit. We are fed say 512K We invert this and we get 111 1111
+ 1111 1011 but if you subtract one and invert you get the
+ desired 111 1111 1111 1100 mask
+
+ But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */
+ regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)
+ | (base<<PAGE_SHIFT) | (type+1);
+
/*
* The writeback rule is quite specific. See the manual. Its
* disable local interrupts, write back the cache, set the mtrr
*/
__asm__ __volatile__ ("wbinvd" : : : "memory");
- wrmsr (0xC0000085, low, high);
+ wrmsr (0xC0000085, regs[0], regs[1]);
if (do_safe) set_mtrr_done (&ctxt);
} /* End Function amd_set_mtrr_up */
@@ -751,9 +757,8 @@ static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
}
else
{
- high = base & 0xfffff000; /* base works on 4K pages... */
- low = ((~(size-1))&0xfffff000);
- low |= 0x1f; /* only support write-combining... */
+ high = base << PAGE_SHIFT;
+ low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
}
centaur_mcr[reg].high = high;
centaur_mcr[reg].low = low;
@@ -1058,7 +1063,7 @@ static int generic_get_free_region (unsigned long base, unsigned long size)
for (i = 0; i < max; ++i)
{
(*get_mtrr) (i, &lbase, &lsize, &ltype);
- if (lsize < 1) return i;
+ if (lsize == 0) return i;
}
return -ENOSPC;
} /* End Function generic_get_free_region */
@@ -1075,10 +1080,10 @@ 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 > 0x2000)
{
cyrix_get_arr (7, &lbase, &lsize, &ltype);
- if (lsize < 1) return 7;
+ if (lsize == 0) return 7;
/* Else try ARR0-ARR6 first */
}
else
@@ -1087,11 +1092,11 @@ static int cyrix_get_free_region (unsigned long base, unsigned long size)
{
cyrix_get_arr (i, &lbase, &lsize, &ltype);
if ((i == 3) && arr3_protected) continue;
- if (lsize < 1) return i;
+ if (lsize == 0) return i;
}
/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
cyrix_get_arr (i, &lbase, &lsize, &ltype);
- if ((lsize < 1) && (size >= 0x40000)) return i;
+ if ((lsize == 0) && (size >= 0x40)) return i;
}
return -ENOSPC;
} /* End Function cyrix_get_free_region */
@@ -1100,9 +1105,9 @@ static int (*get_free_region) (unsigned long base,
unsigned long size) = generic_get_free_region;
/**
- * mtrr_add - Add a memory type region
- * @base: Physical base address of region
- * @size: Physical size of region
+ * mtrr_add_page - Add a memory type region
+ * @base: Physical base address of region in pages (4 KB)
+ * @size: Physical size of region in pages (4 KB)
* @type: Type of MTRR desired
* @increment: If this is true do usage counting on the region
*
@@ -1135,11 +1140,11 @@ static int (*get_free_region) (unsigned long base,
* failures and do not wish system log messages to be sent.
*/
-int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment)
+int mtrr_add_page(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.
+ <base> The starting (base, in pages) address of the region.
+ <size> The size of the region. (in pages)
<type> The type of the new region.
<increment> If true and the region already exists, the usage count will be
incremented.
@@ -1164,7 +1169,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
o Power of 2 block
o base suitably aligned to the power
*/
- if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+ if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) ||
(size & ~(size-1))-size || ( base & (size-1) ) )
return -EINVAL;
break;
@@ -1176,9 +1181,9 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
boot_cpu_data.x86_model == 1 &&
boot_cpu_data.x86_mask <= 7 )
{
- if ( base & ((1 << 22)-1) )
+ if ( base & ((1 << (22-PAGE_SHIFT))-1) )
{
- printk (KERN_WARNING "mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+ printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base);
return -EINVAL;
}
}
@@ -1186,12 +1191,6 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
case MTRR_IF_CYRIX_ARR:
case MTRR_IF_CENTAUR_MCR:
- if ( (base & 0xfff) || (size & 0xfff) )
- {
- printk ("mtrr: size and base must be multiples of 4 kiB\n");
- printk ("mtrr: size: %lx base: %lx\n", size, base);
- return -EINVAL;
- }
if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
{
if (type != MTRR_TYPE_WRCOMB)
@@ -1200,9 +1199,9 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
return -EINVAL;
}
}
- else if (base + size < 0x100000)
+ else if (base + size < 0x100)
{
- printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+ printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
base, size);
return -EINVAL;
}
@@ -1213,7 +1212,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
lbase = lbase >> 1, last = last >> 1);
if (lbase != last)
{
- printk (KERN_WARNING "mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+ printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n",
base, size);
return -EINVAL;
}
@@ -1228,12 +1227,20 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
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 (KERN_WARNING "mtrr: your processor doesn't support write-combining\n");
return -ENOSYS;
}
+
+ if ( base & size_or_mask || size & size_or_mask )
+ {
+ printk ("mtrr: base or size exceeds the MTRR width\n");
+ return -EINVAL;
+ }
+
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
/* Search for existing MTRR */
@@ -1247,7 +1254,8 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
if ( (base < lbase) || (base + size > lbase + lsize) )
{
up(&main_lock);
- printk (KERN_WARNING "mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
+ printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing"
+ " 0x%lx000,0x%lx000\n",
base, size, lbase, lsize);
return -EINVAL;
}
@@ -1256,7 +1264,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
{
if (type == MTRR_TYPE_UNCACHABLE) continue;
up(&main_lock);
- printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
+ printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
base, size, attrib_to_str (ltype), attrib_to_str (type) );
return -EINVAL;
}
@@ -1278,10 +1286,67 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
compute_ascii ();
up(&main_lock);
return i;
+} /* End Function mtrr_add_page */
+
+/**
+ * mtrr_add - Add a memory type region
+ * @base: Physical base address of region
+ * @size: Physical size of region
+ * @type: Type of MTRR desired
+ * @increment: If this is true do usage counting on the region
+ *
+ * Memory type region registers control the caching on newer Intel and
+ * non Intel processors. This function allows drivers to request an
+ * MTRR is added. The details and hardware specifics of each processor's
+ * implementation are hidden from the caller, but nevertheless the
+ * caller should expect to need to provide a power of two size on an
+ * equivalent power of two boundary.
+ *
+ * If the region cannot be added either because all regions are in use
+ * or the CPU cannot support it a negative value is returned. On success
+ * the register number for this entry is returned, but should be treated
+ * as a cookie only.
+ *
+ * On a multiprocessor machine the changes are made to all processors.
+ * This is required on x86 by the Intel processors.
+ *
+ * The available types are
+ *
+ * %MTRR_TYPE_UNCACHEABLE - No caching
+ *
+ * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever
+ *
+ * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts
+ *
+ * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes
+ *
+ * BUGS: Needs a quiet flag for the cases where drivers do not mind
+ * failures and do not wish system log messages to be sent.
+ */
+
+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.
+*/
+
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);
} /* End Function mtrr_add */
/**
- * mtrr_del - delete a memory type region
+ * mtrr_del_page - delete a memory type region
* @reg: Register returned by mtrr_add
* @base: Physical base address
* @size: Size of region
@@ -1295,7 +1360,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
* code.
*/
-int mtrr_del (int reg, unsigned long base, unsigned long size)
+int mtrr_del_page (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.
@@ -1320,7 +1385,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
for (i = 0; i < max; ++i)
{
(*get_mtrr) (i, &lbase, &lsize, &ltype);
- if ( (lbase == base) && (lsize == size) )
+ if (lbase == base && lsize == size)
{
reg = i;
break;
@@ -1329,7 +1394,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
if (reg < 0)
{
up(&main_lock);
- printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
+ printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);
return -EINVAL;
}
}
@@ -1365,12 +1430,46 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
compute_ascii ();
up (&main_lock);
return reg;
-} /* End Function mtrr_del */
+} /* End Function mtrr_del_page */
+
+/**
+ * mtrr_del - delete a memory type region
+ * @reg: Register returned by mtrr_add
+ * @base: Physical base address
+ * @size: Size of region
+ *
+ * If register is supplied then base and size are ignored. This is
+ * how drivers should call it.
+ *
+ * Releases an MTRR region. If the usage count drops to zero the
+ * register is freed and the region returns to default state.
+ * On success the register is returned, on failure a negative error
+ * code.
+ */
+
+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.
+*/
+{
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
#ifdef USERSPACE_INTERFACE
static int mtrr_file_add (unsigned long base, unsigned long size,
- unsigned int type, char increment, struct file *file)
+ unsigned int type, char increment, struct file *file, int page)
{
int reg, max;
unsigned int *fcount = file->private_data;
@@ -1386,18 +1485,38 @@ static int mtrr_file_add (unsigned long base, unsigned long size,
memset (fcount, 0, max * sizeof *fcount);
file->private_data = fcount;
}
- reg = mtrr_add (base, size, type, 1);
+ if (!page) {
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ }
+ reg = mtrr_add_page (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)
+ struct file *file, int page)
{
int reg;
unsigned int *fcount = file->private_data;
- reg = mtrr_del (-1, base, size);
+ if (!page) {
+ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ return -EINVAL;
+ }
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ }
+ reg = mtrr_del_page (-1, base, size);
if (reg < 0) return reg;
if (fcount == NULL) return reg;
if (fcount[reg] < 1) return -EINVAL;
@@ -1418,12 +1537,13 @@ static ssize_t mtrr_read (struct file *file, char *buf, size_t len,
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:
+ "base=%Lx size=%Lx type=%s" OR:
"disable=%d"
*/
{
int i, err;
- unsigned long reg, base, size;
+ unsigned long reg;
+ unsigned long long base, size;
char *ptr;
char line[LINE_SIZE];
@@ -1438,7 +1558,7 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
if ( !strncmp (line, "disable=", 8) )
{
reg = simple_strtoul (line + 8, &ptr, 0);
- err = mtrr_del (reg, 0, 0);
+ err = mtrr_del_page (reg, 0, 0);
if (err < 0) return err;
return len;
}
@@ -1447,14 +1567,20 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
printk ("mtrr: no \"base=\" in line: \"%s\"\n", line);
return -EINVAL;
}
- base = simple_strtoul (line + 5, &ptr, 0);
+ base = simple_strtoull (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);
+ size = simple_strtoull (ptr + 5, &ptr, 0);
+ if ( (base & 0xfff) || (size & 0xfff) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base);
+ return -EINVAL;
+ }
for (; isspace (*ptr); ++ptr);
if ( strncmp (ptr, "type=", 5) )
{
@@ -1466,7 +1592,9 @@ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len,
for (i = 0; i < MTRR_NUM_TYPES; ++i)
{
if ( strcmp (ptr, mtrr_strings[i]) ) continue;
- err = mtrr_add (base, size, i, 1);
+ base >>= PAGE_SHIFT;
+ size >>= PAGE_SHIFT;
+ err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1);
if (err < 0) return err;
return len;
}
@@ -1490,7 +1618,7 @@ static int mtrr_ioctl (struct inode *inode, struct file *file,
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);
+ err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0);
if (err < 0) return err;
break;
case MTRRIOC_SET_ENTRY:
@@ -1504,7 +1632,7 @@ static int mtrr_ioctl (struct inode *inode, struct file *file,
if ( !suser () ) return -EPERM;
if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
return -EFAULT;
- err = mtrr_file_del (sentry.base, sentry.size, file);
+ err = mtrr_file_del (sentry.base, sentry.size, file, 0);
if (err < 0) return err;
break;
case MTRRIOC_KILL_ENTRY:
@@ -1519,7 +1647,54 @@ static int mtrr_ioctl (struct inode *inode, struct file *file,
return -EFAULT;
if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
+
+ /* Hide entries that go above 4GB */
+ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000)
+ gentry.base = gentry.size = gentry.type = 0;
+ else {
+ gentry.base <<= PAGE_SHIFT;
+ gentry.size <<= PAGE_SHIFT;
+ gentry.type = type;
+ }
+
+ if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
+ return -EFAULT;
+ break;
+ case MTRRIOC_ADD_PAGE_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, 1);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_SET_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_DEL_PAGE_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, 1);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_KILL_PAGE_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_del_page (-1, sentry.base, sentry.size);
+ if (err < 0) return err;
+ break;
+ case MTRRIOC_GET_PAGE_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;
@@ -1578,24 +1753,24 @@ static void compute_ascii (void)
for (i = 0; i < max; i++)
{
(*get_mtrr) (i, &base, &size, &type);
- if (size < 1) usage_table[i] = 0;
+ if (size == 0) usage_table[i] = 0;
else
{
- if (size < 0x100000)
+ if (size < (0x100000 >> PAGE_SHIFT))
{
- /* 1MB */
- factor = 'k';
- size >>= 10;
+ /* less than 1MB */
+ factor = 'K';
+ size <<= PAGE_SHIFT - 10;
}
else
{
factor = 'M';
- size >>= 20;
+ size >>= 20 - PAGE_SHIFT;
}
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,
+ "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
+ i, base, base >> (20 - PAGE_SHIFT), size, factor,
attrib_to_str (type), usage_table[i]);
ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
}
@@ -1762,11 +1937,38 @@ static int __init mtrr_setup(void)
mtrr_if = MTRR_IF_INTEL;
get_mtrr = intel_get_mtrr;
set_mtrr_up = intel_set_mtrr_up;
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ /* The original Athlon docs said that
+ total addressable memory is 44 bits wide.
+ It was not really clear whether its MTRRs
+ follow this or not. (Read: 44 or 36 bits).
+ However, "x86-64_overview.pdf" explicitly
+ states that "previous implementations support
+ 36 bit MTRRs" and also provides a way to
+ query the width (in bits) of the physical
+ addressable memory on the Hammer family.
+ */
+ if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
+ u32 phys_addr;
+ phys_addr = cpuid_eax(0x80000008) & 0xff ;
+ size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
+ size_and_mask = ~size_or_mask & 0xfff00000;
+ break;
+ }
+ default:
+ /* Intel, etc. */
+ size_or_mask = 0xff000000; /* 36 bits */
+ size_and_mask = 0x00f00000;
+ break;
+ }
} else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
/* Pre-Athlon (K6) AMD CPU MTRRs */
mtrr_if = MTRR_IF_AMD_K6;
get_mtrr = amd_get_mtrr;
set_mtrr_up = amd_set_mtrr_up;
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
/* Cyrix ARRs */
mtrr_if = MTRR_IF_CYRIX_ARR;
@@ -1774,12 +1976,16 @@ static int __init mtrr_setup(void)
set_mtrr_up = cyrix_set_arr_up;
get_free_region = cyrix_get_free_region;
cyrix_arr_init();
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
/* Centaur MCRs */
mtrr_if = MTRR_IF_CENTAUR_MCR;
get_mtrr = centaur_get_mcr;
set_mtrr_up = centaur_set_mcr_up;
centaur_mcr_init();
+ size_or_mask = 0xfff00000; /* 32 bits */
+ size_and_mask = 0;
} else {
/* No supported MTRR interface */
mtrr_if = MTRR_IF_NONE;
diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
index 17a929bb2..cdf4fc827 100644
--- a/arch/i386/kernel/pci-irq.c
+++ b/arch/i386/kernel/pci-irq.c
@@ -176,7 +176,6 @@ static void pirq_ali_ide_interrupt(struct pci_dev *router, unsigned reg, unsigne
pci_read_config_byte(router, reg, &x);
x = (x & 0xe0) | val; /* clear the level->edge transform */
pci_write_config_byte(router, reg, x);
- eisa_set_level_irq(irq);
}
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -196,7 +195,6 @@ static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i
pirq_ali_ide_interrupt(router, 0x75, val, irq);
break;
}
- eisa_set_level_irq(irq);
return 1;
}
return 0;
@@ -279,6 +277,54 @@ static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
return 1;
}
+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ u8 x;
+ int reg = 0x41 + (pirq - 'A') ;
+
+ pci_read_config_byte(router, reg, &x);
+ return (x & 0x80) ? 0 : (x & 0x0f);
+}
+
+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ u8 x;
+ int reg = 0x41 + (pirq - 'A') ;
+
+ pci_read_config_byte(router, reg, &x);
+ x = (pirq & 0x20) ? 0 : (irq & 0x0f);
+ pci_write_config_byte(router, reg, x);
+
+ return 1;
+}
+
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ * config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ * Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ * devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ * for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ if (pirq > 8) {
+ printk("VLSI router pirq escape (%d)\n", pirq);
+ return 0;
+ }
+ return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ if (pirq > 8) {
+ printk("VLSI router pirq escape (%d)\n", pirq);
+ return 0;
+ }
+ write_config_nybble(router, 0x74, pirq-1, irq);
+ return 1;
+}
+
#ifdef CONFIG_PCI_BIOS
static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -309,7 +355,8 @@ static struct irq_router pirq_routers[] = {
{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
{ "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-
+ { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+ { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
{ "default", 0, 0, NULL, NULL }
};
@@ -355,7 +402,7 @@ static void __init pirq_find_router(void)
pirq_router_dev->slot_name);
}
-static struct irq_info *pirq_get_info(struct pci_dev *dev, int pin)
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
{
struct irq_routing_table *rt = pirq_table;
int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
@@ -373,25 +420,28 @@ static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs
static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
+ u8 pin;
struct irq_info *info;
- int i, pirq, pin, newirq;
+ int i, pirq, newirq;
int irq = 0;
u32 mask;
struct irq_router *r = pirq_router;
- struct pci_dev *dev2, *d;
+ struct pci_dev *dev2;
char *msg = NULL;
if (!pirq_table)
return 0;
/* Find IRQ routing entry */
- pin = pci_get_interrupt_pin(dev, &d);
- if (pin < 0) {
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (!pin) {
DBG(" -> no interrupt pin\n");
return 0;
}
- DBG("IRQ for %s(%d) via %s", dev->slot_name, pin, d->slot_name);
- info = pirq_get_info(d, pin);
+ pin = pin - 1;
+
+ DBG("IRQ for %s:%d", dev->slot_name, pin);
+ info = pirq_get_info(dev);
if (!info) {
DBG(" -> not found in routing table\n");
return 0;
@@ -405,9 +455,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask;
- /* Find the best IRQ to assign */
- newirq = 0;
- if (assign) {
+ /*
+ * Find the best IRQ to assign: use the one
+ * reported by the device if possible.
+ */
+ newirq = dev->irq;
+ if (!newirq && assign) {
for (i = 0; i < 16; i++) {
if (!(mask & (1 << i)))
continue;
@@ -417,16 +470,22 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
newirq = i;
}
}
- DBG(" -> newirq=%d", newirq);
}
+ DBG(" -> newirq=%d", newirq);
/* Try to get current IRQ */
- if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) {
+ if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
+ /* We refuse to override the dev->irq information. Give a warning! */
+ if (dev->irq && dev->irq != irq) {
+ printk("IRQ routing conflict in pirq table! Try 'pci=autoirq'\n");
+ return 0;
+ }
} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
DBG(" -> assigning IRQ %d", newirq);
- if (r->set(pirq_router_dev, d, pirq, newirq)) {
+ if (r->set(pirq_router_dev, dev, pirq, newirq)) {
+ eisa_set_level_irq(newirq);
DBG(" ... OK\n");
msg = "Assigned";
irq = newirq;
@@ -445,9 +504,14 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
/* Update IRQ for all devices with the same pirq value */
pci_for_each_dev(dev2) {
- if ((pin = pci_get_interrupt_pin(dev2, &d)) >= 0 &&
- (info = pirq_get_info(d, pin)) &&
- info->irq[pin].link == pirq) {
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+ if (!pin)
+ continue;
+ pin--;
+ info = pirq_get_info(dev2);
+ if (!info)
+ continue;
+ if (info->irq[pin].link == pirq) {
dev2->irq = irq;
pirq_penalty[irq]++;
if (dev != dev2)
@@ -556,19 +620,17 @@ void pcibios_penalize_isa_irq(int irq)
void pcibios_enable_irq(struct pci_dev *dev)
{
- if (!dev->irq) {
- u8 pin;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1)) {
- char *msg;
- if (io_apic_assign_pci_irqs)
- msg = " Probably buggy MP table.";
- else if (pci_probe & PCI_BIOS_IRQ_SCAN)
- msg = "";
- else
- msg = " Please try using pci=biosirq.";
- printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
- 'A' + pin - 1, dev->slot_name, msg);
- }
+ u8 pin;
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+ char *msg;
+ if (io_apic_assign_pci_irqs)
+ msg = " Probably buggy MP table.";
+ else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+ msg = "";
+ else
+ msg = " Please try using pci=biosirq.";
+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+ 'A' + pin - 1, dev->slot_name, msg);
}
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 6d3cf4d9a..8e7176c32 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -496,9 +496,9 @@ void release_thread(struct task_struct *dead_task)
void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
{
struct mm_struct * old_mm = current->mm;
- void * old_ldt = old_mm->segments, * ldt = old_ldt;
+ void * old_ldt = old_mm->segments, * ldt;
- if (!old_mm->segments) {
+ if (!old_ldt) {
/*
* default LDT - use the one from init_task
*/
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 692965a06..fffe11398 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -126,7 +126,7 @@ unsigned int mca_pentium_flag;
*/
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info;
-struct apm_bios_info apm_bios_info;
+struct apm_info apm_info;
struct sys_desc_table_struct {
unsigned short length;
unsigned char table[0];
@@ -608,7 +608,7 @@ void __init setup_arch(char **cmdline_p)
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
- apm_bios_info = APM_BIOS_INFO;
+ apm_info.bios = APM_BIOS_INFO;
if( SYS_DESC_TABLE.length != 0 ) {
MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
machine_id = SYS_DESC_TABLE.table[0];
@@ -1531,8 +1531,32 @@ static void __init init_intel(struct cpuinfo_x86 *c)
dh = des >> 4;
dl = des & 0x0F;
+ /* Black magic... */
+
switch ( dh )
{
+ case 0:
+ switch ( dl ) {
+ case 6:
+ /* L1 I cache */
+ l1i += 8;
+ break;
+ case 8:
+ /* L1 I cache */
+ l1i += 16;
+ break;
+ case 10:
+ /* L1 D cache */
+ l1d += 8;
+ break;
+ case 12:
+ /* L1 D cache */
+ l1d += 16;
+ break;
+ default:
+ /* TLB, or unknown */
+ }
+ break;
case 2:
if ( dl ) {
/* L3 cache */
@@ -1541,6 +1565,16 @@ static void __init init_intel(struct cpuinfo_x86 *c)
}
break;
case 4:
+ if ( c->x86 > 6 && dl ) {
+ /* P4 family */
+ if ( dl ) {
+ /* L3 cache */
+ cs = 128 << (dl-1);
+ l3 += cs;
+ break;
+ }
+ }
+ /* else same as 8 - fall through */
case 8:
if ( dl ) {
/* L2 cache */
@@ -1556,9 +1590,16 @@ static void __init init_intel(struct cpuinfo_x86 *c)
}
break;
case 7:
- /* L1 I cache */
- cs = dl ? (16 << (dl-1)) : 12;
- l1i += cs;
+ if ( dl >= 8 )
+ {
+ /* L2 cache */
+ cs = 64<<(dl-8);
+ l2 += cs;
+ } else {
+ /* L0 I cache, count as L1 */
+ cs = dl ? (16 << (dl-1)) : 12;
+ l1i += cs;
+ }
break;
default:
/* TLB, or something else we don't know about */
@@ -2066,8 +2107,8 @@ int get_cpuinfo(char * buffer)
/* Intel-defined */
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflsh", NULL, "dtes", "acpi", "mmx",
- "fxsr", "sse", "sse2", "selfsnoop", NULL, "acc", "ia64", NULL,
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL,
/* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -2113,7 +2154,7 @@ int get_cpuinfo(char * buffer)
p += sprintf(p, "stepping\t: unknown\n");
if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
- p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
+ p += sprintf(p, "cpu MHz\t\t: %lu.%03lu\n",
cpu_khz / 1000, (cpu_khz % 1000));
}
@@ -2131,7 +2172,7 @@ int get_cpuinfo(char * buffer)
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
"wp\t\t: %s\n"
- "features\t:",
+ "flags\t\t:",
c->fdiv_bug ? "yes" : "no",
c->hlt_works_ok ? "no" : "yes",
c->f00f_bug ? "yes" : "no",
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 57a07765e..858e7dda0 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -886,8 +886,10 @@ void __init smp_boot_cpus(void)
/*
* If we couldn't find a local APIC, then get out of here now!
*/
- if (!verify_local_APIC()) {
- printk(KERN_ERR "BIOS bug, local APIC at 0x%lX not detected!...\n", mp_lapic_addr);
+ if (APIC_INTEGRATED(apic_version[boot_cpu_id]) &&
+ !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) {
+ printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+ boot_cpu_id);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
#ifndef CONFIG_VISWS
io_apic_irqs = 0;
@@ -897,6 +899,8 @@ void __init smp_boot_cpus(void)
goto smp_done;
}
+ verify_local_APIC();
+
/*
* If SMP should be disabled, then really disable it!
*/
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index b84421374..f2077f2f2 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -62,20 +62,8 @@ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
*/
struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
-extern int console_loglevel;
extern void bust_spinlocks(void);
-static inline void console_silent(void)
-{
- console_loglevel = 0;
-}
-
-static inline void console_verbose(void)
-{
- if (console_loglevel)
- console_loglevel = 15;
-}
-
asmlinkage void divide_error(void);
asmlinkage void debug(void);
asmlinkage void nmi(void);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 39a6ce0f8..b2e5a1bfc 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -198,7 +198,7 @@ void __init kmap_init(void)
void show_mem(void)
{
- int i,free = 0, total = 0, reserved = 0;
+ int i, total = 0, reserved = 0;
int shared = 0, cached = 0;
int highmem = 0;
@@ -214,9 +214,7 @@ void show_mem(void)
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
- else if (!page_count(mem_map+i))
- free++;
- else
+ else if (page_count(mem_map+i))
shared += page_count(mem_map+i) - 1;
}
printk("%d pages of RAM\n", total);
@@ -437,7 +435,7 @@ void __init zap_low_mappings (void)
}
/*
- * paging_init() sets up the page tables - note that the first 4MB are
+ * paging_init() sets up the page tables - note that the first 8MB are
* already mapped by head.S.
*
* This routines also unmaps the page at virtual kernel address 0, so