svn commit: r348996 - head/sys/dev/ipmi
Jonathan T. Looney
jtl at FreeBSD.org
Wed Jun 12 16:06:32 UTC 2019
Author: jtl
Date: Wed Jun 12 16:06:31 2019
New Revision: 348996
URL: https://svnweb.freebsd.org/changeset/base/348996
Log:
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.
Submitted by: Loic Prylli <lprylli at netflix.com>
Reviewed by: jhb
MFC after: 2 weeks
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D20527
Modified:
head/sys/dev/ipmi/ipmi_kcs.c
Modified: head/sys/dev/ipmi/ipmi_kcs.c
==============================================================================
--- head/sys/dev/ipmi/ipmi_kcs.c Wed Jun 12 16:05:20 2019 (r348995)
+++ head/sys/dev/ipmi/ipmi_kcs.c Wed Jun 12 16:06:31 2019 (r348996)
@@ -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
More information about the svn-src-all
mailing list