diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/boot/setup.S | 12 | ||||
-rw-r--r-- | arch/i386/config.in | 2 | ||||
-rw-r--r-- | arch/i386/defconfig | 53 | ||||
-rw-r--r-- | arch/i386/kernel/apic.c | 118 | ||||
-rw-r--r-- | arch/i386/kernel/apm.c | 188 | ||||
-rw-r--r-- | arch/i386/kernel/dmi_scan.c | 182 | ||||
-rw-r--r-- | arch/i386/kernel/head.S | 2 | ||||
-rw-r--r-- | arch/i386/kernel/i386_ksyms.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/microcode.c | 122 | ||||
-rw-r--r-- | arch/i386/kernel/mtrr.c | 378 | ||||
-rw-r--r-- | arch/i386/kernel/pci-irq.c | 128 | ||||
-rw-r--r-- | arch/i386/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/i386/kernel/setup.c | 59 | ||||
-rw-r--r-- | arch/i386/kernel/smpboot.c | 8 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 12 | ||||
-rw-r--r-- | arch/i386/mm/init.c | 8 |
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(¤t->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(µcode_dev) < 0) { + error = misc_register(µcode_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, µcode_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(µcode_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(µcode_rwsem); - return -EFAULT; - } + ret = -EFAULT; + if (copy_to_user(buf, mc_applied + *ppos, len)) + goto out; *ppos += len; + ret = len; +out: up_read(µcode_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(µcode_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(µcode_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(µcode_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, <ype); - 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, <ype); - 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, <ype); 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, <ype); - 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, <ype); - 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 |