Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic-v3-its: Move pending doorbell after VMOVP

After moving a VPE from a redistributor to another, we're still left
with a potential pending doorbell interrupt on the old redistributor.
That interrupt should be moved to the new one to be either cleared
or take, depending on what the hypervisor wishes to do.

So let's move it right after having execited VMOVP. This doesn't
add much cost in the !DirectLPI case (we trade a DISCARD for a MOVI),
and the cost of the DIRECTLPI case should be minimal (two extra MMIO
accesses).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+32 -2
+32 -2
drivers/irqchip/irq-gic-v3-its.c
··· 2318 2318 its_send_mapti(vpe_proxy.dev, vpe->vpe_db_lpi, vpe->vpe_proxy_event); 2319 2319 } 2320 2320 2321 + static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to) 2322 + { 2323 + unsigned long flags; 2324 + struct its_collection *target_col; 2325 + 2326 + if (gic_rdists->has_direct_lpi) { 2327 + void __iomem *rdbase; 2328 + 2329 + rdbase = per_cpu_ptr(gic_rdists->rdist, from)->rd_base; 2330 + gic_write_lpir(vpe->vpe_db_lpi, rdbase + GICR_CLRLPIR); 2331 + while (gic_read_lpir(rdbase + GICR_SYNCR) & 1) 2332 + cpu_relax(); 2333 + 2334 + return; 2335 + } 2336 + 2337 + raw_spin_lock_irqsave(&vpe_proxy.lock, flags); 2338 + 2339 + its_vpe_db_proxy_map_locked(vpe); 2340 + 2341 + target_col = &vpe_proxy.dev->its->collections[to]; 2342 + its_send_movi(vpe_proxy.dev, target_col, vpe->vpe_proxy_event); 2343 + vpe_proxy.dev->event_map.col_map[vpe->vpe_proxy_event] = to; 2344 + 2345 + raw_spin_unlock_irqrestore(&vpe_proxy.lock, flags); 2346 + } 2347 + 2321 2348 static int its_vpe_set_affinity(struct irq_data *d, 2322 2349 const struct cpumask *mask_val, 2323 2350 bool force) ··· 2355 2328 /* 2356 2329 * Changing affinity is mega expensive, so let's be as lazy as 2357 2330 * we can and only do it if we really have to. Also, if mapped 2358 - * into the proxy device, we need to nuke that mapping. 2331 + * into the proxy device, we need to move the doorbell 2332 + * interrupt to its new location. 2359 2333 */ 2360 2334 if (vpe->col_idx != cpu) { 2361 - its_vpe_db_proxy_unmap(vpe); 2335 + int from = vpe->col_idx; 2336 + 2362 2337 vpe->col_idx = cpu; 2363 2338 its_send_vmovp(vpe); 2339 + its_vpe_db_proxy_move(vpe, from, cpu); 2364 2340 } 2365 2341 2366 2342 return IRQ_SET_MASK_OK_DONE;