|
@@ -266,6 +266,76 @@ __visible void smp_trace_x86_platform_ipi(struct pt_regs *regs)
|
|
|
EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
+/*
|
|
|
+ * This cpu is going to be removed and its vectors migrated to the remaining
|
|
|
+ * online cpus. Check to see if there are enough vectors in the remaining cpus.
|
|
|
+ * This function is protected by stop_machine().
|
|
|
+ */
|
|
|
+int check_irq_vectors_for_cpu_disable(void)
|
|
|
+{
|
|
|
+ int irq, cpu;
|
|
|
+ unsigned int this_cpu, vector, this_count, count;
|
|
|
+ struct irq_desc *desc;
|
|
|
+ struct irq_data *data;
|
|
|
+ struct cpumask affinity_new, online_new;
|
|
|
+
|
|
|
+ this_cpu = smp_processor_id();
|
|
|
+ cpumask_copy(&online_new, cpu_online_mask);
|
|
|
+ cpu_clear(this_cpu, online_new);
|
|
|
+
|
|
|
+ this_count = 0;
|
|
|
+ for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
|
|
|
+ irq = __this_cpu_read(vector_irq[vector]);
|
|
|
+ if (irq >= 0) {
|
|
|
+ desc = irq_to_desc(irq);
|
|
|
+ data = irq_desc_get_irq_data(desc);
|
|
|
+ cpumask_copy(&affinity_new, data->affinity);
|
|
|
+ cpu_clear(this_cpu, affinity_new);
|
|
|
+
|
|
|
+ /* Do not count inactive or per-cpu irqs. */
|
|
|
+ if (!irq_has_action(irq) || irqd_is_per_cpu(data))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A single irq may be mapped to multiple
|
|
|
+ * cpu's vector_irq[] (for example IOAPIC cluster
|
|
|
+ * mode). In this case we have two
|
|
|
+ * possibilities:
|
|
|
+ *
|
|
|
+ * 1) the resulting affinity mask is empty; that is
|
|
|
+ * this the down'd cpu is the last cpu in the irq's
|
|
|
+ * affinity mask, or
|
|
|
+ *
|
|
|
+ * 2) the resulting affinity mask is no longer
|
|
|
+ * a subset of the online cpus but the affinity
|
|
|
+ * mask is not zero; that is the down'd cpu is the
|
|
|
+ * last online cpu in a user set affinity mask.
|
|
|
+ */
|
|
|
+ if (cpumask_empty(&affinity_new) ||
|
|
|
+ !cpumask_subset(&affinity_new, &online_new))
|
|
|
+ this_count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ count = 0;
|
|
|
+ for_each_online_cpu(cpu) {
|
|
|
+ if (cpu == this_cpu)
|
|
|
+ continue;
|
|
|
+ for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
|
|
|
+ vector++) {
|
|
|
+ if (per_cpu(vector_irq, cpu)[vector] < 0)
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count < this_count) {
|
|
|
+ pr_warn("CPU %d disable failed: CPU has %u vectors assigned and there are only %u available.\n",
|
|
|
+ this_cpu, this_count, count);
|
|
|
+ return -ERANGE;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* A cpu has been removed from cpu_online_mask. Reset irq affinities. */
|
|
|
void fixup_irqs(void)
|
|
|
{
|