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@netflix.com> Reviewed by: jhb MFC after: 2 weeks Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D20527
This commit is contained in:
parent
51cb7e55fe
commit
29aa313806
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user