aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic/vector.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/apic/vector.c')
-rw-r--r--arch/x86/kernel/apic/vector.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 3cc471beb50b..bb6f7a2148d7 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -134,21 +134,40 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
134{ 134{
135 struct apic_chip_data *apicd = apic_chip_data(irqd); 135 struct apic_chip_data *apicd = apic_chip_data(irqd);
136 struct irq_desc *desc = irq_data_to_desc(irqd); 136 struct irq_desc *desc = irq_data_to_desc(irqd);
137 bool managed = irqd_affinity_is_managed(irqd);
137 138
138 lockdep_assert_held(&vector_lock); 139 lockdep_assert_held(&vector_lock);
139 140
140 trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector, 141 trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector,
141 apicd->cpu); 142 apicd->cpu);
142 143
143 /* Setup the vector move, if required */ 144 /*
144 if (apicd->vector && cpu_online(apicd->cpu)) { 145 * If there is no vector associated or if the associated vector is
146 * the shutdown vector, which is associated to make PCI/MSI
147 * shutdown mode work, then there is nothing to release. Clear out
148 * prev_vector for this and the offlined target case.
149 */
150 apicd->prev_vector = 0;
151 if (!apicd->vector || apicd->vector == MANAGED_IRQ_SHUTDOWN_VECTOR)
152 goto setnew;
153 /*
154 * If the target CPU of the previous vector is online, then mark
155 * the vector as move in progress and store it for cleanup when the
156 * first interrupt on the new vector arrives. If the target CPU is
157 * offline then the regular release mechanism via the cleanup
158 * vector is not possible and the vector can be immediately freed
159 * in the underlying matrix allocator.
160 */
161 if (cpu_online(apicd->cpu)) {
145 apicd->move_in_progress = true; 162 apicd->move_in_progress = true;
146 apicd->prev_vector = apicd->vector; 163 apicd->prev_vector = apicd->vector;
147 apicd->prev_cpu = apicd->cpu; 164 apicd->prev_cpu = apicd->cpu;
148 } else { 165 } else {
149 apicd->prev_vector = 0; 166 irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
167 managed);
150 } 168 }
151 169
170setnew:
152 apicd->vector = newvec; 171 apicd->vector = newvec;
153 apicd->cpu = newcpu; 172 apicd->cpu = newcpu;
154 BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec])); 173 BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));