diff mbox

xive: Fix xive reset corrupting EQ allocation bitmap

Message ID 1488954777.2870.166.camel@kernel.crashing.org
State Accepted
Headers show

Commit Message

Benjamin Herrenschmidt March 8, 2017, 6:32 a.m. UTC
This causes us to hand out the physical processor EQs again to
VPs when KVM uses the XIVE, thus causing loss of host interrupts.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 hw/xive.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

Comments

Stewart Smith March 9, 2017, 3:34 a.m. UTC | #1
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> This causes us to hand out the physical processor EQs again to
> VPs when KVM uses the XIVE, thus causing loss of host interrupts.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Merged to master as of 40f50bde8185c817e295f390d0706a085602cafa
diff mbox

Patch

diff --git a/hw/xive.c b/hw/xive.c
index ba9dc54..2c47bfc 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -3715,6 +3715,7 @@  static void xive_cleanup_cpu_cam(struct cpu_thread *c)
 static void xive_reset_one(struct xive *x)
 {
 	struct cpu_thread *c;
+	bool eq_firmware;
 	int i = 0;
 
 	/* Mask all interrupt sources */
@@ -3732,15 +3733,29 @@  static void xive_reset_one(struct xive *x)
 	bitmap_for_each_one(*x->eq_map, MAX_EQ_COUNT >> 3, i) {
 		struct xive_eq eq0 = {0};
 		struct xive_eq *eq;
+		int j;
 
 		if (i == 0)
 			continue;
-		eq = xive_get_eq(x, i);
-		if (!eq)
-			continue;
-		xive_eqc_cache_update(x, x->block_id,
-				      i, 0, 4, &eq0, false, true);
-		if (!(eq->w0 & EQ_W0_FIRMWARE))
+		eq_firmware = false;
+		for (j = 0; j < 8; j++) {
+			uint32_t idx = (i << 3) | j;
+
+			eq = xive_get_eq(x, idx);
+			if (!eq)
+				continue;
+
+			/* We need to preserve the firmware bit, otherwise
+			 * we will incorrectly free the EQs that are reserved
+			 * for the physical CPUs
+			 */
+			eq0.w0 = eq->w0 & EQ_W0_FIRMWARE;
+			xive_eqc_cache_update(x, x->block_id,
+					      idx, 0, 4, &eq0, false, true);
+			if (eq->w0 & EQ_W0_FIRMWARE)
+				eq_firmware = true;
+		}
+		if (!eq_firmware)
 			bitmap_clr_bit(*x->eq_map, i);
 	}