Merge branches 'x86/mm', 'x86/build', 'x86/apic' and 'x86/platform' into x86/core, to apply dependent patch
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -31,12 +31,12 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/pci_x86.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/io_apic.h>
|
||||
@@ -400,57 +400,13 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
|
||||
int polarity)
|
||||
{
|
||||
int irq, node;
|
||||
|
||||
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
|
||||
return gsi;
|
||||
|
||||
trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
|
||||
polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
|
||||
node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
|
||||
if (mp_set_gsi_attr(gsi, trigger, polarity, node)) {
|
||||
pr_warn("Failed to set pin attr for GSI%d\n", gsi);
|
||||
return -1;
|
||||
}
|
||||
|
||||
irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
/* Don't set up the ACPI SCI because it's already set up */
|
||||
if (enable_update_mptable && acpi_gbl_FADT.sci_interrupt != gsi)
|
||||
mp_config_acpi_gsi(dev, gsi, trigger, polarity);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void mp_unregister_gsi(u32 gsi)
|
||||
{
|
||||
int irq;
|
||||
|
||||
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
|
||||
return;
|
||||
|
||||
irq = mp_map_gsi_to_irq(gsi, 0);
|
||||
if (irq > 0)
|
||||
mp_unmap_irq(irq);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops acpi_irqdomain_ops = {
|
||||
.map = mp_irqdomain_map,
|
||||
.unmap = mp_irqdomain_unmap,
|
||||
};
|
||||
|
||||
static int __init
|
||||
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
|
||||
{
|
||||
struct acpi_madt_io_apic *ioapic = NULL;
|
||||
struct ioapic_domain_cfg cfg = {
|
||||
.type = IOAPIC_DOMAIN_DYNAMIC,
|
||||
.ops = &acpi_irqdomain_ops,
|
||||
.ops = &mp_ioapic_irqdomain_ops,
|
||||
};
|
||||
|
||||
ioapic = (struct acpi_madt_io_apic *)header;
|
||||
@@ -652,7 +608,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
|
||||
* Make sure all (legacy) PCI IRQs are set as level-triggered.
|
||||
*/
|
||||
if (trigger == ACPI_LEVEL_SENSITIVE)
|
||||
eisa_set_level_irq(gsi);
|
||||
elcr_set_level_irq(gsi);
|
||||
#endif
|
||||
|
||||
return gsi;
|
||||
@@ -663,10 +619,21 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity)
|
||||
{
|
||||
int irq = gsi;
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
int node;
|
||||
struct irq_alloc_info info;
|
||||
|
||||
node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
|
||||
trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
|
||||
polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
|
||||
ioapic_set_alloc_attr(&info, node, trigger, polarity);
|
||||
|
||||
mutex_lock(&acpi_ioapic_lock);
|
||||
irq = mp_register_gsi(dev, gsi, trigger, polarity);
|
||||
irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
|
||||
/* Don't set up the ACPI SCI because it's already set up */
|
||||
if (irq >= 0 && enable_update_mptable &&
|
||||
acpi_gbl_FADT.sci_interrupt != gsi)
|
||||
mp_config_acpi_gsi(dev, gsi, trigger, polarity);
|
||||
mutex_unlock(&acpi_ioapic_lock);
|
||||
#endif
|
||||
|
||||
@@ -676,8 +643,12 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
|
||||
static void acpi_unregister_gsi_ioapic(u32 gsi)
|
||||
{
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
int irq;
|
||||
|
||||
mutex_lock(&acpi_ioapic_lock);
|
||||
mp_unregister_gsi(gsi);
|
||||
irq = mp_map_gsi_to_irq(gsi, 0, NULL);
|
||||
if (irq > 0)
|
||||
mp_unmap_irq(irq);
|
||||
mutex_unlock(&acpi_ioapic_lock);
|
||||
#endif
|
||||
}
|
||||
@@ -786,7 +757,7 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
|
||||
u64 addr;
|
||||
struct ioapic_domain_cfg cfg = {
|
||||
.type = IOAPIC_DOMAIN_DYNAMIC,
|
||||
.ops = &acpi_irqdomain_ops,
|
||||
.ops = &mp_ioapic_irqdomain_ops,
|
||||
};
|
||||
|
||||
ioapic_id = acpi_get_ioapic_id(handle, gsi_base, &addr);
|
||||
|
@@ -62,7 +62,7 @@ ENTRY(do_suspend_lowlevel)
|
||||
pushfq
|
||||
popq pt_regs_flags(%rax)
|
||||
|
||||
movq $resume_point, saved_rip(%rip)
|
||||
movq $.Lresume_point, saved_rip(%rip)
|
||||
|
||||
movq %rsp, saved_rsp
|
||||
movq %rbp, saved_rbp
|
||||
@@ -75,10 +75,10 @@ ENTRY(do_suspend_lowlevel)
|
||||
xorl %eax, %eax
|
||||
call x86_acpi_enter_sleep_state
|
||||
/* in case something went wrong, restore the machine status and go on */
|
||||
jmp resume_point
|
||||
jmp .Lresume_point
|
||||
|
||||
.align 4
|
||||
resume_point:
|
||||
.Lresume_point:
|
||||
/* We don't restore %rax, it must be 0 anyway */
|
||||
movq $saved_context, %rax
|
||||
movq saved_context_cr4(%rax), %rbx
|
||||
|
@@ -227,6 +227,15 @@ void __init arch_init_ideal_nops(void)
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case X86_VENDOR_AMD:
|
||||
if (boot_cpu_data.x86 > 0xf) {
|
||||
ideal_nops = p6_nops;
|
||||
return;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
#ifdef CONFIG_X86_64
|
||||
ideal_nops = k8_nops;
|
||||
|
@@ -171,10 +171,6 @@ static int __init apbt_clockevent_register(void)
|
||||
|
||||
static void apbt_setup_irq(struct apbt_dev *adev)
|
||||
{
|
||||
/* timer0 irq has been setup early */
|
||||
if (adev->irq == 0)
|
||||
return;
|
||||
|
||||
irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
|
||||
irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
|
||||
* Moved from arch/x86/kernel/apic/io_apic.c.
|
||||
* Jiang Liu <jiang.liu@linux.intel.com>
|
||||
* Add support of hierarchical irqdomain
|
||||
*
|
||||
* 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
|
||||
@@ -14,78 +16,112 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/htirq.h>
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/hypertransport.h>
|
||||
|
||||
static struct irq_domain *htirq_domain;
|
||||
|
||||
/*
|
||||
* Hypertransport interrupt support
|
||||
*/
|
||||
static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
|
||||
{
|
||||
struct ht_irq_msg msg;
|
||||
|
||||
fetch_ht_irq_msg(irq, &msg);
|
||||
|
||||
msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
|
||||
msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
|
||||
|
||||
msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
|
||||
msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
|
||||
|
||||
write_ht_irq_msg(irq, &msg);
|
||||
}
|
||||
|
||||
static int
|
||||
ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
unsigned int dest;
|
||||
struct irq_data *parent = data->parent_data;
|
||||
int ret;
|
||||
|
||||
ret = apic_set_affinity(data, mask, &dest);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = parent->chip->irq_set_affinity(parent, mask, force);
|
||||
if (ret >= 0) {
|
||||
struct ht_irq_msg msg;
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
|
||||
target_ht_irq(data->irq, dest, cfg->vector);
|
||||
return IRQ_SET_MASK_OK_NOCOPY;
|
||||
fetch_ht_irq_msg(data->irq, &msg);
|
||||
msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK |
|
||||
HT_IRQ_LOW_DEST_ID_MASK);
|
||||
msg.address_lo |= HT_IRQ_LOW_VECTOR(cfg->vector) |
|
||||
HT_IRQ_LOW_DEST_ID(cfg->dest_apicid);
|
||||
msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
|
||||
msg.address_hi |= HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
|
||||
write_ht_irq_msg(data->irq, &msg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct irq_chip ht_irq_chip = {
|
||||
.name = "PCI-HT",
|
||||
.irq_mask = mask_ht_irq,
|
||||
.irq_unmask = unmask_ht_irq,
|
||||
.irq_ack = apic_ack_edge,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_set_affinity = ht_set_affinity,
|
||||
.irq_retrigger = apic_retrigger_irq,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
|
||||
static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct ht_irq_cfg *ht_cfg;
|
||||
struct irq_alloc_info *info = arg;
|
||||
struct pci_dev *dev;
|
||||
irq_hw_number_t hwirq;
|
||||
int ret;
|
||||
|
||||
if (nr_irqs > 1 || !info)
|
||||
return -EINVAL;
|
||||
|
||||
dev = info->ht_dev;
|
||||
hwirq = (info->ht_idx & 0xFF) |
|
||||
PCI_DEVID(dev->bus->number, dev->devfn) << 8 |
|
||||
(pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 24;
|
||||
if (irq_find_mapping(domain, hwirq) > 0)
|
||||
return -EEXIST;
|
||||
|
||||
ht_cfg = kmalloc(sizeof(*ht_cfg), GFP_KERNEL);
|
||||
if (!ht_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
|
||||
if (ret < 0) {
|
||||
kfree(ht_cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize msg to a value that will never match the first write. */
|
||||
ht_cfg->msg.address_lo = 0xffffffff;
|
||||
ht_cfg->msg.address_hi = 0xffffffff;
|
||||
ht_cfg->dev = info->ht_dev;
|
||||
ht_cfg->update = info->ht_update;
|
||||
ht_cfg->pos = info->ht_pos;
|
||||
ht_cfg->idx = 0x10 + (info->ht_idx * 2);
|
||||
irq_domain_set_info(domain, virq, hwirq, &ht_irq_chip, ht_cfg,
|
||||
handle_edge_irq, ht_cfg, "edge");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
|
||||
|
||||
BUG_ON(nr_irqs != 1);
|
||||
kfree(irq_data->chip_data);
|
||||
irq_domain_free_irqs_top(domain, virq, nr_irqs);
|
||||
}
|
||||
|
||||
static void htirq_domain_activate(struct irq_domain *domain,
|
||||
struct irq_data *irq_data)
|
||||
{
|
||||
struct irq_cfg *cfg;
|
||||
struct ht_irq_msg msg;
|
||||
unsigned dest;
|
||||
int err;
|
||||
|
||||
if (disable_apic)
|
||||
return -ENXIO;
|
||||
|
||||
cfg = irq_cfg(irq);
|
||||
err = assign_irq_vector(irq, cfg, apic->target_cpus());
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = apic->cpu_mask_to_apicid_and(cfg->domain,
|
||||
apic->target_cpus(), &dest);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
|
||||
struct irq_cfg *cfg = irqd_cfg(irq_data);
|
||||
|
||||
msg.address_hi = HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
|
||||
msg.address_lo =
|
||||
HT_IRQ_LOW_BASE |
|
||||
HT_IRQ_LOW_DEST_ID(dest) |
|
||||
HT_IRQ_LOW_DEST_ID(cfg->dest_apicid) |
|
||||
HT_IRQ_LOW_VECTOR(cfg->vector) |
|
||||
((apic->irq_dest_mode == 0) ?
|
||||
HT_IRQ_LOW_DM_PHYSICAL :
|
||||
@@ -95,13 +131,56 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
|
||||
HT_IRQ_LOW_MT_FIXED :
|
||||
HT_IRQ_LOW_MT_ARBITRATED) |
|
||||
HT_IRQ_LOW_IRQ_MASKED;
|
||||
|
||||
write_ht_irq_msg(irq, &msg);
|
||||
|
||||
irq_set_chip_and_handler_name(irq, &ht_irq_chip,
|
||||
handle_edge_irq, "edge");
|
||||
|
||||
dev_dbg(&dev->dev, "irq %d for HT\n", irq);
|
||||
|
||||
return 0;
|
||||
write_ht_irq_msg(irq_data->irq, &msg);
|
||||
}
|
||||
|
||||
static void htirq_domain_deactivate(struct irq_domain *domain,
|
||||
struct irq_data *irq_data)
|
||||
{
|
||||
struct ht_irq_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
write_ht_irq_msg(irq_data->irq, &msg);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops htirq_domain_ops = {
|
||||
.alloc = htirq_domain_alloc,
|
||||
.free = htirq_domain_free,
|
||||
.activate = htirq_domain_activate,
|
||||
.deactivate = htirq_domain_deactivate,
|
||||
};
|
||||
|
||||
void arch_init_htirq_domain(struct irq_domain *parent)
|
||||
{
|
||||
if (disable_apic)
|
||||
return;
|
||||
|
||||
htirq_domain = irq_domain_add_tree(NULL, &htirq_domain_ops, NULL);
|
||||
if (!htirq_domain)
|
||||
pr_warn("failed to initialize irqdomain for HTIRQ.\n");
|
||||
else
|
||||
htirq_domain->parent = parent;
|
||||
}
|
||||
|
||||
int arch_setup_ht_irq(int idx, int pos, struct pci_dev *dev,
|
||||
ht_irq_update_t *update)
|
||||
{
|
||||
struct irq_alloc_info info;
|
||||
|
||||
if (!htirq_domain)
|
||||
return -ENOSYS;
|
||||
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.ht_idx = idx;
|
||||
info.ht_pos = pos;
|
||||
info.ht_dev = dev;
|
||||
info.ht_update = update;
|
||||
|
||||
return irq_domain_alloc_irqs(htirq_domain, 1, dev_to_node(&dev->dev),
|
||||
&info);
|
||||
}
|
||||
|
||||
void arch_teardown_ht_irq(unsigned int irq)
|
||||
{
|
||||
irq_domain_free_irqs(irq, 1);
|
||||
}
|
||||
|
File diff ditekan karena terlalu besar
Load Diff
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
|
||||
* Moved from arch/x86/kernel/apic/io_apic.c.
|
||||
* Jiang Liu <jiang.liu@linux.intel.com>
|
||||
* Convert to hierarchical irqdomain
|
||||
*
|
||||
* 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
|
||||
@@ -14,22 +16,23 @@
|
||||
#include <linux/dmar.h>
|
||||
#include <linux/hpet.h>
|
||||
#include <linux/msi.h>
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/msidef.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/irq_remapping.h>
|
||||
|
||||
void native_compose_msi_msg(struct pci_dev *pdev,
|
||||
unsigned int irq, unsigned int dest,
|
||||
struct msi_msg *msg, u8 hpet_id)
|
||||
static struct irq_domain *msi_default_domain;
|
||||
|
||||
static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct irq_cfg *cfg = irq_cfg(irq);
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
|
||||
msg->address_hi = MSI_ADDR_BASE_HI;
|
||||
|
||||
if (x2apic_enabled())
|
||||
msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
|
||||
msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
|
||||
|
||||
msg->address_lo =
|
||||
MSI_ADDR_BASE_LO |
|
||||
@@ -39,7 +42,7 @@ void native_compose_msi_msg(struct pci_dev *pdev,
|
||||
((apic->irq_delivery_mode != dest_LowestPrio) ?
|
||||
MSI_ADDR_REDIRECTION_CPU :
|
||||
MSI_ADDR_REDIRECTION_LOWPRI) |
|
||||
MSI_ADDR_DEST_ID(dest);
|
||||
MSI_ADDR_DEST_ID(cfg->dest_apicid);
|
||||
|
||||
msg->data =
|
||||
MSI_DATA_TRIGGER_EDGE |
|
||||
@@ -50,237 +53,305 @@ void native_compose_msi_msg(struct pci_dev *pdev,
|
||||
MSI_DATA_VECTOR(cfg->vector);
|
||||
}
|
||||
|
||||
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
|
||||
struct msi_msg *msg, u8 hpet_id)
|
||||
{
|
||||
struct irq_cfg *cfg;
|
||||
int err;
|
||||
unsigned dest;
|
||||
|
||||
if (disable_apic)
|
||||
return -ENXIO;
|
||||
|
||||
cfg = irq_cfg(irq);
|
||||
err = assign_irq_vector(irq, cfg, apic->target_cpus());
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = apic->cpu_mask_to_apicid_and(cfg->domain,
|
||||
apic->target_cpus(), &dest);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct msi_msg msg;
|
||||
unsigned int dest;
|
||||
int ret;
|
||||
|
||||
ret = apic_set_affinity(data, mask, &dest);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
__get_cached_msi_msg(data->msi_desc, &msg);
|
||||
|
||||
msg.data &= ~MSI_DATA_VECTOR_MASK;
|
||||
msg.data |= MSI_DATA_VECTOR(cfg->vector);
|
||||
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
|
||||
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
||||
|
||||
__pci_write_msi_msg(data->msi_desc, &msg);
|
||||
|
||||
return IRQ_SET_MASK_OK_NOCOPY;
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
|
||||
* which implement the MSI or MSI-X Capability Structure.
|
||||
*/
|
||||
static struct irq_chip msi_chip = {
|
||||
static struct irq_chip pci_msi_controller = {
|
||||
.name = "PCI-MSI",
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_ack = apic_ack_edge,
|
||||
.irq_set_affinity = msi_set_affinity,
|
||||
.irq_retrigger = apic_retrigger_irq,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_compose_msi_msg = irq_msi_compose_msg,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
|
||||
unsigned int irq_base, unsigned int irq_offset)
|
||||
{
|
||||
struct irq_chip *chip = &msi_chip;
|
||||
struct msi_msg msg;
|
||||
unsigned int irq = irq_base + irq_offset;
|
||||
int ret;
|
||||
|
||||
ret = msi_compose_msg(dev, irq, &msg, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
|
||||
|
||||
/*
|
||||
* MSI-X message is written per-IRQ, the offset is always 0.
|
||||
* MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
|
||||
*/
|
||||
if (!irq_offset)
|
||||
pci_write_msi_msg(irq, &msg);
|
||||
|
||||
setup_remapped_irq(irq, irq_cfg(irq), chip);
|
||||
|
||||
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
|
||||
|
||||
dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||||
{
|
||||
struct msi_desc *msidesc;
|
||||
unsigned int irq;
|
||||
int node, ret;
|
||||
struct irq_domain *domain;
|
||||
struct irq_alloc_info info;
|
||||
|
||||
/* Multiple MSI vectors only supported with interrupt remapping */
|
||||
if (type == PCI_CAP_ID_MSI && nvec > 1)
|
||||
return 1;
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.type = X86_IRQ_ALLOC_TYPE_MSI;
|
||||
info.msi_dev = dev;
|
||||
|
||||
node = dev_to_node(&dev->dev);
|
||||
domain = irq_remapping_get_irq_domain(&info);
|
||||
if (domain == NULL)
|
||||
domain = msi_default_domain;
|
||||
if (domain == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||||
irq = irq_alloc_hwirq(node);
|
||||
if (!irq)
|
||||
return -ENOSPC;
|
||||
|
||||
ret = setup_msi_irq(dev, msidesc, irq, 0);
|
||||
if (ret < 0) {
|
||||
irq_free_hwirq(irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
|
||||
}
|
||||
|
||||
void native_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
irq_free_hwirq(irq);
|
||||
irq_domain_free_irqs(irq, 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DMAR_TABLE
|
||||
static int
|
||||
dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
bool force)
|
||||
static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
|
||||
msi_alloc_info_t *arg)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
unsigned int dest, irq = data->irq;
|
||||
struct msi_msg msg;
|
||||
int ret;
|
||||
|
||||
ret = apic_set_affinity(data, mask, &dest);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dmar_msi_read(irq, &msg);
|
||||
|
||||
msg.data &= ~MSI_DATA_VECTOR_MASK;
|
||||
msg.data |= MSI_DATA_VECTOR(cfg->vector);
|
||||
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
|
||||
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
||||
msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
|
||||
|
||||
dmar_msi_write(irq, &msg);
|
||||
|
||||
return IRQ_SET_MASK_OK_NOCOPY;
|
||||
return arg->msi_hwirq;
|
||||
}
|
||||
|
||||
static struct irq_chip dmar_msi_type = {
|
||||
.name = "DMAR_MSI",
|
||||
.irq_unmask = dmar_msi_unmask,
|
||||
.irq_mask = dmar_msi_mask,
|
||||
.irq_ack = apic_ack_edge,
|
||||
.irq_set_affinity = dmar_msi_set_affinity,
|
||||
.irq_retrigger = apic_retrigger_irq,
|
||||
static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
|
||||
int nvec, msi_alloc_info_t *arg)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct msi_desc *desc = first_pci_msi_entry(pdev);
|
||||
|
||||
init_irq_alloc_info(arg, NULL);
|
||||
arg->msi_dev = pdev;
|
||||
if (desc->msi_attrib.is_msix) {
|
||||
arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
|
||||
} else {
|
||||
arg->type = X86_IRQ_ALLOC_TYPE_MSI;
|
||||
arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
|
||||
{
|
||||
arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
|
||||
}
|
||||
|
||||
static struct msi_domain_ops pci_msi_domain_ops = {
|
||||
.get_hwirq = pci_msi_get_hwirq,
|
||||
.msi_prepare = pci_msi_prepare,
|
||||
.set_desc = pci_msi_set_desc,
|
||||
};
|
||||
|
||||
static struct msi_domain_info pci_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_PCI_MSIX,
|
||||
.ops = &pci_msi_domain_ops,
|
||||
.chip = &pci_msi_controller,
|
||||
.handler = handle_edge_irq,
|
||||
.handler_name = "edge",
|
||||
};
|
||||
|
||||
void arch_init_msi_domain(struct irq_domain *parent)
|
||||
{
|
||||
if (disable_apic)
|
||||
return;
|
||||
|
||||
msi_default_domain = pci_msi_create_irq_domain(NULL,
|
||||
&pci_msi_domain_info, parent);
|
||||
if (!msi_default_domain)
|
||||
pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
static struct irq_chip pci_msi_ir_controller = {
|
||||
.name = "IR-PCI-MSI",
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
int arch_setup_dmar_msi(unsigned int irq)
|
||||
{
|
||||
int ret;
|
||||
struct msi_msg msg;
|
||||
static struct msi_domain_info pci_msi_ir_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
|
||||
.ops = &pci_msi_domain_ops,
|
||||
.chip = &pci_msi_ir_controller,
|
||||
.handler = handle_edge_irq,
|
||||
.handler_name = "edge",
|
||||
};
|
||||
|
||||
struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
|
||||
{
|
||||
return pci_msi_create_irq_domain(NULL, &pci_msi_ir_domain_info, parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DMAR_TABLE
|
||||
static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
dmar_msi_write(data->irq, msg);
|
||||
}
|
||||
|
||||
static struct irq_chip dmar_msi_controller = {
|
||||
.name = "DMAR-MSI",
|
||||
.irq_unmask = dmar_msi_unmask,
|
||||
.irq_mask = dmar_msi_mask,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_set_affinity = msi_domain_set_affinity,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_compose_msi_msg = irq_msi_compose_msg,
|
||||
.irq_write_msi_msg = dmar_msi_write_msg,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info,
|
||||
msi_alloc_info_t *arg)
|
||||
{
|
||||
return arg->dmar_id;
|
||||
}
|
||||
|
||||
static int dmar_msi_init(struct irq_domain *domain,
|
||||
struct msi_domain_info *info, unsigned int virq,
|
||||
irq_hw_number_t hwirq, msi_alloc_info_t *arg)
|
||||
{
|
||||
irq_domain_set_info(domain, virq, arg->dmar_id, info->chip, NULL,
|
||||
handle_edge_irq, arg->dmar_data, "edge");
|
||||
|
||||
ret = msi_compose_msg(NULL, irq, &msg, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dmar_msi_write(irq, &msg);
|
||||
irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
|
||||
"edge");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msi_domain_ops dmar_msi_domain_ops = {
|
||||
.get_hwirq = dmar_msi_get_hwirq,
|
||||
.msi_init = dmar_msi_init,
|
||||
};
|
||||
|
||||
static struct msi_domain_info dmar_msi_domain_info = {
|
||||
.ops = &dmar_msi_domain_ops,
|
||||
.chip = &dmar_msi_controller,
|
||||
};
|
||||
|
||||
static struct irq_domain *dmar_get_irq_domain(void)
|
||||
{
|
||||
static struct irq_domain *dmar_domain;
|
||||
static DEFINE_MUTEX(dmar_lock);
|
||||
|
||||
mutex_lock(&dmar_lock);
|
||||
if (dmar_domain == NULL)
|
||||
dmar_domain = msi_create_irq_domain(NULL, &dmar_msi_domain_info,
|
||||
x86_vector_domain);
|
||||
mutex_unlock(&dmar_lock);
|
||||
|
||||
return dmar_domain;
|
||||
}
|
||||
|
||||
int dmar_alloc_hwirq(int id, int node, void *arg)
|
||||
{
|
||||
struct irq_domain *domain = dmar_get_irq_domain();
|
||||
struct irq_alloc_info info;
|
||||
|
||||
if (!domain)
|
||||
return -1;
|
||||
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.type = X86_IRQ_ALLOC_TYPE_DMAR;
|
||||
info.dmar_id = id;
|
||||
info.dmar_data = arg;
|
||||
|
||||
return irq_domain_alloc_irqs(domain, 1, node, &info);
|
||||
}
|
||||
|
||||
void dmar_free_hwirq(int irq)
|
||||
{
|
||||
irq_domain_free_irqs(irq, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MSI message composition
|
||||
*/
|
||||
#ifdef CONFIG_HPET_TIMER
|
||||
|
||||
static int hpet_msi_set_affinity(struct irq_data *data,
|
||||
const struct cpumask *mask, bool force)
|
||||
static inline int hpet_dev_id(struct irq_domain *domain)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct msi_msg msg;
|
||||
unsigned int dest;
|
||||
int ret;
|
||||
struct msi_domain_info *info = msi_get_domain_info(domain);
|
||||
|
||||
ret = apic_set_affinity(data, mask, &dest);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hpet_msi_read(data->handler_data, &msg);
|
||||
|
||||
msg.data &= ~MSI_DATA_VECTOR_MASK;
|
||||
msg.data |= MSI_DATA_VECTOR(cfg->vector);
|
||||
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
|
||||
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
|
||||
|
||||
hpet_msi_write(data->handler_data, &msg);
|
||||
|
||||
return IRQ_SET_MASK_OK_NOCOPY;
|
||||
return (int)(long)info->data;
|
||||
}
|
||||
|
||||
static struct irq_chip hpet_msi_type = {
|
||||
.name = "HPET_MSI",
|
||||
static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
hpet_msi_write(data->handler_data, msg);
|
||||
}
|
||||
|
||||
static struct irq_chip hpet_msi_controller = {
|
||||
.name = "HPET-MSI",
|
||||
.irq_unmask = hpet_msi_unmask,
|
||||
.irq_mask = hpet_msi_mask,
|
||||
.irq_ack = apic_ack_edge,
|
||||
.irq_set_affinity = hpet_msi_set_affinity,
|
||||
.irq_retrigger = apic_retrigger_irq,
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_set_affinity = msi_domain_set_affinity,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_compose_msi_msg = irq_msi_compose_msg,
|
||||
.irq_write_msi_msg = hpet_msi_write_msg,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
int default_setup_hpet_msi(unsigned int irq, unsigned int id)
|
||||
static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info,
|
||||
msi_alloc_info_t *arg)
|
||||
{
|
||||
struct irq_chip *chip = &hpet_msi_type;
|
||||
struct msi_msg msg;
|
||||
int ret;
|
||||
return arg->hpet_index;
|
||||
}
|
||||
|
||||
ret = msi_compose_msg(NULL, irq, &msg, id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
static int hpet_msi_init(struct irq_domain *domain,
|
||||
struct msi_domain_info *info, unsigned int virq,
|
||||
irq_hw_number_t hwirq, msi_alloc_info_t *arg)
|
||||
{
|
||||
irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
|
||||
irq_domain_set_info(domain, virq, arg->hpet_index, info->chip, NULL,
|
||||
handle_edge_irq, arg->hpet_data, "edge");
|
||||
|
||||
hpet_msi_write(irq_get_handler_data(irq), &msg);
|
||||
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
|
||||
setup_remapped_irq(irq, irq_cfg(irq), chip);
|
||||
|
||||
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hpet_msi_free(struct irq_domain *domain,
|
||||
struct msi_domain_info *info, unsigned int virq)
|
||||
{
|
||||
irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
|
||||
}
|
||||
|
||||
static struct msi_domain_ops hpet_msi_domain_ops = {
|
||||
.get_hwirq = hpet_msi_get_hwirq,
|
||||
.msi_init = hpet_msi_init,
|
||||
.msi_free = hpet_msi_free,
|
||||
};
|
||||
|
||||
static struct msi_domain_info hpet_msi_domain_info = {
|
||||
.ops = &hpet_msi_domain_ops,
|
||||
.chip = &hpet_msi_controller,
|
||||
};
|
||||
|
||||
struct irq_domain *hpet_create_irq_domain(int hpet_id)
|
||||
{
|
||||
struct irq_domain *parent;
|
||||
struct irq_alloc_info info;
|
||||
struct msi_domain_info *domain_info;
|
||||
|
||||
if (x86_vector_domain == NULL)
|
||||
return NULL;
|
||||
|
||||
domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL);
|
||||
if (!domain_info)
|
||||
return NULL;
|
||||
|
||||
*domain_info = hpet_msi_domain_info;
|
||||
domain_info->data = (void *)(long)hpet_id;
|
||||
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.type = X86_IRQ_ALLOC_TYPE_HPET;
|
||||
info.hpet_id = hpet_id;
|
||||
parent = irq_remapping_get_ir_irq_domain(&info);
|
||||
if (parent == NULL)
|
||||
parent = x86_vector_domain;
|
||||
else
|
||||
hpet_msi_controller.name = "IR-HPET-MSI";
|
||||
|
||||
return msi_create_irq_domain(NULL, domain_info, parent);
|
||||
}
|
||||
|
||||
int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
|
||||
int dev_num)
|
||||
{
|
||||
struct irq_alloc_info info;
|
||||
|
||||
init_irq_alloc_info(&info, NULL);
|
||||
info.type = X86_IRQ_ALLOC_TYPE_HPET;
|
||||
info.hpet_data = dev;
|
||||
info.hpet_id = hpet_dev_id(domain);
|
||||
info.hpet_index = dev_num;
|
||||
|
||||
return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
|
||||
}
|
||||
#endif
|
||||
|
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
|
||||
* Moved from arch/x86/kernel/apic/io_apic.c.
|
||||
* Jiang Liu <jiang.liu@linux.intel.com>
|
||||
* Enable support of hierarchical irqdomains
|
||||
*
|
||||
* 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
|
||||
@@ -11,15 +13,28 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/irq_remapping.h>
|
||||
|
||||
struct apic_chip_data {
|
||||
struct irq_cfg cfg;
|
||||
cpumask_var_t domain;
|
||||
cpumask_var_t old_domain;
|
||||
u8 move_in_progress : 1;
|
||||
};
|
||||
|
||||
struct irq_domain *x86_vector_domain;
|
||||
static DEFINE_RAW_SPINLOCK(vector_lock);
|
||||
static cpumask_var_t vector_cpumask;
|
||||
static struct irq_chip lapic_controller;
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
|
||||
#endif
|
||||
|
||||
void lock_vector_lock(void)
|
||||
{
|
||||
@@ -34,71 +49,59 @@ void unlock_vector_lock(void)
|
||||
raw_spin_unlock(&vector_lock);
|
||||
}
|
||||
|
||||
struct irq_cfg *irq_cfg(unsigned int irq)
|
||||
static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
|
||||
{
|
||||
return irq_get_chip_data(irq);
|
||||
if (!irq_data)
|
||||
return NULL;
|
||||
|
||||
while (irq_data->parent_data)
|
||||
irq_data = irq_data->parent_data;
|
||||
|
||||
return irq_data->chip_data;
|
||||
}
|
||||
|
||||
struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
|
||||
{
|
||||
return irq_data->chip_data;
|
||||
struct apic_chip_data *data = apic_chip_data(irq_data);
|
||||
|
||||
return data ? &data->cfg : NULL;
|
||||
}
|
||||
|
||||
static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
|
||||
struct irq_cfg *irq_cfg(unsigned int irq)
|
||||
{
|
||||
struct irq_cfg *cfg;
|
||||
return irqd_cfg(irq_get_irq_data(irq));
|
||||
}
|
||||
|
||||
cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
|
||||
if (!cfg)
|
||||
static struct apic_chip_data *alloc_apic_chip_data(int node)
|
||||
{
|
||||
struct apic_chip_data *data;
|
||||
|
||||
data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
|
||||
if (!data)
|
||||
return NULL;
|
||||
if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
|
||||
goto out_cfg;
|
||||
if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
|
||||
if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
|
||||
goto out_data;
|
||||
if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
|
||||
goto out_domain;
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
INIT_LIST_HEAD(&cfg->irq_2_pin);
|
||||
#endif
|
||||
return cfg;
|
||||
return data;
|
||||
out_domain:
|
||||
free_cpumask_var(cfg->domain);
|
||||
out_cfg:
|
||||
kfree(cfg);
|
||||
free_cpumask_var(data->domain);
|
||||
out_data:
|
||||
kfree(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
|
||||
static void free_apic_chip_data(struct apic_chip_data *data)
|
||||
{
|
||||
int res = irq_alloc_desc_at(at, node);
|
||||
struct irq_cfg *cfg;
|
||||
|
||||
if (res < 0) {
|
||||
if (res != -EEXIST)
|
||||
return NULL;
|
||||
cfg = irq_cfg(at);
|
||||
if (cfg)
|
||||
return cfg;
|
||||
if (data) {
|
||||
free_cpumask_var(data->domain);
|
||||
free_cpumask_var(data->old_domain);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
cfg = alloc_irq_cfg(at, node);
|
||||
if (cfg)
|
||||
irq_set_chip_data(at, cfg);
|
||||
else
|
||||
irq_free_desc(at);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
|
||||
{
|
||||
if (!cfg)
|
||||
return;
|
||||
irq_set_chip_data(at, NULL);
|
||||
free_cpumask_var(cfg->domain);
|
||||
free_cpumask_var(cfg->old_domain);
|
||||
kfree(cfg);
|
||||
}
|
||||
|
||||
static int
|
||||
__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
||||
static int __assign_irq_vector(int irq, struct apic_chip_data *d,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
/*
|
||||
* NOTE! The local APIC isn't very good at handling
|
||||
@@ -114,36 +117,33 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
||||
static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
|
||||
static int current_offset = VECTOR_OFFSET_START % 16;
|
||||
int cpu, err;
|
||||
cpumask_var_t tmp_mask;
|
||||
|
||||
if (cfg->move_in_progress)
|
||||
if (d->move_in_progress)
|
||||
return -EBUSY;
|
||||
|
||||
if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Only try and allocate irqs on cpus that are present */
|
||||
err = -ENOSPC;
|
||||
cpumask_clear(cfg->old_domain);
|
||||
cpumask_clear(d->old_domain);
|
||||
cpu = cpumask_first_and(mask, cpu_online_mask);
|
||||
while (cpu < nr_cpu_ids) {
|
||||
int new_cpu, vector, offset;
|
||||
|
||||
apic->vector_allocation_domain(cpu, tmp_mask, mask);
|
||||
apic->vector_allocation_domain(cpu, vector_cpumask, mask);
|
||||
|
||||
if (cpumask_subset(tmp_mask, cfg->domain)) {
|
||||
if (cpumask_subset(vector_cpumask, d->domain)) {
|
||||
err = 0;
|
||||
if (cpumask_equal(tmp_mask, cfg->domain))
|
||||
if (cpumask_equal(vector_cpumask, d->domain))
|
||||
break;
|
||||
/*
|
||||
* New cpumask using the vector is a proper subset of
|
||||
* the current in use mask. So cleanup the vector
|
||||
* allocation for the members that are not used anymore.
|
||||
*/
|
||||
cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
|
||||
cfg->move_in_progress =
|
||||
cpumask_intersects(cfg->old_domain, cpu_online_mask);
|
||||
cpumask_and(cfg->domain, cfg->domain, tmp_mask);
|
||||
cpumask_andnot(d->old_domain, d->domain,
|
||||
vector_cpumask);
|
||||
d->move_in_progress =
|
||||
cpumask_intersects(d->old_domain, cpu_online_mask);
|
||||
cpumask_and(d->domain, d->domain, vector_cpumask);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -157,16 +157,18 @@ next:
|
||||
}
|
||||
|
||||
if (unlikely(current_vector == vector)) {
|
||||
cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
|
||||
cpumask_andnot(tmp_mask, mask, cfg->old_domain);
|
||||
cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
|
||||
cpumask_or(d->old_domain, d->old_domain,
|
||||
vector_cpumask);
|
||||
cpumask_andnot(vector_cpumask, mask, d->old_domain);
|
||||
cpu = cpumask_first_and(vector_cpumask,
|
||||
cpu_online_mask);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_bit(vector, used_vectors))
|
||||
goto next;
|
||||
|
||||
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
|
||||
for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
|
||||
if (per_cpu(vector_irq, new_cpu)[vector] >
|
||||
VECTOR_UNDEFINED)
|
||||
goto next;
|
||||
@@ -174,55 +176,73 @@ next:
|
||||
/* Found one! */
|
||||
current_vector = vector;
|
||||
current_offset = offset;
|
||||
if (cfg->vector) {
|
||||
cpumask_copy(cfg->old_domain, cfg->domain);
|
||||
cfg->move_in_progress =
|
||||
cpumask_intersects(cfg->old_domain, cpu_online_mask);
|
||||
if (d->cfg.vector) {
|
||||
cpumask_copy(d->old_domain, d->domain);
|
||||
d->move_in_progress =
|
||||
cpumask_intersects(d->old_domain, cpu_online_mask);
|
||||
}
|
||||
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
|
||||
for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
|
||||
per_cpu(vector_irq, new_cpu)[vector] = irq;
|
||||
cfg->vector = vector;
|
||||
cpumask_copy(cfg->domain, tmp_mask);
|
||||
d->cfg.vector = vector;
|
||||
cpumask_copy(d->domain, vector_cpumask);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
free_cpumask_var(tmp_mask);
|
||||
|
||||
if (!err) {
|
||||
/* cache destination APIC IDs into cfg->dest_apicid */
|
||||
err = apic->cpu_mask_to_apicid_and(mask, d->domain,
|
||||
&d->cfg.dest_apicid);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
||||
static int assign_irq_vector(int irq, struct apic_chip_data *data,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||
err = __assign_irq_vector(irq, cfg, mask);
|
||||
err = __assign_irq_vector(irq, data, mask);
|
||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
void clear_irq_vector(int irq, struct irq_cfg *cfg)
|
||||
static int assign_irq_vector_policy(int irq, int node,
|
||||
struct apic_chip_data *data,
|
||||
struct irq_alloc_info *info)
|
||||
{
|
||||
if (info && info->mask)
|
||||
return assign_irq_vector(irq, data, info->mask);
|
||||
if (node != NUMA_NO_NODE &&
|
||||
assign_irq_vector(irq, data, cpumask_of_node(node)) == 0)
|
||||
return 0;
|
||||
return assign_irq_vector(irq, data, apic->target_cpus());
|
||||
}
|
||||
|
||||
static void clear_irq_vector(int irq, struct apic_chip_data *data)
|
||||
{
|
||||
int cpu, vector;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||
BUG_ON(!cfg->vector);
|
||||
BUG_ON(!data->cfg.vector);
|
||||
|
||||
vector = cfg->vector;
|
||||
for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
|
||||
vector = data->cfg.vector;
|
||||
for_each_cpu_and(cpu, data->domain, cpu_online_mask)
|
||||
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
||||
|
||||
cfg->vector = 0;
|
||||
cpumask_clear(cfg->domain);
|
||||
data->cfg.vector = 0;
|
||||
cpumask_clear(data->domain);
|
||||
|
||||
if (likely(!cfg->move_in_progress)) {
|
||||
if (likely(!data->move_in_progress)) {
|
||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
|
||||
for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
|
||||
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
|
||||
vector++) {
|
||||
if (per_cpu(vector_irq, cpu)[vector] != irq)
|
||||
@@ -231,10 +251,95 @@ void clear_irq_vector(int irq, struct irq_cfg *cfg)
|
||||
break;
|
||||
}
|
||||
}
|
||||
cfg->move_in_progress = 0;
|
||||
data->move_in_progress = 0;
|
||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||
}
|
||||
|
||||
void init_irq_alloc_info(struct irq_alloc_info *info,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->mask = mask;
|
||||
}
|
||||
|
||||
void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
|
||||
{
|
||||
if (src)
|
||||
*dst = *src;
|
||||
else
|
||||
memset(dst, 0, sizeof(*dst));
|
||||
}
|
||||
|
||||
static void x86_vector_free_irqs(struct irq_domain *domain,
|
||||
unsigned int virq, unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *irq_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
|
||||
if (irq_data && irq_data->chip_data) {
|
||||
clear_irq_vector(virq + i, irq_data->chip_data);
|
||||
free_apic_chip_data(irq_data->chip_data);
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
if (virq + i < nr_legacy_irqs())
|
||||
legacy_irq_data[virq + i] = NULL;
|
||||
#endif
|
||||
irq_domain_reset_irq_data(irq_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct irq_alloc_info *info = arg;
|
||||
struct apic_chip_data *data;
|
||||
struct irq_data *irq_data;
|
||||
int i, err;
|
||||
|
||||
if (disable_apic)
|
||||
return -ENXIO;
|
||||
|
||||
/* Currently vector allocator can't guarantee contiguous allocations */
|
||||
if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
|
||||
return -ENOSYS;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
irq_data = irq_domain_get_irq_data(domain, virq + i);
|
||||
BUG_ON(!irq_data);
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
|
||||
data = legacy_irq_data[virq + i];
|
||||
else
|
||||
#endif
|
||||
data = alloc_apic_chip_data(irq_data->node);
|
||||
if (!data) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
irq_data->chip = &lapic_controller;
|
||||
irq_data->chip_data = data;
|
||||
irq_data->hwirq = virq + i;
|
||||
err = assign_irq_vector_policy(virq, irq_data->node, data,
|
||||
info);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
x86_vector_free_irqs(domain, virq, i + 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops x86_vector_domain_ops = {
|
||||
.alloc = x86_vector_alloc_irqs,
|
||||
.free = x86_vector_free_irqs,
|
||||
};
|
||||
|
||||
int __init arch_probe_nr_irqs(void)
|
||||
{
|
||||
int nr;
|
||||
@@ -258,8 +363,43 @@ int __init arch_probe_nr_irqs(void)
|
||||
return nr_legacy_irqs();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
static void init_legacy_irqs(void)
|
||||
{
|
||||
int i, node = cpu_to_node(0);
|
||||
struct apic_chip_data *data;
|
||||
|
||||
/*
|
||||
* For legacy IRQ's, start with assigning irq0 to irq15 to
|
||||
* ISA_IRQ_VECTOR(i) for all cpu's.
|
||||
*/
|
||||
for (i = 0; i < nr_legacy_irqs(); i++) {
|
||||
data = legacy_irq_data[i] = alloc_apic_chip_data(node);
|
||||
BUG_ON(!data);
|
||||
|
||||
data->cfg.vector = ISA_IRQ_VECTOR(i);
|
||||
cpumask_setall(data->domain);
|
||||
irq_set_chip_data(i, data);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void init_legacy_irqs(void) { }
|
||||
#endif
|
||||
|
||||
int __init arch_early_irq_init(void)
|
||||
{
|
||||
init_legacy_irqs();
|
||||
|
||||
x86_vector_domain = irq_domain_add_tree(NULL, &x86_vector_domain_ops,
|
||||
NULL);
|
||||
BUG_ON(x86_vector_domain == NULL);
|
||||
irq_set_default_host(x86_vector_domain);
|
||||
|
||||
arch_init_msi_domain(x86_vector_domain);
|
||||
arch_init_htirq_domain(x86_vector_domain);
|
||||
|
||||
BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
|
||||
|
||||
return arch_early_ioapic_init();
|
||||
}
|
||||
|
||||
@@ -267,7 +407,7 @@ static void __setup_vector_irq(int cpu)
|
||||
{
|
||||
/* Initialize vector_irq on a new cpu */
|
||||
int irq, vector;
|
||||
struct irq_cfg *cfg;
|
||||
struct apic_chip_data *data;
|
||||
|
||||
/*
|
||||
* vector_lock will make sure that we don't run into irq vector
|
||||
@@ -277,13 +417,13 @@ static void __setup_vector_irq(int cpu)
|
||||
raw_spin_lock(&vector_lock);
|
||||
/* Mark the inuse vectors */
|
||||
for_each_active_irq(irq) {
|
||||
cfg = irq_cfg(irq);
|
||||
if (!cfg)
|
||||
data = apic_chip_data(irq_get_irq_data(irq));
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
if (!cpumask_test_cpu(cpu, cfg->domain))
|
||||
if (!cpumask_test_cpu(cpu, data->domain))
|
||||
continue;
|
||||
vector = cfg->vector;
|
||||
vector = data->cfg.vector;
|
||||
per_cpu(vector_irq, cpu)[vector] = irq;
|
||||
}
|
||||
/* Mark the free vectors */
|
||||
@@ -292,8 +432,8 @@ static void __setup_vector_irq(int cpu)
|
||||
if (irq <= VECTOR_UNDEFINED)
|
||||
continue;
|
||||
|
||||
cfg = irq_cfg(irq);
|
||||
if (!cpumask_test_cpu(cpu, cfg->domain))
|
||||
data = apic_chip_data(irq_get_irq_data(irq));
|
||||
if (!cpumask_test_cpu(cpu, data->domain))
|
||||
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
||||
}
|
||||
raw_spin_unlock(&vector_lock);
|
||||
@@ -314,20 +454,20 @@ void setup_vector_irq(int cpu)
|
||||
* legacy vector to irq mapping:
|
||||
*/
|
||||
for (irq = 0; irq < nr_legacy_irqs(); irq++)
|
||||
per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq;
|
||||
per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq;
|
||||
|
||||
__setup_vector_irq(cpu);
|
||||
}
|
||||
|
||||
int apic_retrigger_irq(struct irq_data *data)
|
||||
static int apic_retrigger_irq(struct irq_data *irq_data)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct apic_chip_data *data = apic_chip_data(irq_data);
|
||||
unsigned long flags;
|
||||
int cpu;
|
||||
|
||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||
cpu = cpumask_first_and(cfg->domain, cpu_online_mask);
|
||||
apic->send_IPI_mask(cpumask_of(cpu), cfg->vector);
|
||||
cpu = cpumask_first_and(data->domain, cpu_online_mask);
|
||||
apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
|
||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||
|
||||
return 1;
|
||||
@@ -340,73 +480,76 @@ void apic_ack_edge(struct irq_data *data)
|
||||
ack_APIC_irq();
|
||||
}
|
||||
|
||||
/*
|
||||
* Either sets data->affinity to a valid value, and returns
|
||||
* ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
|
||||
* leaves data->affinity untouched.
|
||||
*/
|
||||
int apic_set_affinity(struct irq_data *data, const struct cpumask *mask,
|
||||
unsigned int *dest_id)
|
||||
static int apic_set_affinity(struct irq_data *irq_data,
|
||||
const struct cpumask *dest, bool force)
|
||||
{
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
unsigned int irq = data->irq;
|
||||
int err;
|
||||
struct apic_chip_data *data = irq_data->chip_data;
|
||||
int err, irq = irq_data->irq;
|
||||
|
||||
if (!config_enabled(CONFIG_SMP))
|
||||
return -EPERM;
|
||||
|
||||
if (!cpumask_intersects(mask, cpu_online_mask))
|
||||
if (!cpumask_intersects(dest, cpu_online_mask))
|
||||
return -EINVAL;
|
||||
|
||||
err = assign_irq_vector(irq, cfg, mask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
|
||||
err = assign_irq_vector(irq, data, dest);
|
||||
if (err) {
|
||||
if (assign_irq_vector(irq, cfg, data->affinity))
|
||||
struct irq_data *top = irq_get_irq_data(irq);
|
||||
|
||||
if (assign_irq_vector(irq, data, top->affinity))
|
||||
pr_err("Failed to recover vector for irq %d\n", irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
cpumask_copy(data->affinity, mask);
|
||||
|
||||
return 0;
|
||||
return IRQ_SET_MASK_OK;
|
||||
}
|
||||
|
||||
static struct irq_chip lapic_controller = {
|
||||
.irq_ack = apic_ack_edge,
|
||||
.irq_set_affinity = apic_set_affinity,
|
||||
.irq_retrigger = apic_retrigger_irq,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void send_cleanup_vector(struct irq_cfg *cfg)
|
||||
static void __send_cleanup_vector(struct apic_chip_data *data)
|
||||
{
|
||||
cpumask_var_t cleanup_mask;
|
||||
|
||||
if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
|
||||
unsigned int i;
|
||||
|
||||
for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
||||
for_each_cpu_and(i, data->old_domain, cpu_online_mask)
|
||||
apic->send_IPI_mask(cpumask_of(i),
|
||||
IRQ_MOVE_CLEANUP_VECTOR);
|
||||
} else {
|
||||
cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
|
||||
cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask);
|
||||
apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
|
||||
free_cpumask_var(cleanup_mask);
|
||||
}
|
||||
cfg->move_in_progress = 0;
|
||||
data->move_in_progress = 0;
|
||||
}
|
||||
|
||||
void send_cleanup_vector(struct irq_cfg *cfg)
|
||||
{
|
||||
struct apic_chip_data *data;
|
||||
|
||||
data = container_of(cfg, struct apic_chip_data, cfg);
|
||||
if (data->move_in_progress)
|
||||
__send_cleanup_vector(data);
|
||||
}
|
||||
|
||||
asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
||||
{
|
||||
unsigned vector, me;
|
||||
|
||||
ack_APIC_irq();
|
||||
irq_enter();
|
||||
exit_idle();
|
||||
entering_ack_irq();
|
||||
|
||||
me = smp_processor_id();
|
||||
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
|
||||
int irq;
|
||||
unsigned int irr;
|
||||
struct irq_desc *desc;
|
||||
struct irq_cfg *cfg;
|
||||
struct apic_chip_data *data;
|
||||
|
||||
irq = __this_cpu_read(vector_irq[vector]);
|
||||
|
||||
@@ -417,8 +560,8 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
||||
if (!desc)
|
||||
continue;
|
||||
|
||||
cfg = irq_cfg(irq);
|
||||
if (!cfg)
|
||||
data = apic_chip_data(&desc->irq_data);
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
raw_spin_lock(&desc->lock);
|
||||
@@ -427,10 +570,11 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
||||
* Check if the irq migration is in progress. If so, we
|
||||
* haven't received the cleanup request yet for this irq.
|
||||
*/
|
||||
if (cfg->move_in_progress)
|
||||
if (data->move_in_progress)
|
||||
goto unlock;
|
||||
|
||||
if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
|
||||
if (vector == data->cfg.vector &&
|
||||
cpumask_test_cpu(me, data->domain))
|
||||
goto unlock;
|
||||
|
||||
irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
|
||||
@@ -450,20 +594,21 @@ unlock:
|
||||
raw_spin_unlock(&desc->lock);
|
||||
}
|
||||
|
||||
irq_exit();
|
||||
exiting_irq();
|
||||
}
|
||||
|
||||
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
|
||||
{
|
||||
unsigned me;
|
||||
struct apic_chip_data *data;
|
||||
|
||||
if (likely(!cfg->move_in_progress))
|
||||
data = container_of(cfg, struct apic_chip_data, cfg);
|
||||
if (likely(!data->move_in_progress))
|
||||
return;
|
||||
|
||||
me = smp_processor_id();
|
||||
|
||||
if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
|
||||
send_cleanup_vector(cfg);
|
||||
if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
|
||||
__send_cleanup_vector(data);
|
||||
}
|
||||
|
||||
void irq_complete_move(struct irq_cfg *cfg)
|
||||
@@ -475,46 +620,11 @@ void irq_force_complete_move(int irq)
|
||||
{
|
||||
struct irq_cfg *cfg = irq_cfg(irq);
|
||||
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
__irq_complete_move(cfg, cfg->vector);
|
||||
if (cfg)
|
||||
__irq_complete_move(cfg, cfg->vector);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dynamic irq allocate and deallocation. Should be replaced by irq domains!
|
||||
*/
|
||||
int arch_setup_hwirq(unsigned int irq, int node)
|
||||
{
|
||||
struct irq_cfg *cfg;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
cfg = alloc_irq_cfg(irq, node);
|
||||
if (!cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||
ret = __assign_irq_vector(irq, cfg, apic->target_cpus());
|
||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||
|
||||
if (!ret)
|
||||
irq_set_chip_data(irq, cfg);
|
||||
else
|
||||
free_irq_cfg(irq, cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arch_teardown_hwirq(unsigned int irq)
|
||||
{
|
||||
struct irq_cfg *cfg = irq_cfg(irq);
|
||||
|
||||
free_remapped_irq(irq);
|
||||
clear_irq_vector(irq, cfg);
|
||||
free_irq_cfg(irq, cfg);
|
||||
}
|
||||
|
||||
static void __init print_APIC_field(int base)
|
||||
{
|
||||
int i;
|
||||
|
@@ -21,11 +21,13 @@ early_param("x2apic_phys", set_x2apic_phys_mode);
|
||||
|
||||
static bool x2apic_fadt_phys(void)
|
||||
{
|
||||
#ifdef CONFIG_ACPI
|
||||
if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
|
||||
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
|
||||
printk(KERN_DEBUG "System requires x2apic physical mode\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,25 @@ void common(void) {
|
||||
OFFSET(pbe_orig_address, pbe, orig_address);
|
||||
OFFSET(pbe_next, pbe, next);
|
||||
|
||||
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
|
||||
BLANK();
|
||||
OFFSET(IA32_SIGCONTEXT_ax, sigcontext_ia32, ax);
|
||||
OFFSET(IA32_SIGCONTEXT_bx, sigcontext_ia32, bx);
|
||||
OFFSET(IA32_SIGCONTEXT_cx, sigcontext_ia32, cx);
|
||||
OFFSET(IA32_SIGCONTEXT_dx, sigcontext_ia32, dx);
|
||||
OFFSET(IA32_SIGCONTEXT_si, sigcontext_ia32, si);
|
||||
OFFSET(IA32_SIGCONTEXT_di, sigcontext_ia32, di);
|
||||
OFFSET(IA32_SIGCONTEXT_bp, sigcontext_ia32, bp);
|
||||
OFFSET(IA32_SIGCONTEXT_sp, sigcontext_ia32, sp);
|
||||
OFFSET(IA32_SIGCONTEXT_ip, sigcontext_ia32, ip);
|
||||
|
||||
BLANK();
|
||||
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
|
||||
|
||||
BLANK();
|
||||
OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
BLANK();
|
||||
OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled);
|
||||
@@ -49,7 +68,9 @@ void common(void) {
|
||||
OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
|
||||
OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
|
||||
OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
|
||||
#ifdef CONFIG_X86_32
|
||||
OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
|
||||
#endif
|
||||
OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
|
||||
OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
|
||||
#endif
|
||||
|
@@ -17,17 +17,6 @@ void foo(void);
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
OFFSET(IA32_SIGCONTEXT_ax, sigcontext, ax);
|
||||
OFFSET(IA32_SIGCONTEXT_bx, sigcontext, bx);
|
||||
OFFSET(IA32_SIGCONTEXT_cx, sigcontext, cx);
|
||||
OFFSET(IA32_SIGCONTEXT_dx, sigcontext, dx);
|
||||
OFFSET(IA32_SIGCONTEXT_si, sigcontext, si);
|
||||
OFFSET(IA32_SIGCONTEXT_di, sigcontext, di);
|
||||
OFFSET(IA32_SIGCONTEXT_bp, sigcontext, bp);
|
||||
OFFSET(IA32_SIGCONTEXT_sp, sigcontext, sp);
|
||||
OFFSET(IA32_SIGCONTEXT_ip, sigcontext, ip);
|
||||
BLANK();
|
||||
|
||||
OFFSET(CPUINFO_x86, cpuinfo_x86, x86);
|
||||
OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
|
||||
OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
|
||||
@@ -37,10 +26,6 @@ void foo(void)
|
||||
OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
|
||||
BLANK();
|
||||
|
||||
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
|
||||
OFFSET(TI_cpu, thread_info, cpu);
|
||||
BLANK();
|
||||
|
||||
OFFSET(PT_EBX, pt_regs, bx);
|
||||
OFFSET(PT_ECX, pt_regs, cx);
|
||||
OFFSET(PT_EDX, pt_regs, dx);
|
||||
@@ -60,9 +45,6 @@ void foo(void)
|
||||
OFFSET(PT_OLDSS, pt_regs, ss);
|
||||
BLANK();
|
||||
|
||||
OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
|
||||
BLANK();
|
||||
|
||||
OFFSET(saved_context_gdt_desc, saved_context, gdt_desc);
|
||||
BLANK();
|
||||
|
||||
|
@@ -29,27 +29,6 @@ int main(void)
|
||||
BLANK();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
|
||||
BLANK();
|
||||
|
||||
#define ENTRY(entry) OFFSET(IA32_SIGCONTEXT_ ## entry, sigcontext_ia32, entry)
|
||||
ENTRY(ax);
|
||||
ENTRY(bx);
|
||||
ENTRY(cx);
|
||||
ENTRY(dx);
|
||||
ENTRY(si);
|
||||
ENTRY(di);
|
||||
ENTRY(bp);
|
||||
ENTRY(sp);
|
||||
ENTRY(ip);
|
||||
BLANK();
|
||||
#undef ENTRY
|
||||
|
||||
OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
|
||||
BLANK();
|
||||
#endif
|
||||
|
||||
#define ENTRY(entry) OFFSET(pt_regs_ ## entry, pt_regs, entry)
|
||||
ENTRY(bx);
|
||||
ENTRY(cx);
|
||||
|
@@ -1155,10 +1155,6 @@ static __init int setup_disablecpuid(char *arg)
|
||||
}
|
||||
__setup("clearcpuid=", setup_disablecpuid);
|
||||
|
||||
DEFINE_PER_CPU(unsigned long, kernel_stack) =
|
||||
(unsigned long)&init_thread_union + THREAD_SIZE;
|
||||
EXPORT_PER_CPU_SYMBOL(kernel_stack);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
|
||||
struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
|
||||
|
@@ -39,14 +39,12 @@ void hyperv_vector_handler(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
irq_enter();
|
||||
exit_idle();
|
||||
|
||||
entering_irq();
|
||||
inc_irq_stat(irq_hv_callback_count);
|
||||
if (vmbus_handler)
|
||||
vmbus_handler();
|
||||
|
||||
irq_exit();
|
||||
exiting_irq();
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
|
@@ -98,7 +98,8 @@ x86_get_mtrr_mem_range(struct range *range, int nr_range,
|
||||
continue;
|
||||
base = range_state[i].base_pfn;
|
||||
if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
|
||||
(mtrr_state.enabled & 1)) {
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
|
||||
/* Var MTRR contains UC entry below 1M? Skip it: */
|
||||
printk(BIOS_BUG_MSG, i);
|
||||
if (base + size <= (1<<(20-PAGE_SHIFT)))
|
||||
|
@@ -102,59 +102,76 @@ static int check_type_overlap(u8 *prev, u8 *curr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error/Semi-error returns:
|
||||
* 0xFF - when MTRR is not enabled
|
||||
* *repeat == 1 implies [start:end] spanned across MTRR range and type returned
|
||||
* corresponds only to [start:*partial_end].
|
||||
* Caller has to lookup again for [*partial_end:end].
|
||||
/**
|
||||
* mtrr_type_lookup_fixed - look up memory type in MTRR fixed entries
|
||||
*
|
||||
* Return the MTRR fixed memory type of 'start'.
|
||||
*
|
||||
* MTRR fixed entries are divided into the following ways:
|
||||
* 0x00000 - 0x7FFFF : This range is divided into eight 64KB sub-ranges
|
||||
* 0x80000 - 0xBFFFF : This range is divided into sixteen 16KB sub-ranges
|
||||
* 0xC0000 - 0xFFFFF : This range is divided into sixty-four 4KB sub-ranges
|
||||
*
|
||||
* Return Values:
|
||||
* MTRR_TYPE_(type) - Matched memory type
|
||||
* MTRR_TYPE_INVALID - Unmatched
|
||||
*/
|
||||
static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
|
||||
static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (start >= 0x100000)
|
||||
return MTRR_TYPE_INVALID;
|
||||
|
||||
/* 0x0 - 0x7FFFF */
|
||||
if (start < 0x80000) {
|
||||
idx = 0;
|
||||
idx += (start >> 16);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
/* 0x80000 - 0xBFFFF */
|
||||
} else if (start < 0xC0000) {
|
||||
idx = 1 * 8;
|
||||
idx += ((start - 0x80000) >> 14);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
}
|
||||
|
||||
/* 0xC0000 - 0xFFFFF */
|
||||
idx = 3 * 8;
|
||||
idx += ((start - 0xC0000) >> 12);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* mtrr_type_lookup_variable - look up memory type in MTRR variable entries
|
||||
*
|
||||
* Return Value:
|
||||
* MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
|
||||
*
|
||||
* Output Arguments:
|
||||
* repeat - Set to 1 when [start:end] spanned across MTRR range and type
|
||||
* returned corresponds only to [start:*partial_end]. Caller has
|
||||
* to lookup again for [*partial_end:end].
|
||||
*
|
||||
* uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
|
||||
* region is fully covered by a single MTRR entry or the default
|
||||
* type.
|
||||
*/
|
||||
static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
|
||||
int *repeat, u8 *uniform)
|
||||
{
|
||||
int i;
|
||||
u64 base, mask;
|
||||
u8 prev_match, curr_match;
|
||||
|
||||
*repeat = 0;
|
||||
if (!mtrr_state_set)
|
||||
return 0xFF;
|
||||
*uniform = 1;
|
||||
|
||||
if (!mtrr_state.enabled)
|
||||
return 0xFF;
|
||||
|
||||
/* Make end inclusive end, instead of exclusive */
|
||||
/* Make end inclusive instead of exclusive */
|
||||
end--;
|
||||
|
||||
/* Look in fixed ranges. Just return the type as per start */
|
||||
if (mtrr_state.have_fixed && (start < 0x100000)) {
|
||||
int idx;
|
||||
|
||||
if (start < 0x80000) {
|
||||
idx = 0;
|
||||
idx += (start >> 16);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
} else if (start < 0xC0000) {
|
||||
idx = 1 * 8;
|
||||
idx += ((start - 0x80000) >> 14);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
} else if (start < 0x1000000) {
|
||||
idx = 3 * 8;
|
||||
idx += ((start - 0xC0000) >> 12);
|
||||
return mtrr_state.fixed_ranges[idx];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look in variable ranges
|
||||
* Look of multiple ranges matching this address and pick type
|
||||
* as per MTRR precedence
|
||||
*/
|
||||
if (!(mtrr_state.enabled & 2))
|
||||
return mtrr_state.def_type;
|
||||
|
||||
prev_match = 0xFF;
|
||||
prev_match = MTRR_TYPE_INVALID;
|
||||
for (i = 0; i < num_var_ranges; ++i) {
|
||||
unsigned short start_state, end_state;
|
||||
unsigned short start_state, end_state, inclusive;
|
||||
|
||||
if (!(mtrr_state.var_ranges[i].mask_lo & (1 << 11)))
|
||||
continue;
|
||||
@@ -166,20 +183,29 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
|
||||
|
||||
start_state = ((start & mask) == (base & mask));
|
||||
end_state = ((end & mask) == (base & mask));
|
||||
inclusive = ((start < base) && (end > base));
|
||||
|
||||
if (start_state != end_state) {
|
||||
if ((start_state != end_state) || inclusive) {
|
||||
/*
|
||||
* We have start:end spanning across an MTRR.
|
||||
* We split the region into
|
||||
* either
|
||||
* (start:mtrr_end) (mtrr_end:end)
|
||||
* or
|
||||
* (start:mtrr_start) (mtrr_start:end)
|
||||
* We split the region into either
|
||||
*
|
||||
* - start_state:1
|
||||
* (start:mtrr_end)(mtrr_end:end)
|
||||
* - end_state:1
|
||||
* (start:mtrr_start)(mtrr_start:end)
|
||||
* - inclusive:1
|
||||
* (start:mtrr_start)(mtrr_start:mtrr_end)(mtrr_end:end)
|
||||
*
|
||||
* depending on kind of overlap.
|
||||
* Return the type for first region and a pointer to
|
||||
* the start of second region so that caller will
|
||||
* lookup again on the second region.
|
||||
* Note: This way we handle multiple overlaps as well.
|
||||
*
|
||||
* Return the type of the first region and a pointer
|
||||
* to the start of next region so that caller will be
|
||||
* advised to lookup again after having adjusted start
|
||||
* and end.
|
||||
*
|
||||
* Note: This way we handle overlaps with multiple
|
||||
* entries and the default type properly.
|
||||
*/
|
||||
if (start_state)
|
||||
*partial_end = base + get_mtrr_size(mask);
|
||||
@@ -193,59 +219,94 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
|
||||
|
||||
end = *partial_end - 1; /* end is inclusive */
|
||||
*repeat = 1;
|
||||
*uniform = 0;
|
||||
}
|
||||
|
||||
if ((start & mask) != (base & mask))
|
||||
continue;
|
||||
|
||||
curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
|
||||
if (prev_match == 0xFF) {
|
||||
if (prev_match == MTRR_TYPE_INVALID) {
|
||||
prev_match = curr_match;
|
||||
continue;
|
||||
}
|
||||
|
||||
*uniform = 0;
|
||||
if (check_type_overlap(&prev_match, &curr_match))
|
||||
return curr_match;
|
||||
}
|
||||
|
||||
if (mtrr_tom2) {
|
||||
if (start >= (1ULL<<32) && (end < mtrr_tom2))
|
||||
return MTRR_TYPE_WRBACK;
|
||||
}
|
||||
|
||||
if (prev_match != 0xFF)
|
||||
if (prev_match != MTRR_TYPE_INVALID)
|
||||
return prev_match;
|
||||
|
||||
return mtrr_state.def_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the effective MTRR type for the region
|
||||
* Error return:
|
||||
* 0xFF - when MTRR is not enabled
|
||||
/**
|
||||
* mtrr_type_lookup - look up memory type in MTRR
|
||||
*
|
||||
* Return Values:
|
||||
* MTRR_TYPE_(type) - The effective MTRR type for the region
|
||||
* MTRR_TYPE_INVALID - MTRR is disabled
|
||||
*
|
||||
* Output Argument:
|
||||
* uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
|
||||
* region is fully covered by a single MTRR entry or the default
|
||||
* type.
|
||||
*/
|
||||
u8 mtrr_type_lookup(u64 start, u64 end)
|
||||
u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform)
|
||||
{
|
||||
u8 type, prev_type;
|
||||
u8 type, prev_type, is_uniform = 1, dummy;
|
||||
int repeat;
|
||||
u64 partial_end;
|
||||
|
||||
type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
|
||||
if (!mtrr_state_set)
|
||||
return MTRR_TYPE_INVALID;
|
||||
|
||||
if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
|
||||
return MTRR_TYPE_INVALID;
|
||||
|
||||
/*
|
||||
* Look up the fixed ranges first, which take priority over
|
||||
* the variable ranges.
|
||||
*/
|
||||
if ((start < 0x100000) &&
|
||||
(mtrr_state.have_fixed) &&
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
|
||||
is_uniform = 0;
|
||||
type = mtrr_type_lookup_fixed(start, end);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the variable ranges. Look of multiple ranges matching
|
||||
* this address and pick type as per MTRR precedence.
|
||||
*/
|
||||
type = mtrr_type_lookup_variable(start, end, &partial_end,
|
||||
&repeat, &is_uniform);
|
||||
|
||||
/*
|
||||
* Common path is with repeat = 0.
|
||||
* However, we can have cases where [start:end] spans across some
|
||||
* MTRR range. Do repeated lookups for that case here.
|
||||
* MTRR ranges and/or the default type. Do repeated lookups for
|
||||
* that case here.
|
||||
*/
|
||||
while (repeat) {
|
||||
prev_type = type;
|
||||
start = partial_end;
|
||||
type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
|
||||
is_uniform = 0;
|
||||
type = mtrr_type_lookup_variable(start, end, &partial_end,
|
||||
&repeat, &dummy);
|
||||
|
||||
if (check_type_overlap(&prev_type, &type))
|
||||
return type;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
|
||||
type = MTRR_TYPE_WRBACK;
|
||||
|
||||
out:
|
||||
*uniform = is_uniform;
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -347,7 +408,9 @@ static void __init print_mtrr_state(void)
|
||||
mtrr_attrib_to_str(mtrr_state.def_type));
|
||||
if (mtrr_state.have_fixed) {
|
||||
pr_debug("MTRR fixed ranges %sabled:\n",
|
||||
mtrr_state.enabled & 1 ? "en" : "dis");
|
||||
((mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
|
||||
(mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) ?
|
||||
"en" : "dis");
|
||||
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
|
||||
for (i = 0; i < 2; ++i)
|
||||
print_fixed(0x80000 + i * 0x20000, 0x04000,
|
||||
@@ -360,7 +423,7 @@ static void __init print_mtrr_state(void)
|
||||
print_fixed_last();
|
||||
}
|
||||
pr_debug("MTRR variable ranges %sabled:\n",
|
||||
mtrr_state.enabled & 2 ? "en" : "dis");
|
||||
mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED ? "en" : "dis");
|
||||
high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
|
||||
|
||||
for (i = 0; i < num_var_ranges; ++i) {
|
||||
@@ -382,7 +445,7 @@ static void __init print_mtrr_state(void)
|
||||
}
|
||||
|
||||
/* Grab all of the MTRR state for this CPU into *state */
|
||||
void __init get_mtrr_state(void)
|
||||
bool __init get_mtrr_state(void)
|
||||
{
|
||||
struct mtrr_var_range *vrs;
|
||||
unsigned long flags;
|
||||
@@ -426,6 +489,8 @@ void __init get_mtrr_state(void)
|
||||
|
||||
post_set();
|
||||
local_irq_restore(flags);
|
||||
|
||||
return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
|
||||
}
|
||||
|
||||
/* Some BIOS's are messed up and don't set all MTRRs the same! */
|
||||
|
@@ -59,6 +59,12 @@
|
||||
#define MTRR_TO_PHYS_WC_OFFSET 1000
|
||||
|
||||
u32 num_var_ranges;
|
||||
static bool __mtrr_enabled;
|
||||
|
||||
static bool mtrr_enabled(void)
|
||||
{
|
||||
return __mtrr_enabled;
|
||||
}
|
||||
|
||||
unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
|
||||
static DEFINE_MUTEX(mtrr_mutex);
|
||||
@@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
|
||||
int i, replace, error;
|
||||
mtrr_type ltype;
|
||||
|
||||
if (!mtrr_if)
|
||||
if (!mtrr_enabled())
|
||||
return -ENXIO;
|
||||
|
||||
error = mtrr_if->validate_add_page(base, size, type);
|
||||
@@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
|
||||
int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
|
||||
bool increment)
|
||||
{
|
||||
if (!mtrr_enabled())
|
||||
return -ENODEV;
|
||||
if (mtrr_check(base, size))
|
||||
return -EINVAL;
|
||||
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
|
||||
@@ -463,8 +471,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
|
||||
unsigned long lbase, lsize;
|
||||
int error = -EINVAL;
|
||||
|
||||
if (!mtrr_if)
|
||||
return -ENXIO;
|
||||
if (!mtrr_enabled())
|
||||
return -ENODEV;
|
||||
|
||||
max = num_var_ranges;
|
||||
/* No CPU hotplug when we change MTRR entries */
|
||||
@@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
|
||||
*/
|
||||
int mtrr_del(int reg, unsigned long base, unsigned long size)
|
||||
{
|
||||
if (!mtrr_enabled())
|
||||
return -ENODEV;
|
||||
if (mtrr_check(base, size))
|
||||
return -EINVAL;
|
||||
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
|
||||
@@ -538,6 +548,9 @@ EXPORT_SYMBOL(mtrr_del);
|
||||
* attempts to add a WC MTRR covering size bytes starting at base and
|
||||
* logs an error if this fails.
|
||||
*
|
||||
* The called should provide a power of two size on an equivalent
|
||||
* power of two boundary.
|
||||
*
|
||||
* Drivers must store the return value to pass to mtrr_del_wc_if_needed,
|
||||
* but drivers should not try to interpret that return value.
|
||||
*/
|
||||
@@ -545,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pat_enabled)
|
||||
if (pat_enabled() || !mtrr_enabled())
|
||||
return 0; /* Success! (We don't need to do anything.) */
|
||||
|
||||
ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
|
||||
@@ -577,7 +590,7 @@ void arch_phys_wc_del(int handle)
|
||||
EXPORT_SYMBOL(arch_phys_wc_del);
|
||||
|
||||
/*
|
||||
* phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value
|
||||
* arch_phys_wc_index - translates arch_phys_wc_add's return value
|
||||
* @handle: Return value from arch_phys_wc_add
|
||||
*
|
||||
* This will turn the return value from arch_phys_wc_add into an mtrr
|
||||
@@ -587,14 +600,14 @@ EXPORT_SYMBOL(arch_phys_wc_del);
|
||||
* in printk line. Alas there is an illegitimate use in some ancient
|
||||
* drm ioctls.
|
||||
*/
|
||||
int phys_wc_to_mtrr_index(int handle)
|
||||
int arch_phys_wc_index(int handle)
|
||||
{
|
||||
if (handle < MTRR_TO_PHYS_WC_OFFSET)
|
||||
return -1;
|
||||
else
|
||||
return handle - MTRR_TO_PHYS_WC_OFFSET;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index);
|
||||
EXPORT_SYMBOL_GPL(arch_phys_wc_index);
|
||||
|
||||
/*
|
||||
* HACK ALERT!
|
||||
@@ -734,10 +747,12 @@ void __init mtrr_bp_init(void)
|
||||
}
|
||||
|
||||
if (mtrr_if) {
|
||||
__mtrr_enabled = true;
|
||||
set_num_var_ranges();
|
||||
init_table();
|
||||
if (use_intel()) {
|
||||
get_mtrr_state();
|
||||
/* BIOS may override */
|
||||
__mtrr_enabled = get_mtrr_state();
|
||||
|
||||
if (mtrr_cleanup(phys_addr)) {
|
||||
changed_by_mtrr_cleanup = 1;
|
||||
@@ -745,10 +760,16 @@ void __init mtrr_bp_init(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mtrr_enabled())
|
||||
pr_info("MTRR: Disabled\n");
|
||||
}
|
||||
|
||||
void mtrr_ap_init(void)
|
||||
{
|
||||
if (!mtrr_enabled())
|
||||
return;
|
||||
|
||||
if (!use_intel() || mtrr_aps_delayed_init)
|
||||
return;
|
||||
/*
|
||||
@@ -774,6 +795,9 @@ void mtrr_save_state(void)
|
||||
{
|
||||
int first_cpu;
|
||||
|
||||
if (!mtrr_enabled())
|
||||
return;
|
||||
|
||||
get_online_cpus();
|
||||
first_cpu = cpumask_first(cpu_online_mask);
|
||||
smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
|
||||
@@ -782,6 +806,8 @@ void mtrr_save_state(void)
|
||||
|
||||
void set_mtrr_aps_delayed_init(void)
|
||||
{
|
||||
if (!mtrr_enabled())
|
||||
return;
|
||||
if (!use_intel())
|
||||
return;
|
||||
|
||||
@@ -793,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
|
||||
*/
|
||||
void mtrr_aps_init(void)
|
||||
{
|
||||
if (!use_intel())
|
||||
if (!use_intel() || !mtrr_enabled())
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -810,7 +836,7 @@ void mtrr_aps_init(void)
|
||||
|
||||
void mtrr_bp_restore(void)
|
||||
{
|
||||
if (!use_intel())
|
||||
if (!use_intel() || !mtrr_enabled())
|
||||
return;
|
||||
|
||||
mtrr_if->set_all();
|
||||
@@ -818,7 +844,7 @@ void mtrr_bp_restore(void)
|
||||
|
||||
static int __init mtrr_init_finialize(void)
|
||||
{
|
||||
if (!mtrr_if)
|
||||
if (!mtrr_enabled())
|
||||
return 0;
|
||||
|
||||
if (use_intel()) {
|
||||
|
@@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
|
||||
|
||||
void fill_mtrr_var_range(unsigned int index,
|
||||
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
|
||||
void get_mtrr_state(void);
|
||||
bool get_mtrr_state(void);
|
||||
|
||||
extern void set_mtrr_ops(const struct mtrr_ops *ops);
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
@@ -17,6 +16,7 @@
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/initrd.h>
|
||||
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/pci_x86.h>
|
||||
@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] =
|
||||
},
|
||||
};
|
||||
|
||||
static int ioapic_xlate(struct irq_domain *domain,
|
||||
struct device_node *controller,
|
||||
const u32 *intspec, u32 intsize,
|
||||
irq_hw_number_t *out_hwirq, u32 *out_type)
|
||||
static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct of_phandle_args *irq_data = (void *)arg;
|
||||
struct of_ioapic_type *it;
|
||||
u32 line, idx, gsi;
|
||||
struct irq_alloc_info tmp;
|
||||
|
||||
if (WARN_ON(intsize < 2))
|
||||
if (WARN_ON(irq_data->args_count < 2))
|
||||
return -EINVAL;
|
||||
if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
|
||||
return -EINVAL;
|
||||
|
||||
line = intspec[0];
|
||||
it = &of_ioapic_type[irq_data->args[1]];
|
||||
ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
|
||||
tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
|
||||
tmp.ioapic_pin = irq_data->args[0];
|
||||
|
||||
if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
|
||||
return -EINVAL;
|
||||
|
||||
it = &of_ioapic_type[intspec[1]];
|
||||
|
||||
idx = (u32)(long)domain->host_data;
|
||||
gsi = mp_pin_to_gsi(idx, line);
|
||||
if (mp_set_gsi_attr(gsi, it->trigger, it->polarity, cpu_to_node(0)))
|
||||
return -EBUSY;
|
||||
|
||||
*out_hwirq = line;
|
||||
*out_type = it->out_type;
|
||||
return 0;
|
||||
return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
|
||||
}
|
||||
|
||||
const struct irq_domain_ops ioapic_irq_domain_ops = {
|
||||
.map = mp_irqdomain_map,
|
||||
.unmap = mp_irqdomain_unmap,
|
||||
.xlate = ioapic_xlate,
|
||||
static const struct irq_domain_ops ioapic_irq_domain_ops = {
|
||||
.alloc = dt_irqdomain_alloc,
|
||||
.free = mp_irqdomain_free,
|
||||
.activate = mp_irqdomain_activate,
|
||||
.deactivate = mp_irqdomain_deactivate,
|
||||
};
|
||||
|
||||
static void __init dtb_add_ioapic(struct device_node *dn)
|
||||
|
@@ -216,7 +216,7 @@ ENTRY(system_call)
|
||||
GLOBAL(system_call_after_swapgs)
|
||||
|
||||
movq %rsp,PER_CPU_VAR(rsp_scratch)
|
||||
movq PER_CPU_VAR(kernel_stack),%rsp
|
||||
movq PER_CPU_VAR(cpu_current_top_of_stack),%rsp
|
||||
|
||||
/* Construct struct pt_regs on stack */
|
||||
pushq_cfi $__USER_DS /* pt_regs->ss */
|
||||
@@ -419,26 +419,27 @@ syscall_return:
|
||||
* a completely clean 64-bit userspace context.
|
||||
*/
|
||||
movq RCX(%rsp),%rcx
|
||||
cmpq %rcx,RIP(%rsp) /* RCX == RIP */
|
||||
movq RIP(%rsp),%r11
|
||||
cmpq %rcx,%r11 /* RCX == RIP */
|
||||
jne opportunistic_sysret_failed
|
||||
|
||||
/*
|
||||
* On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
|
||||
* in kernel space. This essentially lets the user take over
|
||||
* the kernel, since userspace controls RSP. It's not worth
|
||||
* testing for canonicalness exactly -- this check detects any
|
||||
* of the 17 high bits set, which is true for non-canonical
|
||||
* or kernel addresses. (This will pessimize vsyscall=native.
|
||||
* Big deal.)
|
||||
* the kernel, since userspace controls RSP.
|
||||
*
|
||||
* If virtual addresses ever become wider, this will need
|
||||
* If width of "canonical tail" ever becomes variable, this will need
|
||||
* to be updated to remain correct on both old and new CPUs.
|
||||
*/
|
||||
.ifne __VIRTUAL_MASK_SHIFT - 47
|
||||
.error "virtual address width changed -- SYSRET checks need update"
|
||||
.endif
|
||||
shr $__VIRTUAL_MASK_SHIFT, %rcx
|
||||
jnz opportunistic_sysret_failed
|
||||
/* Change top 16 bits to be the sign-extension of 47th bit */
|
||||
shl $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
|
||||
sar $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
|
||||
/* If this changed %rcx, it was not canonical */
|
||||
cmpq %rcx, %r11
|
||||
jne opportunistic_sysret_failed
|
||||
|
||||
cmpq $__USER_CS,CS(%rsp) /* CS must match SYSRET */
|
||||
jne opportunistic_sysret_failed
|
||||
@@ -475,8 +476,8 @@ syscall_return:
|
||||
*/
|
||||
syscall_return_via_sysret:
|
||||
CFI_REMEMBER_STATE
|
||||
/* r11 is already restored (see code above) */
|
||||
RESTORE_C_REGS_EXCEPT_R11
|
||||
/* rcx and r11 are already restored (see code above) */
|
||||
RESTORE_C_REGS_EXCEPT_RCX_R11
|
||||
movq RSP(%rsp),%rsp
|
||||
USERGS_SYSRET64
|
||||
CFI_RESTORE_STATE
|
||||
@@ -533,40 +534,27 @@ GLOBAL(stub_execveat)
|
||||
CFI_ENDPROC
|
||||
END(stub_execveat)
|
||||
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
|
||||
.align 8
|
||||
GLOBAL(stub_x32_execve)
|
||||
CFI_STARTPROC
|
||||
DEFAULT_FRAME 0, 8
|
||||
call compat_sys_execve
|
||||
jmp return_from_execve
|
||||
CFI_ENDPROC
|
||||
END(stub_x32_execve)
|
||||
.align 8
|
||||
GLOBAL(stub_x32_execveat)
|
||||
CFI_STARTPROC
|
||||
DEFAULT_FRAME 0, 8
|
||||
call compat_sys_execveat
|
||||
jmp return_from_execve
|
||||
CFI_ENDPROC
|
||||
END(stub_x32_execveat)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
.align 8
|
||||
GLOBAL(stub32_execve)
|
||||
CFI_STARTPROC
|
||||
DEFAULT_FRAME 0, 8
|
||||
call compat_sys_execve
|
||||
jmp return_from_execve
|
||||
CFI_ENDPROC
|
||||
END(stub32_execve)
|
||||
END(stub_x32_execve)
|
||||
.align 8
|
||||
GLOBAL(stub_x32_execveat)
|
||||
GLOBAL(stub32_execveat)
|
||||
CFI_STARTPROC
|
||||
DEFAULT_FRAME 0, 8
|
||||
call compat_sys_execveat
|
||||
jmp return_from_execve
|
||||
CFI_ENDPROC
|
||||
END(stub32_execveat)
|
||||
END(stub_x32_execveat)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -622,7 +610,7 @@ ENTRY(ret_from_fork)
|
||||
|
||||
RESTORE_EXTRA_REGS
|
||||
|
||||
testl $3,CS(%rsp) # from kernel_thread?
|
||||
testb $3, CS(%rsp) # from kernel_thread?
|
||||
|
||||
/*
|
||||
* By the time we get here, we have no idea whether our pt_regs,
|
||||
@@ -686,8 +674,8 @@ END(irq_entries_start)
|
||||
|
||||
leaq -RBP(%rsp),%rdi /* arg1 for \func (pointer to pt_regs) */
|
||||
|
||||
testl $3, CS-RBP(%rsp)
|
||||
je 1f
|
||||
testb $3, CS-RBP(%rsp)
|
||||
jz 1f
|
||||
SWAPGS
|
||||
1:
|
||||
/*
|
||||
@@ -741,8 +729,8 @@ ret_from_intr:
|
||||
CFI_DEF_CFA_REGISTER rsp
|
||||
CFI_ADJUST_CFA_OFFSET RBP
|
||||
|
||||
testl $3,CS(%rsp)
|
||||
je retint_kernel
|
||||
testb $3, CS(%rsp)
|
||||
jz retint_kernel
|
||||
/* Interrupt came from user space */
|
||||
|
||||
GET_THREAD_INFO(%rcx)
|
||||
@@ -928,6 +916,8 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR \
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
apicinterrupt3 POSTED_INTR_VECTOR \
|
||||
kvm_posted_intr_ipi smp_kvm_posted_intr_ipi
|
||||
apicinterrupt3 POSTED_INTR_WAKEUP_VECTOR \
|
||||
kvm_posted_intr_wakeup_ipi smp_kvm_posted_intr_wakeup_ipi
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_MCE_THRESHOLD
|
||||
@@ -989,7 +979,7 @@ ENTRY(\sym)
|
||||
.if \paranoid
|
||||
.if \paranoid == 1
|
||||
CFI_REMEMBER_STATE
|
||||
testl $3, CS(%rsp) /* If coming from userspace, switch */
|
||||
testb $3, CS(%rsp) /* If coming from userspace, switch */
|
||||
jnz 1f /* stacks. */
|
||||
.endif
|
||||
call paranoid_entry
|
||||
@@ -1202,17 +1192,17 @@ ENTRY(xen_failsafe_callback)
|
||||
/*CFI_REL_OFFSET ds,DS*/
|
||||
CFI_REL_OFFSET r11,8
|
||||
CFI_REL_OFFSET rcx,0
|
||||
movw %ds,%cx
|
||||
movl %ds,%ecx
|
||||
cmpw %cx,0x10(%rsp)
|
||||
CFI_REMEMBER_STATE
|
||||
jne 1f
|
||||
movw %es,%cx
|
||||
movl %es,%ecx
|
||||
cmpw %cx,0x18(%rsp)
|
||||
jne 1f
|
||||
movw %fs,%cx
|
||||
movl %fs,%ecx
|
||||
cmpw %cx,0x20(%rsp)
|
||||
jne 1f
|
||||
movw %gs,%cx
|
||||
movl %gs,%ecx
|
||||
cmpw %cx,0x28(%rsp)
|
||||
jne 1f
|
||||
/* All segments match their saved values => Category 2 (Bad IRET). */
|
||||
@@ -1330,8 +1320,8 @@ ENTRY(error_entry)
|
||||
SAVE_C_REGS 8
|
||||
SAVE_EXTRA_REGS 8
|
||||
xorl %ebx,%ebx
|
||||
testl $3,CS+8(%rsp)
|
||||
je error_kernelspace
|
||||
testb $3, CS+8(%rsp)
|
||||
jz error_kernelspace
|
||||
error_swapgs:
|
||||
SWAPGS
|
||||
error_sti:
|
||||
@@ -1382,7 +1372,7 @@ ENTRY(error_exit)
|
||||
TRACE_IRQS_OFF
|
||||
GET_THREAD_INFO(%rcx)
|
||||
testl %eax,%eax
|
||||
jne retint_kernel
|
||||
jnz retint_kernel
|
||||
LOCKDEP_SYS_EXIT_IRQ
|
||||
movl TI_flags(%rcx),%edx
|
||||
movl $_TIF_WORK_MASK,%edi
|
||||
@@ -1627,7 +1617,6 @@ end_repeat_nmi:
|
||||
je 1f
|
||||
movq %r12, %cr2
|
||||
1:
|
||||
|
||||
testl %ebx,%ebx /* swapgs needed? */
|
||||
jnz nmi_restore
|
||||
nmi_swapgs:
|
||||
|
@@ -547,7 +547,7 @@ ENTRY(early_idt_handler)
|
||||
cld
|
||||
|
||||
cmpl $2,(%esp) # X86_TRAP_NMI
|
||||
je is_nmi # Ignore NMI
|
||||
je .Lis_nmi # Ignore NMI
|
||||
|
||||
cmpl $2,%ss:early_recursion_flag
|
||||
je hlt_loop
|
||||
@@ -600,7 +600,7 @@ ex_entry:
|
||||
pop %ecx
|
||||
pop %eax
|
||||
decl %ss:early_recursion_flag
|
||||
is_nmi:
|
||||
.Lis_nmi:
|
||||
addl $8,%esp /* drop vector number and error code */
|
||||
iret
|
||||
ENDPROC(early_idt_handler)
|
||||
|
@@ -344,7 +344,7 @@ ENTRY(early_idt_handler)
|
||||
cld
|
||||
|
||||
cmpl $2,(%rsp) # X86_TRAP_NMI
|
||||
je is_nmi # Ignore NMI
|
||||
je .Lis_nmi # Ignore NMI
|
||||
|
||||
cmpl $2,early_recursion_flag(%rip)
|
||||
jz 1f
|
||||
@@ -409,7 +409,7 @@ ENTRY(early_idt_handler)
|
||||
popq %rcx
|
||||
popq %rax
|
||||
decl early_recursion_flag(%rip)
|
||||
is_nmi:
|
||||
.Lis_nmi:
|
||||
addq $16,%rsp # drop vector number and error code
|
||||
INTERRUPT_RETURN
|
||||
ENDPROC(early_idt_handler)
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/hpet.h>
|
||||
#include <asm/time.h>
|
||||
@@ -305,8 +306,6 @@ static void hpet_legacy_clockevent_register(void)
|
||||
printk(KERN_DEBUG "hpet clockevent registered\n");
|
||||
}
|
||||
|
||||
static int hpet_setup_msi_irq(unsigned int irq);
|
||||
|
||||
static void hpet_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt, int timer)
|
||||
{
|
||||
@@ -357,7 +356,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
|
||||
hpet_enable_legacy_int();
|
||||
} else {
|
||||
struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
|
||||
hpet_setup_msi_irq(hdev->irq);
|
||||
irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
|
||||
disable_irq(hdev->irq);
|
||||
irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
|
||||
enable_irq(hdev->irq);
|
||||
@@ -423,6 +422,7 @@ static int hpet_legacy_next_event(unsigned long delta,
|
||||
|
||||
static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
|
||||
static struct hpet_dev *hpet_devs;
|
||||
static struct irq_domain *hpet_domain;
|
||||
|
||||
void hpet_msi_unmask(struct irq_data *data)
|
||||
{
|
||||
@@ -473,31 +473,6 @@ static int hpet_msi_next_event(unsigned long delta,
|
||||
return hpet_next_event(delta, evt, hdev->num);
|
||||
}
|
||||
|
||||
static int hpet_setup_msi_irq(unsigned int irq)
|
||||
{
|
||||
if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
|
||||
irq_free_hwirq(irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hpet_assign_irq(struct hpet_dev *dev)
|
||||
{
|
||||
unsigned int irq = irq_alloc_hwirq(-1);
|
||||
|
||||
if (!irq)
|
||||
return -EINVAL;
|
||||
|
||||
irq_set_handler_data(irq, dev);
|
||||
|
||||
if (hpet_setup_msi_irq(irq))
|
||||
return -EINVAL;
|
||||
|
||||
dev->irq = irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t hpet_interrupt_handler(int irq, void *data)
|
||||
{
|
||||
struct hpet_dev *dev = (struct hpet_dev *)data;
|
||||
@@ -540,9 +515,6 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
|
||||
if (!(hdev->flags & HPET_DEV_VALID))
|
||||
return;
|
||||
|
||||
if (hpet_setup_msi_irq(hdev->irq))
|
||||
return;
|
||||
|
||||
hdev->cpu = cpu;
|
||||
per_cpu(cpu_hpet_dev, cpu) = hdev;
|
||||
evt->name = hdev->name;
|
||||
@@ -574,7 +546,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
|
||||
unsigned int id;
|
||||
unsigned int num_timers;
|
||||
unsigned int num_timers_used = 0;
|
||||
int i;
|
||||
int i, irq;
|
||||
|
||||
if (hpet_msi_disable)
|
||||
return;
|
||||
@@ -587,6 +559,10 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
|
||||
num_timers++; /* Value read out starts from 0 */
|
||||
hpet_print_config();
|
||||
|
||||
hpet_domain = hpet_create_irq_domain(hpet_blockid);
|
||||
if (!hpet_domain)
|
||||
return;
|
||||
|
||||
hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL);
|
||||
if (!hpet_devs)
|
||||
return;
|
||||
@@ -601,15 +577,16 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
|
||||
if (!(cfg & HPET_TN_FSB_CAP))
|
||||
continue;
|
||||
|
||||
irq = hpet_assign_irq(hpet_domain, hdev, hdev->num);
|
||||
if (irq < 0)
|
||||
continue;
|
||||
|
||||
sprintf(hdev->name, "hpet%d", i);
|
||||
hdev->num = i;
|
||||
hdev->irq = irq;
|
||||
hdev->flags = 0;
|
||||
if (cfg & HPET_TN_PERIODIC_CAP)
|
||||
hdev->flags |= HPET_DEV_PERI_CAP;
|
||||
hdev->num = i;
|
||||
|
||||
sprintf(hdev->name, "hpet%d", i);
|
||||
if (hpet_assign_irq(hdev))
|
||||
continue;
|
||||
|
||||
hdev->flags |= HPET_DEV_FSB_CAP;
|
||||
hdev->flags |= HPET_DEV_VALID;
|
||||
num_timers_used++;
|
||||
@@ -709,10 +686,6 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
|
||||
}
|
||||
#else
|
||||
|
||||
static int hpet_setup_msi_irq(unsigned int irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static void hpet_msi_capability_lookup(unsigned int start_timer)
|
||||
{
|
||||
return;
|
||||
|
@@ -329,8 +329,8 @@ static void init_8259A(int auto_eoi)
|
||||
*/
|
||||
outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
|
||||
|
||||
/* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */
|
||||
outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
|
||||
/* ICW2: 8259A-1 IR0-7 mapped to ISA_IRQ_VECTOR(0) */
|
||||
outb_pic(ISA_IRQ_VECTOR(0), PIC_MASTER_IMR);
|
||||
|
||||
/* 8259A-1 (the master) has a slave on IR2 */
|
||||
outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
|
||||
@@ -342,8 +342,8 @@ static void init_8259A(int auto_eoi)
|
||||
|
||||
outb_pic(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */
|
||||
|
||||
/* ICW2: 8259A-2 IR0-7 mapped to IRQ8_VECTOR */
|
||||
outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
|
||||
/* ICW2: 8259A-2 IR0-7 mapped to ISA_IRQ_VECTOR(8) */
|
||||
outb_pic(ISA_IRQ_VECTOR(8), PIC_SLAVE_IMR);
|
||||
/* 8259A-2 is a slave on master's IR2 */
|
||||
outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
|
||||
/* (slave's support for AEOI in flat mode is to be investigated) */
|
||||
|
@@ -22,6 +22,12 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <asm/trace/irq_vectors.h>
|
||||
|
||||
DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
||||
|
||||
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_regs);
|
||||
|
||||
atomic_t irq_err_count;
|
||||
|
||||
/* Function pointer for generic interrupt vector handling */
|
||||
@@ -135,6 +141,18 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
||||
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
|
||||
#if defined(CONFIG_X86_IO_APIC)
|
||||
seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
|
||||
#endif
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
seq_printf(p, "%*s: ", prec, "PIN");
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis);
|
||||
seq_puts(p, " Posted-interrupt notification event\n");
|
||||
|
||||
seq_printf(p, "%*s: ", prec, "PIW");
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ",
|
||||
irq_stats(j)->kvm_posted_intr_wakeup_ipis);
|
||||
seq_puts(p, " Posted-interrupt wakeup event\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -192,8 +210,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
|
||||
unsigned vector = ~regs->orig_ax;
|
||||
unsigned irq;
|
||||
|
||||
irq_enter();
|
||||
exit_idle();
|
||||
entering_irq();
|
||||
|
||||
irq = __this_cpu_read(vector_irq[vector]);
|
||||
|
||||
@@ -209,7 +226,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
|
||||
irq_exit();
|
||||
exiting_irq();
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
return 1;
|
||||
@@ -237,6 +254,18 @@ __visible void smp_x86_platform_ipi(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
static void dummy_handler(void) {}
|
||||
static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler;
|
||||
|
||||
void kvm_set_posted_intr_wakeup_handler(void (*handler)(void))
|
||||
{
|
||||
if (handler)
|
||||
kvm_posted_intr_wakeup_handler = handler;
|
||||
else
|
||||
kvm_posted_intr_wakeup_handler = dummy_handler;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_set_posted_intr_wakeup_handler);
|
||||
|
||||
/*
|
||||
* Handler for POSTED_INTERRUPT_VECTOR.
|
||||
*/
|
||||
@@ -244,16 +273,23 @@ __visible void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
ack_APIC_irq();
|
||||
|
||||
irq_enter();
|
||||
|
||||
exit_idle();
|
||||
|
||||
entering_ack_irq();
|
||||
inc_irq_stat(kvm_posted_intr_ipis);
|
||||
exiting_irq();
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
irq_exit();
|
||||
/*
|
||||
* Handler for POSTED_INTERRUPT_WAKEUP_VECTOR.
|
||||
*/
|
||||
__visible void smp_kvm_posted_intr_wakeup_ipi(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
entering_ack_irq();
|
||||
inc_irq_stat(kvm_posted_intr_wakeup_ipis);
|
||||
kvm_posted_intr_wakeup_handler();
|
||||
exiting_irq();
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
#endif
|
||||
|
@@ -21,12 +21,6 @@
|
||||
|
||||
#include <asm/apic.h>
|
||||
|
||||
DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
||||
|
||||
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_regs);
|
||||
|
||||
#ifdef CONFIG_DEBUG_STACKOVERFLOW
|
||||
|
||||
int sysctl_panic_on_stackoverflow __read_mostly;
|
||||
|
@@ -20,12 +20,6 @@
|
||||
#include <asm/idle.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
||||
|
||||
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
|
||||
EXPORT_PER_CPU_SYMBOL(irq_regs);
|
||||
|
||||
int sysctl_panic_on_stackoverflow;
|
||||
|
||||
/*
|
||||
|
@@ -10,12 +10,6 @@
|
||||
#include <asm/apic.h>
|
||||
#include <asm/trace/irq_vectors.h>
|
||||
|
||||
static inline void irq_work_entering_irq(void)
|
||||
{
|
||||
irq_enter();
|
||||
ack_APIC_irq();
|
||||
}
|
||||
|
||||
static inline void __smp_irq_work_interrupt(void)
|
||||
{
|
||||
inc_irq_stat(apic_irq_work_irqs);
|
||||
@@ -24,14 +18,14 @@ static inline void __smp_irq_work_interrupt(void)
|
||||
|
||||
__visible void smp_irq_work_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
irq_work_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
__smp_irq_work_interrupt();
|
||||
exiting_irq();
|
||||
}
|
||||
|
||||
__visible void smp_trace_irq_work_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
irq_work_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
trace_irq_work_entry(IRQ_WORK_VECTOR);
|
||||
__smp_irq_work_interrupt();
|
||||
trace_irq_work_exit(IRQ_WORK_VECTOR);
|
||||
|
@@ -86,7 +86,7 @@ void __init init_IRQ(void)
|
||||
int i;
|
||||
|
||||
/*
|
||||
* On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
|
||||
* On cpu 0, Assign ISA_IRQ_VECTOR(irq) to IRQ 0..15.
|
||||
* If these IRQ's are handled by legacy interrupt-controllers like PIC,
|
||||
* then this configuration will likely be static after the boot. If
|
||||
* these IRQ's are handled by more mordern controllers like IO-APIC,
|
||||
@@ -94,7 +94,7 @@ void __init init_IRQ(void)
|
||||
* irq's migrate etc.
|
||||
*/
|
||||
for (i = 0; i < nr_legacy_irqs(); i++)
|
||||
per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;
|
||||
per_cpu(vector_irq, 0)[ISA_IRQ_VECTOR(i)] = i;
|
||||
|
||||
x86_init.irqs.intr_init();
|
||||
}
|
||||
@@ -144,6 +144,8 @@ static void __init apic_intr_init(void)
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
/* IPI for KVM to deliver posted interrupt */
|
||||
alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi);
|
||||
/* IPI for KVM to deliver interrupt to wake up tasks */
|
||||
alloc_intr_gate(POSTED_INTR_WAKEUP_VECTOR, kvm_posted_intr_wakeup_ipi);
|
||||
#endif
|
||||
|
||||
/* IPI vectors for APIC spurious and error interrupts */
|
||||
|
@@ -19,8 +19,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <asm/irqdomain.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/pgalloc.h>
|
||||
@@ -113,11 +113,6 @@ static void __init MP_bus_info(struct mpc_bus *m)
|
||||
pr_warn("Unknown bustype %s - ignoring\n", str);
|
||||
}
|
||||
|
||||
static struct irq_domain_ops mp_ioapic_irqdomain_ops = {
|
||||
.map = mp_irqdomain_map,
|
||||
.unmap = mp_irqdomain_unmap,
|
||||
};
|
||||
|
||||
static void __init MP_ioapic_info(struct mpc_ioapic *m)
|
||||
{
|
||||
struct ioapic_domain_cfg cfg = {
|
||||
|
@@ -154,7 +154,9 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
|
||||
ret = paravirt_patch_ident_64(insnbuf, len);
|
||||
|
||||
else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
|
||||
#ifdef CONFIG_X86_32
|
||||
type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
|
||||
#endif
|
||||
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
|
||||
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
|
||||
/* If operation requires a jmp, then jmp */
|
||||
@@ -371,7 +373,7 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
|
||||
|
||||
.load_sp0 = native_load_sp0,
|
||||
|
||||
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
|
||||
#if defined(CONFIG_X86_32)
|
||||
.irq_enable_sysexit = native_irq_enable_sysexit,
|
||||
#endif
|
||||
#ifdef CONFIG_X86_64
|
||||
|
@@ -49,7 +49,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
|
||||
PATCH_SITE(pv_irq_ops, save_fl);
|
||||
PATCH_SITE(pv_irq_ops, irq_enable);
|
||||
PATCH_SITE(pv_irq_ops, irq_disable);
|
||||
PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
|
||||
PATCH_SITE(pv_cpu_ops, usergs_sysret32);
|
||||
PATCH_SITE(pv_cpu_ops, usergs_sysret64);
|
||||
PATCH_SITE(pv_cpu_ops, swapgs);
|
||||
|
@@ -302,13 +302,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
|
||||
arch_end_context_switch(next_p);
|
||||
|
||||
/*
|
||||
* Reload esp0, kernel_stack, and current_top_of_stack. This changes
|
||||
* Reload esp0 and cpu_current_top_of_stack. This changes
|
||||
* current_thread_info().
|
||||
*/
|
||||
load_sp0(tss, next);
|
||||
this_cpu_write(kernel_stack,
|
||||
(unsigned long)task_stack_page(next_p) +
|
||||
THREAD_SIZE);
|
||||
this_cpu_write(cpu_current_top_of_stack,
|
||||
(unsigned long)task_stack_page(next_p) +
|
||||
THREAD_SIZE);
|
||||
|
@@ -409,9 +409,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
|
||||
/* Reload esp0 and ss1. This changes current_thread_info(). */
|
||||
load_sp0(tss, next);
|
||||
|
||||
this_cpu_write(kernel_stack,
|
||||
(unsigned long)task_stack_page(next_p) + THREAD_SIZE);
|
||||
|
||||
/*
|
||||
* Now maybe reload the debug registers and handle I/O bitmaps
|
||||
*/
|
||||
|
@@ -1222,8 +1222,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
init_cpu_to_node();
|
||||
|
||||
init_apic_mappings();
|
||||
if (x86_io_apic_ops.init)
|
||||
x86_io_apic_ops.init();
|
||||
io_apic_init_mappings();
|
||||
|
||||
kvm_guest_init();
|
||||
|
||||
|
@@ -170,8 +170,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
|
||||
|
||||
asmlinkage __visible void smp_reboot_interrupt(void)
|
||||
{
|
||||
ack_APIC_irq();
|
||||
irq_enter();
|
||||
ipi_entering_ack_irq();
|
||||
stop_this_cpu(NULL);
|
||||
irq_exit();
|
||||
}
|
||||
@@ -265,12 +264,6 @@ __visible void smp_reschedule_interrupt(struct pt_regs *regs)
|
||||
*/
|
||||
}
|
||||
|
||||
static inline void smp_entering_irq(void)
|
||||
{
|
||||
ack_APIC_irq();
|
||||
irq_enter();
|
||||
}
|
||||
|
||||
__visible void smp_trace_reschedule_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
@@ -279,7 +272,7 @@ __visible void smp_trace_reschedule_interrupt(struct pt_regs *regs)
|
||||
* scheduler_ipi(). This is OK, since those functions are allowed
|
||||
* to nest.
|
||||
*/
|
||||
smp_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
trace_reschedule_entry(RESCHEDULE_VECTOR);
|
||||
__smp_reschedule_interrupt();
|
||||
trace_reschedule_exit(RESCHEDULE_VECTOR);
|
||||
@@ -297,14 +290,14 @@ static inline void __smp_call_function_interrupt(void)
|
||||
|
||||
__visible void smp_call_function_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
smp_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
__smp_call_function_interrupt();
|
||||
exiting_irq();
|
||||
}
|
||||
|
||||
__visible void smp_trace_call_function_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
smp_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
trace_call_function_entry(CALL_FUNCTION_VECTOR);
|
||||
__smp_call_function_interrupt();
|
||||
trace_call_function_exit(CALL_FUNCTION_VECTOR);
|
||||
@@ -319,14 +312,14 @@ static inline void __smp_call_function_single_interrupt(void)
|
||||
|
||||
__visible void smp_call_function_single_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
smp_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
__smp_call_function_single_interrupt();
|
||||
exiting_irq();
|
||||
}
|
||||
|
||||
__visible void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
smp_entering_irq();
|
||||
ipi_entering_ack_irq();
|
||||
trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR);
|
||||
__smp_call_function_single_interrupt();
|
||||
trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
|
||||
|
@@ -513,6 +513,40 @@ void __inquire_remote_apic(int apicid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The Multiprocessor Specification 1.4 (1997) example code suggests
|
||||
* that there should be a 10ms delay between the BSP asserting INIT
|
||||
* and de-asserting INIT, when starting a remote processor.
|
||||
* But that slows boot and resume on modern processors, which include
|
||||
* many cores and don't require that delay.
|
||||
*
|
||||
* Cmdline "init_cpu_udelay=" is available to over-ride this delay.
|
||||
* Modern processor families are quirked to remove the delay entirely.
|
||||
*/
|
||||
#define UDELAY_10MS_DEFAULT 10000
|
||||
|
||||
static unsigned int init_udelay = UDELAY_10MS_DEFAULT;
|
||||
|
||||
static int __init cpu_init_udelay(char *str)
|
||||
{
|
||||
get_option(&str, &init_udelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("cpu_init_udelay", cpu_init_udelay);
|
||||
|
||||
static void __init smp_quirk_init_udelay(void)
|
||||
{
|
||||
/* if cmdline changed it from default, leave it alone */
|
||||
if (init_udelay != UDELAY_10MS_DEFAULT)
|
||||
return;
|
||||
|
||||
/* if modern processor, use no delay */
|
||||
if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) ||
|
||||
((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF)))
|
||||
init_udelay = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
|
||||
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
|
||||
@@ -555,7 +589,7 @@ wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
|
||||
static int
|
||||
wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
|
||||
{
|
||||
unsigned long send_status, accept_status = 0;
|
||||
unsigned long send_status = 0, accept_status = 0;
|
||||
int maxlvt, num_starts, j;
|
||||
|
||||
maxlvt = lapic_get_maxlvt();
|
||||
@@ -583,7 +617,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
|
||||
pr_debug("Waiting for send to finish...\n");
|
||||
send_status = safe_apic_wait_icr_idle();
|
||||
|
||||
mdelay(10);
|
||||
udelay(init_udelay);
|
||||
|
||||
pr_debug("Deasserting INIT\n");
|
||||
|
||||
@@ -651,6 +685,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
|
||||
* Give the other CPU some time to accept the IPI.
|
||||
*/
|
||||
udelay(200);
|
||||
|
||||
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
|
||||
apic_write(APIC_ESR, 0);
|
||||
accept_status = (apic_read(APIC_ESR) & 0xEF);
|
||||
@@ -792,8 +827,6 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
clear_tsk_thread_flag(idle, TIF_FORK);
|
||||
initial_gs = per_cpu_offset(cpu);
|
||||
#endif
|
||||
per_cpu(kernel_stack, cpu) =
|
||||
(unsigned long)task_stack_page(idle) + THREAD_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1176,6 +1209,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
|
||||
uv_system_init();
|
||||
|
||||
set_mtrr_aps_delayed_init();
|
||||
|
||||
smp_quirk_init_udelay();
|
||||
}
|
||||
|
||||
void arch_enable_nonboot_cpus_begin(void)
|
||||
|
@@ -997,8 +997,8 @@ void __init trap_init(void)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
|
||||
set_bit(SYSCALL_VECTOR, used_vectors);
|
||||
set_system_trap_gate(IA32_SYSCALL_VECTOR, &system_call);
|
||||
set_bit(IA32_SYSCALL_VECTOR, used_vectors);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@@ -111,11 +111,9 @@ EXPORT_SYMBOL_GPL(x86_platform);
|
||||
#if defined(CONFIG_PCI_MSI)
|
||||
struct x86_msi_ops x86_msi = {
|
||||
.setup_msi_irqs = native_setup_msi_irqs,
|
||||
.compose_msi_msg = native_compose_msi_msg,
|
||||
.teardown_msi_irq = native_teardown_msi_irq,
|
||||
.teardown_msi_irqs = default_teardown_msi_irqs,
|
||||
.restore_msi_irqs = default_restore_msi_irqs,
|
||||
.setup_hpet_msi = default_setup_hpet_msi,
|
||||
};
|
||||
|
||||
/* MSI arch specific hooks */
|
||||
@@ -141,13 +139,6 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
|
||||
#endif
|
||||
|
||||
struct x86_io_apic_ops x86_io_apic_ops = {
|
||||
.init = native_io_apic_init_mappings,
|
||||
.read = native_io_apic_read,
|
||||
.write = native_io_apic_write,
|
||||
.modify = native_io_apic_modify,
|
||||
.disable = native_disable_io_apic,
|
||||
.print_entries = native_io_apic_print_entries,
|
||||
.set_affinity = native_ioapic_set_affinity,
|
||||
.setup_entry = native_setup_ioapic_entry,
|
||||
.eoi_ioapic_pin = native_eoi_ioapic_pin,
|
||||
};
|
||||
|
Reference in New Issue
Block a user