Commit 7c382efa authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] Essential x86-64 updates

The most important part is that it makes x86-64 compile again.
Without that 2.6 users won't be very happy.

It also works around a bug that allowed every user program to reboot the
system on B stepping K8.

Also update to match some recent i386 fixes.

Full ChangeLog:
 - Add acpi_pic_set_level_irq to make ACPI compile again
 - Work around compat mode K8 bug in IRET exception handling
 - Increase exception stack. The old 1k stack was too easy
   to overflow (from Jim Paradis, changed by me)
 - Replace safe_smp_processor_id with cpuid (needed for above)
 - When there is only one node always enable fake_node mode
 - Merge with i386 (NTP gettimeofday monoticity fix, irq nr_vectors change)
 - Fix compile problem for UP kernels in time/cpufreq
 - Set all nodes online at bootup
 - Define node_to_cpumask correctly
parent 69c1d1bf
......@@ -251,6 +251,33 @@ acpi_parse_hpet (
}
#endif
#ifdef CONFIG_ACPI_BUS
/*
* Set specified PIC IRQ to level triggered mode.
*
* Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
* for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
* ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0)
* ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
*
* As the BIOS should have done this for us,
* print a warning if the IRQ wasn't already set to level.
*/
void acpi_pic_set_level_irq(unsigned int irq)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3);
unsigned char val = inb(port);
if (!(val & mask)) {
printk(KERN_WARNING PREFIX "IRQ %d was Edge Triggered, "
"setting to Level Triggerd\n", irq);
outb(val | mask, port);
}
}
#endif /* CONFIG_ACPI_BUS */
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
......
......@@ -566,8 +566,14 @@ error_kernelspace:
incl %ebx
/* There are two places in the kernel that can potentially fault with
usergs. Handle them here. The exception handlers after
iret run with kernel gs again, so don't set the user space flag. */
cmpq $iret_label,RIP(%rsp)
iret run with kernel gs again, so don't set the user space flag.
B stepping K8s sometimes report an truncated RIP for IRET
exceptions returning to compat mode. Check for these here too. */
leaq iret_label(%rip),%rbp
cmpq %rbp,RIP(%rsp)
je error_swapgs
movl %ebp,%ebp /* zero extend */
cmpq %rbp,RIP(%rsp)
je error_swapgs
cmpq $gs_change,RIP(%rsp)
je error_swapgs
......
......@@ -622,11 +622,13 @@ static inline int IO_APIC_irq_trigger(int irq)
return 0;
}
int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
static int __init assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
BUG_ON(irq >= NR_IRQ_VECTORS);
if (IO_APIC_VECTOR(irq) > 0)
return IO_APIC_VECTOR(irq);
next:
......
......@@ -189,8 +189,7 @@ void pda_init(int cpu)
pda->irqstackptr += IRQSTACKSIZE-64;
}
#define EXCEPTION_STK_ORDER 0 /* >= N_EXCEPTION_STACKS*EXCEPTION_STKSZ */
char boot_exception_stacks[N_EXCEPTION_STACKS*EXCEPTION_STKSZ];
char boot_exception_stacks[N_EXCEPTION_STACKS * EXCEPTION_STKSZ];
void syscall_init(void)
{
......@@ -226,15 +225,12 @@ void __init cpu_init (void)
#endif
struct tss_struct * t = &init_tss[cpu];
unsigned long v, efer;
char *estacks;
char *estacks = NULL;
struct task_struct *me;
/* CPU 0 is initialised in head64.c */
if (cpu != 0) {
pda_init(cpu);
estacks = (char *)__get_free_pages(GFP_ATOMIC, 0);
if (!estacks)
panic("Can't allocate exception stacks for CPU %d\n",cpu);
} else
estacks = boot_exception_stacks;
......@@ -282,10 +278,15 @@ void __init cpu_init (void)
/*
* set up and load the per-CPU TSS
*/
estacks += EXCEPTION_STKSZ;
for (v = 0; v < N_EXCEPTION_STACKS; v++) {
t->ist[v] = (unsigned long)estacks;
if (cpu) {
estacks = (char *)__get_free_pages(GFP_ATOMIC, 0);
if (!estacks)
panic("Cannot allocate exception stack %ld %d\n",
v, cpu);
}
estacks += EXCEPTION_STKSZ;
t->ist[v] = (unsigned long)estacks;
}
t->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
......
......@@ -487,25 +487,3 @@ asmlinkage void smp_call_function_interrupt(void)
atomic_inc(&call_data->finished);
}
}
/* Slow. Should be only used for debugging. */
int slow_smp_processor_id(void)
{
int stack_location;
unsigned long sp = (unsigned long)&stack_location;
int offset = 0, cpu;
for (offset = 0; next_cpu(offset, cpu_online_map) < NR_CPUS; offset = cpu + 1) {
cpu = next_cpu(offset, cpu_online_map);
if (sp >= (u64)cpu_pda[cpu].irqstackptr - IRQSTACKSIZE &&
sp <= (u64)cpu_pda[cpu].irqstackptr)
return cpu;
unsigned long estack = init_tss[cpu].ist[0] - EXCEPTION_STKSZ;
if (sp >= estack && sp <= estack+(1<<(PAGE_SHIFT+EXCEPTION_STK_ORDER)))
return cpu;
}
return stack_smp_processor_id();
}
......@@ -111,6 +111,14 @@ void do_gettimeofday(struct timeval *tv)
sec = xtime.tv_sec;
usec = xtime.tv_nsec / 1000;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
if (unlikely(time_adjust < 0) && usec > tickadj)
usec = tickadj;
t = (jiffies - wall_jiffies) * (1000000L / HZ) +
do_gettimeoffset();
usec += t;
......@@ -477,22 +485,28 @@ unsigned long get_cmos_time(void)
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
//static unsigned long fast_gettimeoffset_ref = 0;
static unsigned long cpu_khz_ref = 0;
static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
unsigned long *lpj;
#ifdef CONFIG_SMP
lpj = &cpu_data[freq->cpu].loops_per_jiffy;
#else
lpj = &boot_cpu_data.loops_per_jiffy;
#endif
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
loops_per_jiffy_ref = *lpj;
cpu_khz_ref = cpu_khz;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data[freq->cpu].loops_per_jiffy =
*lpj =
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
......
......@@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(unset_nmi_callback);
extern void * memset(void *,int,__kernel_size_t);
extern size_t strlen(const char *);
extern char * bcopy(const char * src, char * dest, int count);
extern void bcopy(const char * src, char * dest, int count);
extern void * memmove(void * dest,const void *src,size_t count);
extern char * strcpy(char * dest,const char *src);
extern int strcmp(const char * cs,const char * ct);
......
......@@ -14,6 +14,10 @@ search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
/* Work around a B stepping K8 bug */
if ((value >> 32) == 0)
value |= 0xffffffffUL << 32;
while (first <= last) {
const struct exception_table_entry *mid;
long diff;
......
......@@ -164,5 +164,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
rr++;
}
if (found == 1)
fake_node = 1;
return 0;
}
......@@ -104,6 +104,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
if (nodeid + 1 > numnodes)
numnodes = nodeid + 1;
nodes_present |= (1UL << nodeid);
node_set_online(nodeid);
}
/* Initialize final allocator for a zone */
......
......@@ -76,8 +76,8 @@ struct hw_interrupt_type;
#ifndef __ASSEMBLY__
extern int irq_vector[NR_IRQS];
#define IO_APIC_VECTOR(irq) irq_vector[irq]
extern u8 irq_vector[NR_IRQ_VECTORS];
#define IO_APIC_VECTOR(irq) ((int)irq_vector[irq])
/*
* Various low-level irq details needed by irq.c, process.c,
......
......@@ -22,6 +22,7 @@
* the usable vector space is 0x20-0xff (224 vectors)
*/
#define NR_IRQS 224
#define NR_IRQ_VECTORS NR_IRQS
static __inline__ int irq_canonicalize(int irq)
{
......
......@@ -24,6 +24,8 @@ extern unsigned long pci_mem_start;
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM (pci_mem_start)
#define PCIBIOS_MIN_CARDBUS_IO 0x4000
void pcibios_config_init(void);
struct pci_bus * pcibios_scan_root(int bus);
extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
......
......@@ -263,8 +263,8 @@ struct thread_struct {
#define DOUBLEFAULT_STACK 2
#define NMI_STACK 3
#define N_EXCEPTION_STACKS 3 /* hw limit: 7 */
#define EXCEPTION_STKSZ 1024
#define EXCEPTION_STK_ORDER 0
#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
#define EXCEPTION_STACK_ORDER 0
#define start_thread(regs,new_rip,new_rsp) do { \
asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0)); \
......
......@@ -74,15 +74,7 @@ extern __inline int hard_smp_processor_id(void)
return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
}
extern int slow_smp_processor_id(void);
extern inline int safe_smp_processor_id(void)
{
if (disable_apic)
return slow_smp_processor_id();
else
return hard_smp_processor_id();
}
#define safe_smp_processor_id() (cpuid_ebx(1) >> 24)
#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
#endif /* !ASSEMBLY */
......
......@@ -10,13 +10,15 @@
/* Map the K8 CPU local memory controllers to a simple 1:1 CPU:NODE topology */
extern int fake_node;
/* This is actually a cpumask_t, but doesn't matter because we don't have
>BITS_PER_LONG CPUs */
extern unsigned long cpu_online_map;
#define cpu_to_node(cpu) (fake_node ? 0 : (cpu))
#define memblk_to_node(memblk) (fake_node ? 0 : (memblk))
#define parent_node(node) (node)
#define node_to_first_cpu(node) (fake_node ? 0 : (node))
#define node_to_cpu_mask(node) (fake_node ? cpu_online_map : (1UL << (node)))
#define node_to_cpumask(node) (fake_node ? cpu_online_map : (1UL << (node)))
#define node_to_memblk(node) (node)
static inline unsigned long pcibus_to_cpumask(int bus)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment