mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
apple_bce: fix cold boot panic in mailbox send
Poll mailbox reply registers with DELAY() when the system is still cold, falling back to the interrupt-driven sema_timedwait path once timers are available. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58871
This commit is contained in:
1 parent
ac5440ec24
commit
ba28690cc6
1 file changed
+37
-13
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sema.h>
|
||||
@@ -62,20 +63,41 @@ bce_mailbox_send(struct bce_mailbox *mb, uint64_t msg, uint64_t *recv,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Wait for interrupt-driven reply */
|
||||
if (sema_timedwait(&mb->mb_cmpl, hz * timeout_ms / 1000) != 0) {
|
||||
/* Timeout -- reset to idle */
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (ETIMEDOUT);
|
||||
if (cold) {
|
||||
/*
|
||||
* During early boot, timer-backed sleeps are not available.
|
||||
* Poll the hardware directly, but account for an installed
|
||||
* interrupt handler consuming the reply first.
|
||||
*/
|
||||
unsigned int waited = 0;
|
||||
|
||||
while (waited < timeout_ms * 1000) {
|
||||
if (atomic_load_int(&mb->status) == 2)
|
||||
break;
|
||||
(void)bce_mailbox_handle_interrupt(mb);
|
||||
if (atomic_load_int(&mb->status) == 2)
|
||||
break;
|
||||
DELAY(100);
|
||||
waited += 100;
|
||||
}
|
||||
if (atomic_load_int(&mb->status) != 2) {
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
} else {
|
||||
/* Wait for interrupt-driven reply */
|
||||
if (sema_timedwait(&mb->mb_cmpl,
|
||||
hz * timeout_ms / 1000) != 0) {
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
if (atomic_load_int(&mb->status) != 2) {
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_load_int(&mb->status) != 2) {
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
|
||||
if (recv != NULL)
|
||||
*recv = mb->mb_result;
|
||||
*recv = mb->mb_result;
|
||||
|
||||
atomic_store_int(&mb->status, 0);
|
||||
return (0);
|
||||
@@ -106,7 +128,9 @@ bce_mailbox_handle_interrupt(struct bce_mailbox *mb)
|
||||
|
||||
if (atomic_load_int(&mb->status) == 1) {
|
||||
atomic_store_int(&mb->status, 2);
|
||||
sema_post(&mb->mb_cmpl);
|
||||
/* A cold sender polls status and must not leave a token. */
|
||||
if (!cold)
|
||||
sema_post(&mb->mb_cmpl);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
Reference in new issue
Block a user