Merge branch 'master' into for-next
This commit is contained in:
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(acpi_disabled);
|
||||
int acpi_noirq; /* skip ACPI IRQ initialization */
|
||||
int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
|
||||
EXPORT_SYMBOL(acpi_pci_disabled);
|
||||
int acpi_ht __initdata = 1; /* enable HT */
|
||||
|
||||
int acpi_lapic;
|
||||
int acpi_ioapic;
|
||||
@@ -1501,9 +1500,8 @@ void __init acpi_boot_table_init(void)
|
||||
|
||||
/*
|
||||
* If acpi_disabled, bail out
|
||||
* One exception: acpi=ht continues far enough to enumerate LAPICs
|
||||
*/
|
||||
if (acpi_disabled && !acpi_ht)
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -1534,9 +1532,8 @@ int __init early_acpi_boot_init(void)
|
||||
{
|
||||
/*
|
||||
* If acpi_disabled, bail out
|
||||
* One exception: acpi=ht continues far enough to enumerate LAPICs
|
||||
*/
|
||||
if (acpi_disabled && !acpi_ht)
|
||||
if (acpi_disabled)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
@@ -1554,9 +1551,8 @@ int __init acpi_boot_init(void)
|
||||
|
||||
/*
|
||||
* If acpi_disabled, bail out
|
||||
* One exception: acpi=ht continues far enough to enumerate LAPICs
|
||||
*/
|
||||
if (acpi_disabled && !acpi_ht)
|
||||
if (acpi_disabled)
|
||||
return 1;
|
||||
|
||||
acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
|
||||
@@ -1591,21 +1587,12 @@ static int __init parse_acpi(char *arg)
|
||||
/* acpi=force to over-ride black-list */
|
||||
else if (strcmp(arg, "force") == 0) {
|
||||
acpi_force = 1;
|
||||
acpi_ht = 1;
|
||||
acpi_disabled = 0;
|
||||
}
|
||||
/* acpi=strict disables out-of-spec workarounds */
|
||||
else if (strcmp(arg, "strict") == 0) {
|
||||
acpi_strict = 1;
|
||||
}
|
||||
/* Limit ACPI just to boot-time to enable HT */
|
||||
else if (strcmp(arg, "ht") == 0) {
|
||||
if (!acpi_force) {
|
||||
printk(KERN_WARNING "acpi=ht will be removed in Linux-2.6.35\n");
|
||||
disable_acpi();
|
||||
}
|
||||
acpi_ht = 1;
|
||||
}
|
||||
/* acpi=rsdt use RSDT instead of XSDT */
|
||||
else if (strcmp(arg, "rsdt") == 0) {
|
||||
acpi_rsdt_forced = 1;
|
||||
|
@@ -162,8 +162,6 @@ static int __init acpi_sleep_setup(char *str)
|
||||
#endif
|
||||
if (strncmp(str, "old_ordering", 12) == 0)
|
||||
acpi_old_suspend_ordering();
|
||||
if (strncmp(str, "sci_force_enable", 16) == 0)
|
||||
acpi_set_sci_en_on_resume();
|
||||
str = strchr(str, ',');
|
||||
if (str != NULL)
|
||||
str += strspn(str, ", \t");
|
||||
|
@@ -1,4 +1,4 @@
|
||||
.section .text.page_aligned
|
||||
.section .text..page_aligned
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/page_types.h>
|
||||
|
@@ -1487,6 +1487,7 @@ static int __attach_device(struct device *dev,
|
||||
struct protection_domain *domain)
|
||||
{
|
||||
struct iommu_dev_data *dev_data, *alias_data;
|
||||
int ret;
|
||||
|
||||
dev_data = get_dev_data(dev);
|
||||
alias_data = get_dev_data(dev_data->alias);
|
||||
@@ -1498,13 +1499,14 @@ static int __attach_device(struct device *dev,
|
||||
spin_lock(&domain->lock);
|
||||
|
||||
/* Some sanity checks */
|
||||
ret = -EBUSY;
|
||||
if (alias_data->domain != NULL &&
|
||||
alias_data->domain != domain)
|
||||
return -EBUSY;
|
||||
goto out_unlock;
|
||||
|
||||
if (dev_data->domain != NULL &&
|
||||
dev_data->domain != domain)
|
||||
return -EBUSY;
|
||||
goto out_unlock;
|
||||
|
||||
/* Do real assignment */
|
||||
if (dev_data->alias != dev) {
|
||||
@@ -1520,10 +1522,14 @@ static int __attach_device(struct device *dev,
|
||||
|
||||
atomic_inc(&dev_data->bind);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out_unlock:
|
||||
|
||||
/* ready */
|
||||
spin_unlock(&domain->lock);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2324,10 +2330,6 @@ int __init amd_iommu_init_dma_ops(void)
|
||||
|
||||
iommu_detected = 1;
|
||||
swiotlb = 0;
|
||||
#ifdef CONFIG_GART_IOMMU
|
||||
gart_iommu_aperture_disabled = 1;
|
||||
gart_iommu_aperture = 0;
|
||||
#endif
|
||||
|
||||
/* Make the driver finally visible to the drivers */
|
||||
dma_ops = &amd_iommu_dma_ops;
|
||||
|
@@ -287,8 +287,12 @@ static u8 * __init iommu_map_mmio_space(u64 address)
|
||||
{
|
||||
u8 *ret;
|
||||
|
||||
if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu"))
|
||||
if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) {
|
||||
pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n",
|
||||
address);
|
||||
pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = ioremap_nocache(address, MMIO_REGION_LENGTH);
|
||||
if (ret != NULL)
|
||||
@@ -1314,7 +1318,7 @@ static int __init amd_iommu_init(void)
|
||||
ret = amd_iommu_init_dma_ops();
|
||||
|
||||
if (ret)
|
||||
goto free;
|
||||
goto free_disable;
|
||||
|
||||
amd_iommu_init_api();
|
||||
|
||||
@@ -1332,9 +1336,10 @@ static int __init amd_iommu_init(void)
|
||||
out:
|
||||
return ret;
|
||||
|
||||
free:
|
||||
free_disable:
|
||||
disable_iommus();
|
||||
|
||||
free:
|
||||
amd_iommu_uninit_devices();
|
||||
|
||||
free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
|
||||
@@ -1353,6 +1358,15 @@ free:
|
||||
|
||||
free_unity_maps();
|
||||
|
||||
#ifdef CONFIG_GART_IOMMU
|
||||
/*
|
||||
* We failed to initialize the AMD IOMMU - try fallback to GART
|
||||
* if possible.
|
||||
*/
|
||||
gart_iommu_init();
|
||||
|
||||
#endif
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include <asm/smp.h>
|
||||
#include <asm/mce.h>
|
||||
#include <asm/kvm_para.h>
|
||||
#include <asm/tsc.h>
|
||||
|
||||
unsigned int num_processors;
|
||||
|
||||
@@ -1151,8 +1152,13 @@ static void __cpuinit lapic_setup_esr(void)
|
||||
*/
|
||||
void __cpuinit setup_local_APIC(void)
|
||||
{
|
||||
unsigned int value;
|
||||
int i, j;
|
||||
unsigned int value, queued;
|
||||
int i, j, acked = 0;
|
||||
unsigned long long tsc = 0, ntsc;
|
||||
long long max_loops = cpu_khz;
|
||||
|
||||
if (cpu_has_tsc)
|
||||
rdtscll(tsc);
|
||||
|
||||
if (disable_apic) {
|
||||
arch_disable_smp_support();
|
||||
@@ -1204,13 +1210,32 @@ void __cpuinit setup_local_APIC(void)
|
||||
* the interrupt. Hence a vector might get locked. It was noticed
|
||||
* for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
|
||||
*/
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
||||
value = apic_read(APIC_ISR + i*0x10);
|
||||
for (j = 31; j >= 0; j--) {
|
||||
if (value & (1<<j))
|
||||
ack_APIC_irq();
|
||||
do {
|
||||
queued = 0;
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--)
|
||||
queued |= apic_read(APIC_IRR + i*0x10);
|
||||
|
||||
for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
||||
value = apic_read(APIC_ISR + i*0x10);
|
||||
for (j = 31; j >= 0; j--) {
|
||||
if (value & (1<<j)) {
|
||||
ack_APIC_irq();
|
||||
acked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (acked > 256) {
|
||||
printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
|
||||
acked);
|
||||
break;
|
||||
}
|
||||
if (cpu_has_tsc) {
|
||||
rdtscll(ntsc);
|
||||
max_loops = (cpu_khz << 10) - (ntsc - tsc);
|
||||
} else
|
||||
max_loops--;
|
||||
} while (queued && max_loops > 0);
|
||||
WARN_ON(max_loops <= 0);
|
||||
|
||||
/*
|
||||
* Now that we are all set up, enable the APIC
|
||||
|
@@ -1121,9 +1121,9 @@ void __cpuinit cpu_init(void)
|
||||
oist = &per_cpu(orig_ist, cpu);
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
if (cpu != 0 && percpu_read(node_number) == 0 &&
|
||||
cpu_to_node(cpu) != NUMA_NO_NODE)
|
||||
percpu_write(node_number, cpu_to_node(cpu));
|
||||
if (cpu != 0 && percpu_read(numa_node) == 0 &&
|
||||
early_cpu_to_node(cpu) != NUMA_NO_NODE)
|
||||
set_numa_node(early_cpu_to_node(cpu));
|
||||
#endif
|
||||
|
||||
me = current;
|
||||
|
@@ -1497,8 +1497,8 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
|
||||
* simply keep the boost-disable flag in sync with the current global
|
||||
* state.
|
||||
*/
|
||||
static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *hcpu)
|
||||
static int cpb_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
unsigned cpu = (long)hcpu;
|
||||
u32 lo, hi;
|
||||
@@ -1528,7 +1528,7 @@ static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block __cpuinitdata cpb_nb = {
|
||||
static struct notifier_block cpb_nb = {
|
||||
.notifier_call = cpb_notify,
|
||||
};
|
||||
|
||||
|
@@ -7,3 +7,5 @@ obj-$(CONFIG_X86_MCE_THRESHOLD) += threshold.o
|
||||
obj-$(CONFIG_X86_MCE_INJECT) += mce-inject.o
|
||||
|
||||
obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
|
||||
|
||||
obj-$(CONFIG_ACPI_APEI) += mce-apei.o
|
||||
|
138
arch/x86/kernel/cpu/mcheck/mce-apei.c
Normal file
138
arch/x86/kernel/cpu/mcheck/mce-apei.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Bridge between MCE and APEI
|
||||
*
|
||||
* On some machine, corrected memory errors are reported via APEI
|
||||
* generic hardware error source (GHES) instead of corrected Machine
|
||||
* Check. These corrected memory errors can be reported to user space
|
||||
* through /dev/mcelog via faking a corrected Machine Check, so that
|
||||
* the error memory page can be offlined by /sbin/mcelog if the error
|
||||
* count for one page is beyond the threshold.
|
||||
*
|
||||
* For fatal MCE, save MCE record into persistent storage via ERST, so
|
||||
* that the MCE record can be logged after reboot via ERST.
|
||||
*
|
||||
* Copyright 2010 Intel Corp.
|
||||
* Author: Huang Ying <ying.huang@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cper.h>
|
||||
#include <acpi/apei.h>
|
||||
#include <asm/mce.h>
|
||||
|
||||
#include "mce-internal.h"
|
||||
|
||||
void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err)
|
||||
{
|
||||
struct mce m;
|
||||
|
||||
/* Only corrected MC is reported */
|
||||
if (!corrected)
|
||||
return;
|
||||
|
||||
mce_setup(&m);
|
||||
m.bank = 1;
|
||||
/* Fake a memory read corrected error with unknown channel */
|
||||
m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f;
|
||||
m.addr = mem_err->physical_addr;
|
||||
mce_log(&m);
|
||||
mce_notify_irq();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apei_mce_report_mem_error);
|
||||
|
||||
#define CPER_CREATOR_MCE \
|
||||
UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
|
||||
0x64, 0x90, 0xb8, 0x9d)
|
||||
#define CPER_SECTION_TYPE_MCE \
|
||||
UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
|
||||
0x04, 0x4a, 0x38, 0xfc)
|
||||
|
||||
/*
|
||||
* CPER specification (in UEFI specification 2.3 appendix N) requires
|
||||
* byte-packed.
|
||||
*/
|
||||
struct cper_mce_record {
|
||||
struct cper_record_header hdr;
|
||||
struct cper_section_descriptor sec_hdr;
|
||||
struct mce mce;
|
||||
} __packed;
|
||||
|
||||
int apei_write_mce(struct mce *m)
|
||||
{
|
||||
struct cper_mce_record rcd;
|
||||
|
||||
memset(&rcd, 0, sizeof(rcd));
|
||||
memcpy(rcd.hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
|
||||
rcd.hdr.revision = CPER_RECORD_REV;
|
||||
rcd.hdr.signature_end = CPER_SIG_END;
|
||||
rcd.hdr.section_count = 1;
|
||||
rcd.hdr.error_severity = CPER_SER_FATAL;
|
||||
/* timestamp, platform_id, partition_id are all invalid */
|
||||
rcd.hdr.validation_bits = 0;
|
||||
rcd.hdr.record_length = sizeof(rcd);
|
||||
rcd.hdr.creator_id = CPER_CREATOR_MCE;
|
||||
rcd.hdr.notification_type = CPER_NOTIFY_MCE;
|
||||
rcd.hdr.record_id = cper_next_record_id();
|
||||
rcd.hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
|
||||
|
||||
rcd.sec_hdr.section_offset = (void *)&rcd.mce - (void *)&rcd;
|
||||
rcd.sec_hdr.section_length = sizeof(rcd.mce);
|
||||
rcd.sec_hdr.revision = CPER_SEC_REV;
|
||||
/* fru_id and fru_text is invalid */
|
||||
rcd.sec_hdr.validation_bits = 0;
|
||||
rcd.sec_hdr.flags = CPER_SEC_PRIMARY;
|
||||
rcd.sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
|
||||
rcd.sec_hdr.section_severity = CPER_SER_FATAL;
|
||||
|
||||
memcpy(&rcd.mce, m, sizeof(*m));
|
||||
|
||||
return erst_write(&rcd.hdr);
|
||||
}
|
||||
|
||||
ssize_t apei_read_mce(struct mce *m, u64 *record_id)
|
||||
{
|
||||
struct cper_mce_record rcd;
|
||||
ssize_t len;
|
||||
|
||||
len = erst_read_next(&rcd.hdr, sizeof(rcd));
|
||||
if (len <= 0)
|
||||
return len;
|
||||
/* Can not skip other records in storage via ERST unless clear them */
|
||||
else if (len != sizeof(rcd) ||
|
||||
uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
|
||||
if (printk_ratelimit())
|
||||
pr_warning(
|
||||
"MCE-APEI: Can not skip the unknown record in ERST");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(m, &rcd.mce, sizeof(*m));
|
||||
*record_id = rcd.hdr.record_id;
|
||||
|
||||
return sizeof(*m);
|
||||
}
|
||||
|
||||
/* Check whether there is record in ERST */
|
||||
int apei_check_mce(void)
|
||||
{
|
||||
return erst_get_record_count();
|
||||
}
|
||||
|
||||
int apei_clear_mce(u64 record_id)
|
||||
{
|
||||
return erst_clear(record_id);
|
||||
}
|
@@ -28,3 +28,26 @@ extern int mce_ser;
|
||||
|
||||
extern struct mce_bank *mce_banks;
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI
|
||||
int apei_write_mce(struct mce *m);
|
||||
ssize_t apei_read_mce(struct mce *m, u64 *record_id);
|
||||
int apei_check_mce(void);
|
||||
int apei_clear_mce(u64 record_id);
|
||||
#else
|
||||
static inline int apei_write_mce(struct mce *m)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline ssize_t apei_read_mce(struct mce *m, u64 *record_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int apei_check_mce(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int apei_clear_mce(u64 record_id)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/edac_mce.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/hw_irq.h>
|
||||
@@ -168,6 +169,15 @@ void mce_log(struct mce *mce)
|
||||
for (;;) {
|
||||
entry = rcu_dereference_check_mce(mcelog.next);
|
||||
for (;;) {
|
||||
/*
|
||||
* If edac_mce is enabled, it will check the error type
|
||||
* and will process it, if it is a known error.
|
||||
* Otherwise, the error will be sent through mcelog
|
||||
* interface
|
||||
*/
|
||||
if (edac_mce_parse(mce))
|
||||
return;
|
||||
|
||||
/*
|
||||
* When the buffer fills up discard new entries.
|
||||
* Assume that the earlier errors are the more
|
||||
@@ -264,7 +274,7 @@ static void wait_for_panic(void)
|
||||
|
||||
static void mce_panic(char *msg, struct mce *final, char *exp)
|
||||
{
|
||||
int i;
|
||||
int i, apei_err = 0;
|
||||
|
||||
if (!fake_panic) {
|
||||
/*
|
||||
@@ -287,8 +297,11 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
|
||||
struct mce *m = &mcelog.entry[i];
|
||||
if (!(m->status & MCI_STATUS_VAL))
|
||||
continue;
|
||||
if (!(m->status & MCI_STATUS_UC))
|
||||
if (!(m->status & MCI_STATUS_UC)) {
|
||||
print_mce(m);
|
||||
if (!apei_err)
|
||||
apei_err = apei_write_mce(m);
|
||||
}
|
||||
}
|
||||
/* Now print uncorrected but with the final one last */
|
||||
for (i = 0; i < MCE_LOG_LEN; i++) {
|
||||
@@ -297,11 +310,17 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
|
||||
continue;
|
||||
if (!(m->status & MCI_STATUS_UC))
|
||||
continue;
|
||||
if (!final || memcmp(m, final, sizeof(struct mce)))
|
||||
if (!final || memcmp(m, final, sizeof(struct mce))) {
|
||||
print_mce(m);
|
||||
if (!apei_err)
|
||||
apei_err = apei_write_mce(m);
|
||||
}
|
||||
}
|
||||
if (final)
|
||||
if (final) {
|
||||
print_mce(final);
|
||||
if (!apei_err)
|
||||
apei_err = apei_write_mce(final);
|
||||
}
|
||||
if (cpu_missing)
|
||||
printk(KERN_EMERG "Some CPUs didn't answer in synchronization\n");
|
||||
print_mce_tail();
|
||||
@@ -1493,6 +1512,43 @@ static void collect_tscs(void *data)
|
||||
rdtscll(cpu_tsc[smp_processor_id()]);
|
||||
}
|
||||
|
||||
static int mce_apei_read_done;
|
||||
|
||||
/* Collect MCE record of previous boot in persistent storage via APEI ERST. */
|
||||
static int __mce_read_apei(char __user **ubuf, size_t usize)
|
||||
{
|
||||
int rc;
|
||||
u64 record_id;
|
||||
struct mce m;
|
||||
|
||||
if (usize < sizeof(struct mce))
|
||||
return -EINVAL;
|
||||
|
||||
rc = apei_read_mce(&m, &record_id);
|
||||
/* Error or no more MCE record */
|
||||
if (rc <= 0) {
|
||||
mce_apei_read_done = 1;
|
||||
return rc;
|
||||
}
|
||||
rc = -EFAULT;
|
||||
if (copy_to_user(*ubuf, &m, sizeof(struct mce)))
|
||||
return rc;
|
||||
/*
|
||||
* In fact, we should have cleared the record after that has
|
||||
* been flushed to the disk or sent to network in
|
||||
* /sbin/mcelog, but we have no interface to support that now,
|
||||
* so just clear it to avoid duplication.
|
||||
*/
|
||||
rc = apei_clear_mce(record_id);
|
||||
if (rc) {
|
||||
mce_apei_read_done = 1;
|
||||
return rc;
|
||||
}
|
||||
*ubuf += sizeof(struct mce);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
|
||||
loff_t *off)
|
||||
{
|
||||
@@ -1506,15 +1562,19 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize,
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&mce_read_mutex);
|
||||
|
||||
if (!mce_apei_read_done) {
|
||||
err = __mce_read_apei(&buf, usize);
|
||||
if (err || buf != ubuf)
|
||||
goto out;
|
||||
}
|
||||
|
||||
next = rcu_dereference_check_mce(mcelog.next);
|
||||
|
||||
/* Only supports full reads right now */
|
||||
if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) {
|
||||
mutex_unlock(&mce_read_mutex);
|
||||
kfree(cpu_tsc);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
err = -EINVAL;
|
||||
if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce))
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
prev = 0;
|
||||
@@ -1562,10 +1622,15 @@ timeout:
|
||||
memset(&mcelog.entry[i], 0, sizeof(struct mce));
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
err = -EFAULT;
|
||||
|
||||
out:
|
||||
mutex_unlock(&mce_read_mutex);
|
||||
kfree(cpu_tsc);
|
||||
|
||||
return err ? -EFAULT : buf - ubuf;
|
||||
return err ? err : buf - ubuf;
|
||||
}
|
||||
|
||||
static unsigned int mce_poll(struct file *file, poll_table *wait)
|
||||
@@ -1573,6 +1638,8 @@ static unsigned int mce_poll(struct file *file, poll_table *wait)
|
||||
poll_wait(file, &mce_wait, wait);
|
||||
if (rcu_dereference_check_mce(mcelog.next))
|
||||
return POLLIN | POLLRDNORM;
|
||||
if (!mce_apei_read_done && apei_check_mce())
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -190,7 +190,7 @@ thermal_throttle_cpu_callback(struct notifier_block *nfb,
|
||||
mutex_unlock(&therm_cpu_lock);
|
||||
break;
|
||||
}
|
||||
return err ? NOTIFY_BAD : NOTIFY_OK;
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
||||
static struct notifier_block thermal_throttle_cpu_notifier __cpuinitdata =
|
||||
|
@@ -106,6 +106,7 @@ struct cpu_hw_events {
|
||||
|
||||
int n_events;
|
||||
int n_added;
|
||||
int n_txn;
|
||||
int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
|
||||
u64 tags[X86_PMC_IDX_MAX];
|
||||
struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
|
||||
@@ -983,6 +984,7 @@ static int x86_pmu_enable(struct perf_event *event)
|
||||
out:
|
||||
cpuc->n_events = n;
|
||||
cpuc->n_added += n - n0;
|
||||
cpuc->n_txn += n - n0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1089,6 +1091,14 @@ static void x86_pmu_disable(struct perf_event *event)
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If we're called during a txn, we don't need to do anything.
|
||||
* The events never got scheduled and ->cancel_txn will truncate
|
||||
* the event_list.
|
||||
*/
|
||||
if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
|
||||
return;
|
||||
|
||||
x86_pmu_stop(event);
|
||||
|
||||
for (i = 0; i < cpuc->n_events; i++) {
|
||||
@@ -1379,6 +1389,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu)
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
|
||||
cpuc->group_flag |= PERF_EVENT_TXN_STARTED;
|
||||
cpuc->n_txn = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1391,6 +1402,11 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)
|
||||
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|
||||
|
||||
cpuc->group_flag &= ~PERF_EVENT_TXN_STARTED;
|
||||
/*
|
||||
* Truncate the collected events.
|
||||
*/
|
||||
cpuc->n_added -= cpuc->n_txn;
|
||||
cpuc->n_events -= cpuc->n_txn;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1419,6 +1435,12 @@ static int x86_pmu_commit_txn(const struct pmu *pmu)
|
||||
*/
|
||||
memcpy(cpuc->assign, assign, n*sizeof(int));
|
||||
|
||||
/*
|
||||
* Clear out the txn count so that ->cancel_txn() which gets
|
||||
* run after ->commit_txn() doesn't undo things.
|
||||
*/
|
||||
cpuc->n_txn = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1717,7 +1739,11 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski
|
||||
*/
|
||||
regs->bp = rewind_frame_pointer(skip + 1);
|
||||
regs->cs = __KERNEL_CS;
|
||||
local_save_flags(regs->flags);
|
||||
/*
|
||||
* We abuse bit 3 to pass exact information, see perf_misc_flags
|
||||
* and the comment with PERF_EFLAGS_EXACT.
|
||||
*/
|
||||
regs->flags = 0;
|
||||
}
|
||||
|
||||
unsigned long perf_instruction_pointer(struct pt_regs *regs)
|
||||
|
@@ -465,15 +465,21 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
|
||||
static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
|
||||
{
|
||||
unsigned long dummy;
|
||||
int overflow = 0;
|
||||
u32 low, high;
|
||||
|
||||
rdmsrl(hwc->config_base + hwc->idx, dummy);
|
||||
if (dummy & P4_CCCR_OVF) {
|
||||
rdmsr(hwc->config_base + hwc->idx, low, high);
|
||||
|
||||
/* we need to check high bit for unflagged overflows */
|
||||
if ((low & P4_CCCR_OVF) || !(high & (1 << 31))) {
|
||||
overflow = 1;
|
||||
(void)checking_wrmsrl(hwc->config_base + hwc->idx,
|
||||
((u64)dummy) & ~P4_CCCR_OVF);
|
||||
((u64)low) & ~P4_CCCR_OVF);
|
||||
}
|
||||
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static inline void p4_pmu_disable_event(struct perf_event *event)
|
||||
@@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
|
||||
|
||||
WARN_ON_ONCE(hwc->idx != idx);
|
||||
|
||||
/*
|
||||
* FIXME: Redundant call, actually not needed
|
||||
* but just to check if we're screwed
|
||||
*/
|
||||
p4_pmu_clear_cccr_ovf(hwc);
|
||||
/* it might be unflagged overflow */
|
||||
handled = p4_pmu_clear_cccr_ovf(hwc);
|
||||
|
||||
val = x86_perf_event_update(event);
|
||||
if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
|
||||
if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* event overflow
|
||||
*/
|
||||
handled = 1;
|
||||
data.period = event->hw.last_period;
|
||||
/* event overflow for sure */
|
||||
data.period = event->hw.last_period;
|
||||
|
||||
if (!x86_perf_event_set_period(event))
|
||||
continue;
|
||||
@@ -670,7 +670,7 @@ static void p4_pmu_swap_config_ts(struct hw_perf_event *hwc, int cpu)
|
||||
|
||||
/*
|
||||
* ESCR address hashing is tricky, ESCRs are not sequential
|
||||
* in memory but all starts from MSR_P4_BSU_ESCR0 (0x03e0) and
|
||||
* in memory but all starts from MSR_P4_BSU_ESCR0 (0x03a0) and
|
||||
* the metric between any ESCRs is laid in range [0xa0,0xe1]
|
||||
*
|
||||
* so we make ~70% filled hashtable
|
||||
@@ -735,8 +735,9 @@ static int p4_get_escr_idx(unsigned int addr)
|
||||
{
|
||||
unsigned int idx = P4_ESCR_MSR_IDX(addr);
|
||||
|
||||
if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE ||
|
||||
!p4_escr_table[idx])) {
|
||||
if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE ||
|
||||
!p4_escr_table[idx] ||
|
||||
p4_escr_table[idx] != addr)) {
|
||||
WARN_ONCE(1, "P4 PMU: Wrong address passed: %x\n", addr);
|
||||
return -1;
|
||||
}
|
||||
@@ -762,7 +763,7 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign
|
||||
{
|
||||
unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
unsigned long escr_mask[BITS_TO_LONGS(P4_ESCR_MSR_TABLE_SIZE)];
|
||||
int cpu = raw_smp_processor_id();
|
||||
int cpu = smp_processor_id();
|
||||
struct hw_perf_event *hwc;
|
||||
struct p4_event_bind *bind;
|
||||
unsigned int i, thread, num;
|
||||
|
@@ -170,7 +170,7 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
|
||||
cpuid_device_destroy(cpu);
|
||||
break;
|
||||
}
|
||||
return err ? NOTIFY_BAD : NOTIFY_OK;
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
||||
static struct notifier_block __refdata cpuid_class_cpu_notifier =
|
||||
|
@@ -34,7 +34,7 @@ EXPORT_SYMBOL(init_task);
|
||||
/*
|
||||
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
|
||||
* no more per-task TSS's. The TSS size is kept cacheline-aligned
|
||||
* so they are allowed to end up in the .data.cacheline_aligned
|
||||
* so they are allowed to end up in the .data..cacheline_aligned
|
||||
* section. Since TSS's are completely CPU-local, we want them
|
||||
* on exact cacheline boundaries, to eliminate cacheline ping-pong.
|
||||
*/
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#define KVM_SCALE 22
|
||||
|
||||
static int kvmclock = 1;
|
||||
static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
|
||||
static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
|
||||
|
||||
static int parse_no_kvmclock(char *arg)
|
||||
{
|
||||
@@ -54,7 +56,8 @@ static unsigned long kvm_get_wallclock(void)
|
||||
|
||||
low = (int)__pa_symbol(&wall_clock);
|
||||
high = ((u64)__pa_symbol(&wall_clock) >> 32);
|
||||
native_write_msr(MSR_KVM_WALL_CLOCK, low, high);
|
||||
|
||||
native_write_msr(msr_kvm_wall_clock, low, high);
|
||||
|
||||
vcpu_time = &get_cpu_var(hv_clock);
|
||||
pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
|
||||
@@ -130,7 +133,8 @@ static int kvm_register_clock(char *txt)
|
||||
high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
|
||||
printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
|
||||
cpu, high, low, txt);
|
||||
return native_write_msr_safe(MSR_KVM_SYSTEM_TIME, low, high);
|
||||
|
||||
return native_write_msr_safe(msr_kvm_system_time, low, high);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
@@ -165,14 +169,14 @@ static void __init kvm_smp_prepare_boot_cpu(void)
|
||||
#ifdef CONFIG_KEXEC
|
||||
static void kvm_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
|
||||
native_write_msr(msr_kvm_system_time, 0, 0);
|
||||
native_machine_crash_shutdown(regs);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kvm_shutdown(void)
|
||||
{
|
||||
native_write_msr_safe(MSR_KVM_SYSTEM_TIME, 0, 0);
|
||||
native_write_msr(msr_kvm_system_time, 0, 0);
|
||||
native_machine_shutdown();
|
||||
}
|
||||
|
||||
@@ -181,27 +185,37 @@ void __init kvmclock_init(void)
|
||||
if (!kvm_para_available())
|
||||
return;
|
||||
|
||||
if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
|
||||
if (kvm_register_clock("boot clock"))
|
||||
return;
|
||||
pv_time_ops.sched_clock = kvm_clock_read;
|
||||
x86_platform.calibrate_tsc = kvm_get_tsc_khz;
|
||||
x86_platform.get_wallclock = kvm_get_wallclock;
|
||||
x86_platform.set_wallclock = kvm_set_wallclock;
|
||||
if (kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) {
|
||||
msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
|
||||
msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
|
||||
} else if (!(kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)))
|
||||
return;
|
||||
|
||||
printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
|
||||
msr_kvm_system_time, msr_kvm_wall_clock);
|
||||
|
||||
if (kvm_register_clock("boot clock"))
|
||||
return;
|
||||
pv_time_ops.sched_clock = kvm_clock_read;
|
||||
x86_platform.calibrate_tsc = kvm_get_tsc_khz;
|
||||
x86_platform.get_wallclock = kvm_get_wallclock;
|
||||
x86_platform.set_wallclock = kvm_set_wallclock;
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
x86_cpuinit.setup_percpu_clockev =
|
||||
kvm_setup_secondary_clock;
|
||||
x86_cpuinit.setup_percpu_clockev =
|
||||
kvm_setup_secondary_clock;
|
||||
#endif
|
||||
#ifdef CONFIG_SMP
|
||||
smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
|
||||
smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
|
||||
#endif
|
||||
machine_ops.shutdown = kvm_shutdown;
|
||||
machine_ops.shutdown = kvm_shutdown;
|
||||
#ifdef CONFIG_KEXEC
|
||||
machine_ops.crash_shutdown = kvm_crash_shutdown;
|
||||
machine_ops.crash_shutdown = kvm_crash_shutdown;
|
||||
#endif
|
||||
kvm_get_preset_lpj();
|
||||
clocksource_register(&kvm_clock);
|
||||
pv_info.paravirt_enabled = 1;
|
||||
pv_info.name = "KVM";
|
||||
}
|
||||
kvm_get_preset_lpj();
|
||||
clocksource_register(&kvm_clock);
|
||||
pv_info.paravirt_enabled = 1;
|
||||
pv_info.name = "KVM";
|
||||
|
||||
if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
|
||||
pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
|
||||
}
|
||||
|
@@ -260,6 +260,7 @@ static void microcode_dev_exit(void)
|
||||
}
|
||||
|
||||
MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
|
||||
MODULE_ALIAS("devname:cpu/microcode");
|
||||
#else
|
||||
#define microcode_dev_init() 0
|
||||
#define microcode_dev_exit() do { } while (0)
|
||||
|
@@ -230,7 +230,7 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
|
||||
msr_device_destroy(cpu);
|
||||
break;
|
||||
}
|
||||
return err ? NOTIFY_BAD : NOTIFY_OK;
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
||||
static struct notifier_block __refdata msr_class_cpu_notifier = {
|
||||
|
@@ -31,8 +31,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
|
||||
.free_coherent = swiotlb_free_coherent,
|
||||
.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
|
||||
.sync_single_for_device = swiotlb_sync_single_for_device,
|
||||
.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
|
||||
.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
|
||||
.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
|
||||
.sync_sg_for_device = swiotlb_sync_sg_for_device,
|
||||
.map_sg = swiotlb_map_sg_attrs,
|
||||
|
@@ -31,8 +31,16 @@ struct pvclock_shadow_time {
|
||||
u32 tsc_to_nsec_mul;
|
||||
int tsc_shift;
|
||||
u32 version;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
static u8 valid_flags __read_mostly = 0;
|
||||
|
||||
void pvclock_set_flags(u8 flags)
|
||||
{
|
||||
valid_flags = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
|
||||
* yielding a 64-bit result.
|
||||
@@ -91,6 +99,7 @@ static unsigned pvclock_get_time_values(struct pvclock_shadow_time *dst,
|
||||
dst->system_timestamp = src->system_time;
|
||||
dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
|
||||
dst->tsc_shift = src->tsc_shift;
|
||||
dst->flags = src->flags;
|
||||
rmb(); /* test version after fetching data */
|
||||
} while ((src->version & 1) || (dst->version != src->version));
|
||||
|
||||
@@ -109,11 +118,14 @@ unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src)
|
||||
return pv_tsc_khz;
|
||||
}
|
||||
|
||||
static atomic64_t last_value = ATOMIC64_INIT(0);
|
||||
|
||||
cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
|
||||
{
|
||||
struct pvclock_shadow_time shadow;
|
||||
unsigned version;
|
||||
cycle_t ret, offset;
|
||||
u64 last;
|
||||
|
||||
do {
|
||||
version = pvclock_get_time_values(&shadow, src);
|
||||
@@ -123,6 +135,31 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
|
||||
barrier();
|
||||
} while (version != src->version);
|
||||
|
||||
if ((valid_flags & PVCLOCK_TSC_STABLE_BIT) &&
|
||||
(shadow.flags & PVCLOCK_TSC_STABLE_BIT))
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Assumption here is that last_value, a global accumulator, always goes
|
||||
* forward. If we are less than that, we should not be much smaller.
|
||||
* We assume there is an error marging we're inside, and then the correction
|
||||
* does not sacrifice accuracy.
|
||||
*
|
||||
* For reads: global may have changed between test and return,
|
||||
* but this means someone else updated poked the clock at a later time.
|
||||
* We just need to make sure we are not seeing a backwards event.
|
||||
*
|
||||
* For updates: last_value = ret is not enough, since two vcpus could be
|
||||
* updating at the same time, and one of them could be slightly behind,
|
||||
* making the assumption that last_value always go forward fail to hold.
|
||||
*/
|
||||
last = atomic64_read(&last_value);
|
||||
do {
|
||||
if (ret < last)
|
||||
return last;
|
||||
last = atomic64_cmpxchg(&last_value, last, ret);
|
||||
} while (unlikely(last != ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -676,6 +676,17 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "DG45FC"),
|
||||
},
|
||||
},
|
||||
/*
|
||||
* The Dell Inspiron Mini 1012 has DMI_BIOS_VENDOR = "Dell Inc.", so
|
||||
* match on the product name.
|
||||
*/
|
||||
{
|
||||
.callback = dmi_low_memory_corruption,
|
||||
.ident = "Phoenix BIOS",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
@@ -21,12 +21,6 @@
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/stackprotector.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
|
||||
# define DBG(fmt, ...) pr_dbg(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define DBG(fmt, ...) do { if (0) pr_dbg(fmt, ##__VA_ARGS__); } while (0)
|
||||
#endif
|
||||
|
||||
DEFINE_PER_CPU(int, cpu_number);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
||||
|
||||
@@ -247,7 +241,7 @@ void __init setup_per_cpu_areas(void)
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* Up to this point, the boot CPU has been using .data.init
|
||||
* Up to this point, the boot CPU has been using .init.data
|
||||
* area. Reload any changed state for the boot CPU.
|
||||
*/
|
||||
if (cpu == boot_cpu_id)
|
||||
@@ -265,10 +259,10 @@ void __init setup_per_cpu_areas(void)
|
||||
|
||||
#if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
|
||||
/*
|
||||
* make sure boot cpu node_number is right, when boot cpu is on the
|
||||
* make sure boot cpu numa_node is right, when boot cpu is on the
|
||||
* node that doesn't have mem installed
|
||||
*/
|
||||
per_cpu(node_number, boot_cpu_id) = cpu_to_node(boot_cpu_id);
|
||||
set_cpu_numa_node(boot_cpu_id, early_cpu_to_node(boot_cpu_id));
|
||||
#endif
|
||||
|
||||
/* Setup node to cpumask map */
|
||||
|
@@ -686,7 +686,7 @@ static void __cpuinit do_fork_idle(struct work_struct *work)
|
||||
static void __cpuinit announce_cpu(int cpu, int apicid)
|
||||
{
|
||||
static int current_node = -1;
|
||||
int node = cpu_to_node(cpu);
|
||||
int node = early_cpu_to_node(cpu);
|
||||
|
||||
if (system_state == SYSTEM_BOOTING) {
|
||||
if (node != current_node) {
|
||||
@@ -1215,9 +1215,17 @@ __init void prefill_possible_map(void)
|
||||
if (!num_processors)
|
||||
num_processors = 1;
|
||||
|
||||
if (setup_possible_cpus == -1)
|
||||
possible = num_processors + disabled_cpus;
|
||||
else
|
||||
i = setup_max_cpus ?: 1;
|
||||
if (setup_possible_cpus == -1) {
|
||||
possible = num_processors;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (setup_max_cpus)
|
||||
possible += disabled_cpus;
|
||||
#else
|
||||
if (possible > i)
|
||||
possible = i;
|
||||
#endif
|
||||
} else
|
||||
possible = setup_possible_cpus;
|
||||
|
||||
total_cpus = max_t(int, possible, num_processors + disabled_cpus);
|
||||
@@ -1230,11 +1238,23 @@ __init void prefill_possible_map(void)
|
||||
possible = nr_cpu_ids;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!setup_max_cpus)
|
||||
#endif
|
||||
if (possible > i) {
|
||||
printk(KERN_WARNING
|
||||
"%d Processors exceeds max_cpus limit of %u\n",
|
||||
possible, setup_max_cpus);
|
||||
possible = i;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
|
||||
possible, max_t(int, possible - num_processors, 0));
|
||||
|
||||
for (i = 0; i < possible; i++)
|
||||
set_cpu_possible(i, true);
|
||||
for (; i < NR_CPUS; i++)
|
||||
set_cpu_possible(i, false);
|
||||
|
||||
nr_cpu_ids = possible;
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@
|
||||
|
||||
/* Global pointer to shared data; NULL means no measured launch. */
|
||||
struct tboot *tboot __read_mostly;
|
||||
EXPORT_SYMBOL(tboot);
|
||||
|
||||
/* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */
|
||||
#define AP_WAIT_TIMEOUT 1
|
||||
|
@@ -97,7 +97,7 @@ SECTIONS
|
||||
HEAD_TEXT
|
||||
#ifdef CONFIG_X86_32
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
*(.text.page_aligned)
|
||||
*(.text..page_aligned)
|
||||
#endif
|
||||
. = ALIGN(8);
|
||||
_stext = .;
|
||||
@@ -305,7 +305,7 @@ SECTIONS
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
|
||||
__bss_start = .;
|
||||
*(.bss.page_aligned)
|
||||
*(.bss..page_aligned)
|
||||
*(.bss)
|
||||
. = ALIGN(4);
|
||||
__bss_stop = .;
|
||||
|
Reference in New Issue
Block a user