summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Lojewski <github@meklort.com>2021-02-06 12:19:49 -0700
committerGitHub <noreply@github.com>2021-02-06 12:19:49 -0700
commit137e8d35f9b566b05b4ed8768f822a2232cdf639 (patch)
tree2b21d86b4580d8582fa692bed0e56512eaff5540
parentbbd2bb18c7ba73d3ff180532435de241d2afc21e (diff)
downloadbcm5719-ortega-137e8d35f9b566b05b4ed8768f822a2232cdf639.tar.gz
bcm5719-ortega-137e8d35f9b566b05b4ed8768f822a2232cdf639.zip
ape: Initialize the network PHY after a GRC reset. (#205)
This change also minimizes a race condition in the event that a GRC reset happened before the Network_checkEnableState check, the firmware could have issue multiple reload commands. Check for this case and skip the APE mode change reset as a reset will immediately follow.
-rw-r--r--ape/include/ape_main.h1
-rw-r--r--ape/main.c135
2 files changed, 97 insertions, 39 deletions
diff --git a/ape/include/ape_main.h b/ape/include/ape_main.h
index 8eae90d..e5c1f0f 100644
--- a/ape/include/ape_main.h
+++ b/ape/include/ape_main.h
@@ -88,5 +88,6 @@ void __attribute__((interrupt)) IRQ_RxPacketEven(void);
void __attribute__((interrupt)) IRQ_RxPacketOdd(void);
void __attribute__((interrupt)) IRQ_RMU(void);
void __attribute__((interrupt)) IRQ_VoltageSource(void);
+void __attribute__((interrupt)) IRQ_PowerStatusChanged(void);
#endif /* APE_MAIN_H */
diff --git a/ape/main.c b/ape/main.c
index c86820a..39ad8b3 100644
--- a/ape/main.c
+++ b/ape/main.c
@@ -68,6 +68,7 @@
#define RX_CPU_RESET_TIMEOUT_MS (1000) /* Wait up to 1 second for each RX CPU to start */
static NetworkPort_t *gPort;
+static bool gResetOccurred;
void handleCommand(volatile SHM_t *shm)
{
@@ -263,6 +264,32 @@ void checkSupply(void)
}
}
+void __attribute__((interrupt)) IRQ_PowerStatusChanged(void)
+{
+ RegAPEStatus_t status;
+ RegAPEStatus2_t status2;
+ status.r32 = APE.Status.r32;
+ status2.r32 = APE.Status2.r32;
+
+ // Clear Interrupts
+ APE.Status.r32 = status.r32;
+ APE.Status2.r32 = status2.r32;
+
+ NVIC.InterruptClearPending.r32 = NVIC_INTERRUPT_CLEAR_PENDING_CLRPEND_GENERAL_RESET;
+
+ printf("PowerStateChanged.\n");
+
+ if (!gResetOccurred)
+ {
+
+ if (status.bits.Port0GRCReset || status.bits.Port1GRCReset || status2.bits.Port2GRCReset || status2.bits.Port3GRCReset)
+ {
+ printf("GRC Reset.\n");
+ gResetOccurred = true;
+ }
+ }
+}
+
void initSHM(volatile SHM_t *shm)
{
RegSHMFwStatus_t status;
@@ -292,62 +319,91 @@ void __attribute__((noreturn)) loaderLoop(void)
initSHM(&SHM2);
initSHM(&SHM3);
+ // Enable GRC Reset / Power Status Changed interrupt
+ NVIC.InterruptSetEnable.r32 = NVIC_INTERRUPT_SET_ENABLE_SETENA_GENERAL_RESET;
+
for (;;)
{
- handleBMCPacket();
- NCSI_handlePassthrough();
- handleCommand(&SHM);
- handleCommand(&SHM1);
- handleCommand(&SHM2);
- handleCommand(&SHM3);
- checkSupply();
-
- if (host_state != SHM.HostDriverState.bits.State)
+ if (gResetOccurred)
{
- reload_type_t type;
- host_state = SHM.HostDriverState.bits.State;
-
- if (SHM_HOST_DRIVER_STATE_STATE_START == host_state)
+ RegAPEStatus_t status;
+ RegAPEStatus2_t status2;
+ status.r32 = APE.Status.r32;
+ status2.r32 = APE.Status2.r32;
+ // Wait for reset to complete.
+ if (status.bits.Port0GRCReset || status.bits.Port1GRCReset || status2.bits.Port2GRCReset || status2.bits.Port3GRCReset)
{
- type = NEVER_RESET;
- printf("host started\n");
-
- reset_allowed = true;
+ // We are waiting for the reset signals to clear before continuing.
+ // Since we never disabled the interrupt, we should never be able to get here anyway.
}
else
{
- if (SHM_HOST_DRIVER_STATE_STATE_UNLOAD == host_state)
+ gResetOccurred = false;
+
+ printf("Handling reset...\n");
+ // Perform TX reinit as the PHY / MII was also probably reset.
+ wait_for_all_rx();
+ RMU_init();
+ NCSI_reload(AS_NEEDED);
+ }
+ }
+ else
+ {
+ Network_checkPortState(gPort);
+
+ handleBMCPacket();
+ NCSI_handlePassthrough();
+ handleCommand(&SHM);
+ handleCommand(&SHM1);
+ handleCommand(&SHM2);
+ handleCommand(&SHM3);
+ checkSupply();
+
+ if (host_state != SHM.HostDriverState.bits.State)
+ {
+ reload_type_t type;
+ host_state = SHM.HostDriverState.bits.State;
+
+ if (SHM_HOST_DRIVER_STATE_STATE_START == host_state)
{
- printf("host unloaded.\n");
- type = AS_NEEDED;
+ type = NEVER_RESET;
+ printf("host started\n");
+
+ reset_allowed = true;
}
else
{
- printf("wol?\n");
- type = AS_NEEDED;
+ if (SHM_HOST_DRIVER_STATE_STATE_UNLOAD == host_state)
+ {
+ printf("host unloaded.\n");
+ type = AS_NEEDED;
+ }
+ else
+ {
+ printf("wol?\n");
+ type = AS_NEEDED;
+ }
+
+ reset_allowed = false;
}
- reset_allowed = false;
+ wait_for_all_rx();
+ RMU_init();
+ NCSI_reload(type);
}
+ else if (reset_allowed && !Network_checkEnableState(gPort) && !gResetOccurred)
+ {
+ printf("APE mode change, resetting.\n");
+ wait_for_all_rx();
+ RMU_init();
+ NCSI_reload(AS_NEEDED);
- wait_for_all_rx();
- RMU_init();
- NCSI_reload(type);
- }
- else if (reset_allowed && !Network_checkEnableState(gPort))
- {
- printf("APE mode change, resetting.\n");
- wait_for_all_rx();
- RMU_init();
- NCSI_reload(AS_NEEDED);
-
- // Update host state to make sure we don't reset twice if it's changed.
- host_state = SHM.HostDriverState.bits.State;
+ // Update host state to make sure we don't reset twice if it's changed.
+ host_state = SHM.HostDriverState.bits.State;
- reset_allowed = false;
+ reset_allowed = false;
+ }
}
-
- Network_checkPortState(gPort);
}
}
@@ -409,6 +465,7 @@ void __attribute__((noreturn)) __start()
{
// Ensure all pending interrupts are cleared.
NVIC.InterruptClearPending.r32 = 0xFFFFFFFF;
+ gResetOccurred = false;
// Switch to APE interrupt handlers
union
OpenPOWER on IntegriCloud