aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c3
-rw-r--r--arch/x86_64/kernel/kprobes.c2
-rw-r--r--arch/x86_64/kernel/process.c7
-rw-r--r--arch/x86_64/kernel/setup.c6
-rw-r--r--arch/x86_64/kernel/smpboot.c2
-rw-r--r--arch/x86_64/kernel/time.c6
-rw-r--r--arch/x86_64/mm/init.c2
-rw-r--r--arch/x86_64/mm/ioremap.c37
-rw-r--r--arch/x86_64/mm/numa.c4
-rw-r--r--arch/x86_64/pci/Makefile2
-rw-r--r--arch/x86_64/pci/mmconfig.c65
11 files changed, 102 insertions, 34 deletions
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 830feb272ec..2b760d0d9ce 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -217,8 +217,7 @@ elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpr
if (!tsk_used_math(tsk))
return 0;
if (!regs)
- regs = (struct pt_regs *)tsk->thread.rsp0;
- --regs;
+ regs = ((struct pt_regs *)tsk->thread.rsp0) - 1;
if (tsk == current)
unlazy_fpu(tsk);
set_fs(KERNEL_DS);
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index dddeb678b44..afe11f4fbd1 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -329,7 +329,7 @@ int __kprobes kprobe_handler(struct pt_regs *regs)
*/
save_previous_kprobe(kcb);
set_current_kprobe(p, regs, kcb);
- p->nmissed++;
+ kprobes_inc_nmissed_count(p);
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_REENTER;
return 1;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 5afd63e8cef..7519fc520eb 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -351,13 +351,6 @@ void flush_thread(void)
struct task_struct *tsk = current;
struct thread_info *t = current_thread_info();
- /*
- * Remove function-return probe instances associated with this task
- * and put them back on the free list. Do not insert an exit probe for
- * this function, it will be disabled by kprobe_flush_task if you do.
- */
- kprobe_flush_task(tsk);
-
if (t->flags & _TIF_ABI_PENDING)
t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 750e01dcbdf..64c4534b930 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -42,6 +42,7 @@
#include <linux/edd.h>
#include <linux/mmzone.h>
#include <linux/kexec.h>
+#include <linux/cpufreq.h>
#include <asm/mtrr.h>
#include <asm/uaccess.h>
@@ -1256,8 +1257,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "stepping\t: unknown\n");
if (cpu_has(c,X86_FEATURE_TSC)) {
+ unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data));
+ if (!freq)
+ freq = cpu_khz;
seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
- cpu_khz / 1000, (cpu_khz % 1000));
+ freq / 1000, (freq % 1000));
}
/* Cache size */
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 683c33f7b96..ecbd7b83acc 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -1181,7 +1181,7 @@ int __cpu_disable(void)
if (cpu == 0)
return -EBUSY;
- disable_APIC_timer();
+ clear_local_APIC();
/*
* HACK:
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index fdaddc4e528..74102796e5c 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -59,7 +59,7 @@ static int notsc __initdata = 0;
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
static unsigned long hpet_period; /* fsecs / HPET clock */
unsigned long hpet_tick; /* HPET clocks / interrupt */
-static int hpet_use_timer;
+static int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */
unsigned long vxtime_hz = PIT_TICK_RATE;
int report_lost_ticks; /* command line option */
unsigned long long monotonic_base;
@@ -908,12 +908,14 @@ void __init time_init(void)
if (!hpet_init())
vxtime_hz = (1000000000000000L + hpet_period / 2) /
hpet_period;
+ else
+ vxtime.hpet_address = 0;
if (hpet_use_timer) {
cpu_khz = hpet_calibrate_tsc();
timename = "HPET";
#ifdef CONFIG_X86_PM_TIMER
- } else if (pmtmr_ioport) {
+ } else if (pmtmr_ioport && !vxtime.hpet_address) {
vxtime_hz = PM_TIMER_FREQUENCY;
timename = "PM";
pit_init();
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 286f6a624c3..c016dfe8478 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -348,7 +348,7 @@ size_zones(unsigned long *z, unsigned long *h,
}
/* Compute holes */
- w = 0;
+ w = start_pfn;
for (i = 0; i < MAX_NR_ZONES; i++) {
unsigned long s = w;
w += z[i];
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index ecf7acb5db9..ae207064201 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -247,9 +247,15 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
return __ioremap(phys_addr, size, _PAGE_PCD);
}
+/**
+ * iounmap - Free a IO remapping
+ * @addr: virtual address from ioremap_*
+ *
+ * Caller must ensure there is only one unmapping for the same pointer.
+ */
void iounmap(volatile void __iomem *addr)
{
- struct vm_struct *p;
+ struct vm_struct *p, *o;
if (addr <= high_memory)
return;
@@ -257,12 +263,31 @@ void iounmap(volatile void __iomem *addr)
addr < phys_to_virt(ISA_END_ADDRESS))
return;
- write_lock(&vmlist_lock);
- p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK));
- if (!p)
+ addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr);
+ /* Use the vm area unlocked, assuming the caller
+ ensures there isn't another iounmap for the same address
+ in parallel. Reuse of the virtual address is prevented by
+ leaving it in the global lists until we're done with it.
+ cpa takes care of the direct mappings. */
+ read_lock(&vmlist_lock);
+ for (p = vmlist; p; p = p->next) {
+ if (p->addr == addr)
+ break;
+ }
+ read_unlock(&vmlist_lock);
+
+ if (!p) {
printk("iounmap: bad address %p\n", addr);
- else if (p->flags >> 20)
+ dump_stack();
+ return;
+ }
+
+ /* Reset the direct mapping. Can block */
+ if (p->flags >> 20)
ioremap_change_attr(p->phys_addr, p->size, 0);
- write_unlock(&vmlist_lock);
+
+ /* Finally remove it */
+ o = remove_vm_area((void *)addr);
+ BUG_ON(p != o || o == NULL);
kfree(p);
}
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index a828a01739c..15b67d2760c 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -53,6 +53,8 @@ static int __init populate_memnodemap(
int res = -1;
unsigned long addr, end;
+ if (shift >= 64)
+ return -1;
memset(memnodemap, 0xff, sizeof(memnodemap));
for (i = 0; i < numnodes; i++) {
addr = nodes[i].start;
@@ -65,7 +67,7 @@ static int __init populate_memnodemap(
if (memnodemap[addr >> shift] != 0xff)
return -1;
memnodemap[addr >> shift] = i;
- addr += (1 << shift);
+ addr += (1UL << shift);
} while (addr < end);
res = 1;
}
diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
index bb34e5ef916..a8f75a2a0f6 100644
--- a/arch/x86_64/pci/Makefile
+++ b/arch/x86_64/pci/Makefile
@@ -11,7 +11,7 @@ obj-y += fixup.o
obj-$(CONFIG_ACPI) += acpi.o
obj-y += legacy.o irq.o common.o
# mmconfig has a 64bit special
-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o
obj-$(CONFIG_NUMA) += k8-bus.o
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index a0838c4a94e..f16c0d57c55 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -8,18 +8,21 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/bitmap.h>
#include "pci.h"
#define MMCONFIG_APER_SIZE (256*1024*1024)
+static DECLARE_BITMAP(fallback_slots, 32);
+
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
struct acpi_table_mcfg_config *cfg;
- char *virt;
+ char __iomem *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
-static char *get_virt(unsigned int seg, int bus)
+static char __iomem *get_virt(unsigned int seg, unsigned bus)
{
int cfg_num = -1;
struct acpi_table_mcfg_config *cfg;
@@ -27,10 +30,9 @@ static char *get_virt(unsigned int seg, int bus)
while (1) {
++cfg_num;
if (cfg_num >= pci_mmcfg_config_num) {
- /* something bad is going on, no cfg table is found. */
- /* so we fall back to the old way we used to do this */
- /* and just rely on the first entry to be correct. */
- return pci_mmcfg_virt[0].virt;
+ /* Not found - fall back to type 1. This happens
+ e.g. on the internal devices of a K8 northbridge. */
+ return NULL;
}
cfg = pci_mmcfg_virt[cfg_num].cfg;
if (cfg->pci_segment_group_number != seg)
@@ -41,20 +43,30 @@ static char *get_virt(unsigned int seg, int bus)
}
}
-static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
-
- return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
+ char __iomem *addr;
+ if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
+ return NULL;
+ addr = get_virt(seg, bus);
+ if (!addr)
+ return NULL;
+ return addr + ((bus << 20) | (devfn << 12));
}
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
- char *addr = pci_dev_base(seg, bus, devfn);
+ char __iomem *addr;
+ /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
+ addr = pci_dev_base(seg, bus, devfn);
+ if (!addr)
+ return pci_conf1_read(seg,bus,devfn,reg,len,value);
+
switch (len) {
case 1:
*value = readb(addr + reg);
@@ -73,11 +85,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
- char *addr = pci_dev_base(seg, bus, devfn);
+ char __iomem *addr;
+ /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
+ addr = pci_dev_base(seg, bus, devfn);
+ if (!addr)
+ return pci_conf1_write(seg,bus,devfn,reg,len,value);
+
switch (len) {
case 1:
writeb(value, addr + reg);
@@ -98,6 +115,30 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write,
};
+/* K8 systems have some devices (typically in the builtin northbridge)
+ that are only accessible using type1
+ Normally this can be expressed in the MCFG by not listing them
+ and assigning suitable _SEGs, but this isn't implemented in some BIOS.
+ Instead try to discover all devices on bus 0 that are unreachable using MM
+ and fallback for them.
+ We only do this for bus 0/seg 0 */
+static __init void unreachable_devices(void)
+{
+ int i;
+ for (i = 0; i < 32; i++) {
+ u32 val1;
+ char __iomem *addr;
+
+ pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
+ if (val1 == 0xffffffff)
+ continue;
+ addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
+ if (addr == NULL|| readl(addr) != val1) {
+ set_bit(i, &fallback_slots);
+ }
+ }
+}
+
static int __init pci_mmcfg_init(void)
{
int i;
@@ -128,6 +169,8 @@ static int __init pci_mmcfg_init(void)
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
}
+ unreachable_devices();
+
raw_pci_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;