Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar: "Misc fixes: - fix hotplug bugs - fix irq live lock - fix various topology handling bugs - fix APIC ACK ordering - fix PV iopl handling - fix speling - fix/tweak memcpy_mcsafe() return value - fix fbcon bug - remove stray prototypes" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/msr: Remove unused native_read_tscp() x86/apic: Remove declaration of unused hw_nmi_is_cpu_stuck x86/oprofile/nmi: Add missing hotplug FROZEN handling x86/hpet: Use proper mask to modify hotplug action x86/apic/uv: Fix the hotplug notifier x86/apb/timer: Use proper mask to modify hotplug action x86/topology: Use total_cpus not nr_cpu_ids for logical packages x86/topology: Fix Intel HT disable x86/topology: Fix logical package mapping x86/irq: Cure live lock in fixup_irqs() x86/tsc: Prevent NULL pointer deref in calibrate_delay_is_known() x86/apic: Fix suspicious RCU usage in smp_trace_call_function_interrupt() x86/iopl: Fix iopl capability check on Xen PV x86/iopl/64: Properly context-switch IOPL on Xen PV selftests/x86: Add an iopl test x86/mm, x86/mce: Fix return type/value for memcpy_mcsafe() x86/video: Don't assume all FB devices are PCI devices arch/x86/irq: Purge useless handler declarations from hw_irq.h x86: Fix misspellings in comments
This commit is contained in:
@@ -1611,7 +1611,7 @@ void __init enable_IR_x2apic(void)
|
||||
legacy_pic->mask_all();
|
||||
mask_ioapic_entries();
|
||||
|
||||
/* If irq_remapping_prepare() succeded, try to enable it */
|
||||
/* If irq_remapping_prepare() succeeded, try to enable it */
|
||||
if (ir_stat >= 0)
|
||||
ir_stat = try_to_enable_IR();
|
||||
/* ir_stat contains the remap mode or an error code */
|
||||
|
@@ -213,6 +213,7 @@ update:
|
||||
*/
|
||||
cpumask_and(d->old_domain, d->old_domain, cpu_online_mask);
|
||||
d->move_in_progress = !cpumask_empty(d->old_domain);
|
||||
d->cfg.old_vector = d->move_in_progress ? d->cfg.vector : 0;
|
||||
d->cfg.vector = vector;
|
||||
cpumask_copy(d->domain, vector_cpumask);
|
||||
success:
|
||||
@@ -655,46 +656,97 @@ void irq_complete_move(struct irq_cfg *cfg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with @desc->lock held and interrupts disabled.
|
||||
* Called from fixup_irqs() with @desc->lock held and interrupts disabled.
|
||||
*/
|
||||
void irq_force_complete_move(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_data *irqdata = irq_desc_get_irq_data(desc);
|
||||
struct apic_chip_data *data = apic_chip_data(irqdata);
|
||||
struct irq_cfg *cfg = data ? &data->cfg : NULL;
|
||||
unsigned int cpu;
|
||||
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
__irq_complete_move(cfg, cfg->vector);
|
||||
|
||||
/*
|
||||
* This is tricky. If the cleanup of @data->old_domain has not been
|
||||
* done yet, then the following setaffinity call will fail with
|
||||
* -EBUSY. This can leave the interrupt in a stale state.
|
||||
*
|
||||
* The cleanup cannot make progress because we hold @desc->lock. So in
|
||||
* case @data->old_domain is not yet cleaned up, we need to drop the
|
||||
* lock and acquire it again. @desc cannot go away, because the
|
||||
* hotplug code holds the sparse irq lock.
|
||||
* All CPUs are stuck in stop machine with interrupts disabled so
|
||||
* calling __irq_complete_move() would be completely pointless.
|
||||
*/
|
||||
raw_spin_lock(&vector_lock);
|
||||
/* Clean out all offline cpus (including ourself) first. */
|
||||
/*
|
||||
* Clean out all offline cpus (including the outgoing one) from the
|
||||
* old_domain mask.
|
||||
*/
|
||||
cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
|
||||
while (!cpumask_empty(data->old_domain)) {
|
||||
|
||||
/*
|
||||
* If move_in_progress is cleared and the old_domain mask is empty,
|
||||
* then there is nothing to cleanup. fixup_irqs() will take care of
|
||||
* the stale vectors on the outgoing cpu.
|
||||
*/
|
||||
if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
|
||||
raw_spin_unlock(&vector_lock);
|
||||
raw_spin_unlock(&desc->lock);
|
||||
cpu_relax();
|
||||
raw_spin_lock(&desc->lock);
|
||||
/*
|
||||
* Reevaluate apic_chip_data. It might have been cleared after
|
||||
* we dropped @desc->lock.
|
||||
*/
|
||||
data = apic_chip_data(irqdata);
|
||||
if (!data)
|
||||
return;
|
||||
raw_spin_lock(&vector_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1) The interrupt is in move_in_progress state. That means that we
|
||||
* have not seen an interrupt since the io_apic was reprogrammed to
|
||||
* the new vector.
|
||||
*
|
||||
* 2) The interrupt has fired on the new vector, but the cleanup IPIs
|
||||
* have not been processed yet.
|
||||
*/
|
||||
if (data->move_in_progress) {
|
||||
/*
|
||||
* In theory there is a race:
|
||||
*
|
||||
* set_ioapic(new_vector) <-- Interrupt is raised before update
|
||||
* is effective, i.e. it's raised on
|
||||
* the old vector.
|
||||
*
|
||||
* So if the target cpu cannot handle that interrupt before
|
||||
* the old vector is cleaned up, we get a spurious interrupt
|
||||
* and in the worst case the ioapic irq line becomes stale.
|
||||
*
|
||||
* But in case of cpu hotplug this should be a non issue
|
||||
* because if the affinity update happens right before all
|
||||
* cpus rendevouz in stop machine, there is no way that the
|
||||
* interrupt can be blocked on the target cpu because all cpus
|
||||
* loops first with interrupts enabled in stop machine, so the
|
||||
* old vector is not yet cleaned up when the interrupt fires.
|
||||
*
|
||||
* So the only way to run into this issue is if the delivery
|
||||
* of the interrupt on the apic/system bus would be delayed
|
||||
* beyond the point where the target cpu disables interrupts
|
||||
* in stop machine. I doubt that it can happen, but at least
|
||||
* there is a theroretical chance. Virtualization might be
|
||||
* able to expose this, but AFAICT the IOAPIC emulation is not
|
||||
* as stupid as the real hardware.
|
||||
*
|
||||
* Anyway, there is nothing we can do about that at this point
|
||||
* w/o refactoring the whole fixup_irq() business completely.
|
||||
* We print at least the irq number and the old vector number,
|
||||
* so we have the necessary information when a problem in that
|
||||
* area arises.
|
||||
*/
|
||||
pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
|
||||
irqdata->irq, cfg->old_vector);
|
||||
}
|
||||
/*
|
||||
* If old_domain is not empty, then other cpus still have the irq
|
||||
* descriptor set in their vector array. Clean it up.
|
||||
*/
|
||||
for_each_cpu(cpu, data->old_domain)
|
||||
per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
|
||||
|
||||
/* Cleanup the left overs of the (half finished) move */
|
||||
cpumask_clear(data->old_domain);
|
||||
data->move_in_progress = 0;
|
||||
raw_spin_unlock(&vector_lock);
|
||||
}
|
||||
#endif
|
||||
|
@@ -792,7 +792,8 @@ static int uv_scir_cpu_notify(struct notifier_block *self, unsigned long action,
|
||||
{
|
||||
long cpu = (long)hcpu;
|
||||
|
||||
switch (action) {
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_ONLINE:
|
||||
uv_heartbeat_enable(cpu);
|
||||
break;
|
||||
@@ -860,7 +861,7 @@ int uv_set_vga_state(struct pci_dev *pdev, bool decode,
|
||||
*/
|
||||
void uv_cpu_init(void)
|
||||
{
|
||||
/* CPU 0 initilization will be done via uv_system_init. */
|
||||
/* CPU 0 initialization will be done via uv_system_init. */
|
||||
if (!uv_blade_info)
|
||||
return;
|
||||
|
||||
|
Reference in New Issue
Block a user