NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/57878: i915 calls agp_i810_chipset_flush with spin lock held but agp_i810_chipset_flush waits for xcall



Correction: need kpreempt_disable/enable around ipi(9) if we _don't_
hold a spin lock when we call it.
From eac456a8881930d2b1f66a87850eaa13be51d093 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Thu, 25 Jan 2024 23:17:34 +0000
Subject: [PATCH] agp_i810(4): Use ipi(9) for chipset flush on all CPUs, not
 xcall(9).

i915 now calls into this with a spin lock held, so we have to use
ipi(9), which spin-waits for the other CPUs to complete, rather than
xcall(9), which may sleep-wait.

Fortunately, this is just to execute WBINVD on x86 (and if this code
ever runs on other architectures, which it probably doesn't, it'll be
a similar barrier instruction), so spinning to wait for that on all
CPUs isn't too costly.

PR kern/57878

XXX pullup-10
---
 sys/dev/pci/agp_i810.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/sys/dev/pci/agp_i810.c b/sys/dev/pci/agp_i810.c
index adfb5716d4a3..961a3a5b077b 100644
--- a/sys/dev/pci/agp_i810.c
+++ b/sys/dev/pci/agp_i810.c
@@ -180,7 +180,7 @@ agp_i810_post_gtt_entry(struct agp_i810_softc *isc, off_t off)
 }
 
 static void
-agp_flush_cache_xc(void *a __unused, void *b __unused)
+agp_flush_cache_ipi(void *cookie __unused)
 {
 
 	agp_flush_cache();
@@ -204,11 +204,19 @@ agp_i810_chipset_flush(struct agp_i810_softc *isc)
 		 * XXX Come to think of it, do these chipsets appear in
 		 * any multi-CPU systems?
 		 */
-		if (cold)
+		if (cold) {
 			agp_flush_cache();
-		else
-			xc_wait(xc_broadcast(0, &agp_flush_cache_xc,
-				NULL, NULL));
+		} else {
+			/*
+			 * Caller may hold a spin lock, so use ipi(9)
+			 * rather than xcall(9) here.
+			 */
+			ipi_msg_t msg = { .func = agp_flush_cache_ipi };
+			kpreempt_disable();
+			ipi_broadcast(&msg, /*skip_self*/false);
+			ipi_wait(&msg);
+			kpreempt_enable();
+		}
 		WRITE4(AGP_I830_HIC, READ4(AGP_I830_HIC) | __BIT(31));
 		while (ISSET(READ4(AGP_I830_HIC), __BIT(31))) {
 			if (timo-- == 0)


Home | Main Index | Thread Index | Old Index