diff options
Diffstat (limited to 'arch/x86/kernel/apic/vector.c')
-rw-r--r-- | arch/x86/kernel/apic/vector.c | 25 |
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 | ||
170 | setnew: | ||
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])); |