Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Apr 2020 16:52:57 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r360156 - stable/12/sys/dev/ipmi
Message-ID:  <202004211652.03LGqv3l087087@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Tue Apr 21 16:52:56 2020
New Revision: 360156
URL: https://svnweb.freebsd.org/changeset/base/360156

Log:
  MFC r348996 (by jtl):
  The current IPMI KCS code is waiting 100us for all transitions (roughly
  between each byte either sent or received). However, most transitions
  actually complete in 2-3 microseconds.
  
  By polling the status register with a delay of 4us with exponential
  backoff, the performance of most IPMI operations is significantly
  improved:
    - A BMC update on a Supermicro x9 or x11 motherboard goes from ~1 hour
      to ~6-8 minutes.
    - An ipmitool sensor list time improves by a factor of 4.
  
  Testing showed no significant improvements on a modern server by using
  a lower delay.
  
  The changes should also generally reduce the total amount of CPU or
  I/O bandwidth used for a given IPMI operation.

Modified:
  stable/12/sys/dev/ipmi/ipmi_kcs.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/ipmi/ipmi_kcs.c
==============================================================================
--- stable/12/sys/dev/ipmi/ipmi_kcs.c	Tue Apr 21 16:13:22 2020	(r360155)
+++ stable/12/sys/dev/ipmi/ipmi_kcs.c	Tue Apr 21 16:52:56 2020	(r360156)
@@ -48,55 +48,46 @@ __FBSDID("$FreeBSD$");
 #include <dev/ipmi/ipmivars.h>
 #endif
 
+#define	POLLING_DELAY_MIN 4	/* Waits are 2-3 usecs on typical systems */
+#define	POLLING_DELAY_MAX 256
+
 static void	kcs_clear_obf(struct ipmi_softc *, int);
 static void	kcs_error(struct ipmi_softc *);
-static int	kcs_wait_for_ibf(struct ipmi_softc *, int);
-static int	kcs_wait_for_obf(struct ipmi_softc *, int);
+static int	kcs_wait_for_ibf(struct ipmi_softc *, bool);
+static int	kcs_wait_for_obf(struct ipmi_softc *, bool);
 
 static int
-kcs_wait_for_ibf(struct ipmi_softc *sc, int state)
+kcs_wait(struct ipmi_softc *sc, int value, int mask)
 {
 	int status, start = ticks;
+	int delay_usec = POLLING_DELAY_MIN;
 
 	status = INB(sc, KCS_CTL_STS);
-	if (state == 0) {
-		/* WAIT FOR IBF = 0 */
-		while (ticks - start < MAX_TIMEOUT && status & KCS_STATUS_IBF) {
-			DELAY(100);
-			status = INB(sc, KCS_CTL_STS);
-		}
-	} else {
-		/* WAIT FOR IBF = 1 */
-		while (ticks - start < MAX_TIMEOUT &&
-		    !(status & KCS_STATUS_IBF)) {
-			DELAY(100);
-			status = INB(sc, KCS_CTL_STS);
-		}
+	while (ticks - start < MAX_TIMEOUT && (status & mask) != value) {
+		/*
+		 * The wait delay is increased exponentially to avoid putting
+		 * significant load on I/O bus.
+		 */
+		DELAY(delay_usec);
+		status = INB(sc, KCS_CTL_STS);
+		if (delay_usec < POLLING_DELAY_MAX)
+			delay_usec *= 2;
 	}
 	return (status);
 }
 
 static int
-kcs_wait_for_obf(struct ipmi_softc *sc, int state)
+kcs_wait_for_ibf(struct ipmi_softc *sc, bool level)
 {
-	int status, start = ticks;
 
-	status = INB(sc, KCS_CTL_STS);
-	if (state == 0) {
-		/* WAIT FOR OBF = 0 */
-		while (ticks - start < MAX_TIMEOUT && status & KCS_STATUS_OBF) {
-			DELAY(100);
-			status = INB(sc, KCS_CTL_STS);
-		}
-	} else {
-		/* WAIT FOR OBF = 1 */
-		while (ticks - start < MAX_TIMEOUT &&
-		    !(status & KCS_STATUS_OBF)) {
-			DELAY(100);
-			status = INB(sc, KCS_CTL_STS);
-		}
-	}
-	return (status);
+	return (kcs_wait(sc, level ? KCS_STATUS_IBF : 0, KCS_STATUS_IBF));
+}
+
+static int
+kcs_wait_for_obf(struct ipmi_softc *sc, bool level)
+{
+
+	return (kcs_wait(sc, level ? KCS_STATUS_OBF : 0, KCS_STATUS_OBF));
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202004211652.03LGqv3l087087>