@@ -47,17 +47,17 @@ enum Trace {
4747 Programmed ,
4848
4949 Startup {
50- early_power_rdbks : fmc_periph:: EarlyPowerRdbksDebug ,
50+ early_power_rdbks : fmc_periph:: EarlyPowerRdbksView ,
5151 } ,
5252 RegStateValues {
53- seq_api_status : fmc_periph:: SeqApiStatusDebug ,
54- seq_raw_status : fmc_periph:: SeqRawStatusDebug ,
55- nic_api_status : fmc_periph:: NicApiStatusDebug ,
56- nic_raw_status : fmc_periph:: NicRawStatusDebug ,
53+ seq_api_status : fmc_periph:: SeqApiStatusView ,
54+ seq_raw_status : fmc_periph:: SeqRawStatusView ,
55+ nic_api_status : fmc_periph:: NicApiStatusView ,
56+ nic_raw_status : fmc_periph:: NicRawStatusView ,
5757 } ,
5858 RegPgValues {
59- rail_pgs : fmc_periph:: RailPgsDebug ,
60- rail_pgs_max_hold : fmc_periph:: RailPgsMaxHoldDebug ,
59+ rail_pgs : fmc_periph:: RailPgsView ,
60+ rail_pgs_max_hold : fmc_periph:: RailPgsMaxHoldView ,
6161 } ,
6262 SetState {
6363 prev : Option < PowerState > ,
@@ -80,6 +80,11 @@ enum Trace {
8080 sp5r3 : bool ,
8181 sp5r4 : bool ,
8282 } ,
83+ ResetCounts {
84+ rstn : u8 ,
85+ pwrokn : u8 ,
86+ } ,
87+ Thermtrip ,
8388}
8489counted_ringbuf ! ( Trace , 128 , Trace :: None ) ;
8590
@@ -421,9 +426,21 @@ impl ServerImpl {
421426 use fmc_periph:: A0Sm ;
422427 match ( self . get_state_impl ( ) , state) {
423428 ( PowerState :: A2 , PowerState :: A0 ) => {
429+ // Reset edge counters in the sequencer
430+ self . seq . amd_reset_fedges . set_counts ( 0 ) ;
431+ self . seq . amd_pwrok_fedges . set_counts ( 0 ) ;
432+
433+ // Reset edge interrupts flags
434+ self . seq . ifr . modify ( |h| {
435+ h. set_amd_pwrok_fedge ( false ) ;
436+ h. set_amd_rstn_fedge ( false ) ;
437+ } ) ;
438+
439+ // Tell the sequencer to go to A0
424440 self . seq . power_ctrl . modify ( |m| m. set_a0_en ( true ) ) ;
425- let mut okay = false ;
441+
426442 // Wait 2 seconds for power-up
443+ let mut okay = false ;
427444 for _ in 0 ..200 {
428445 let state = self . log_state_registers ( ) ;
429446 match state. seq {
@@ -502,7 +519,8 @@ impl ServerImpl {
502519 }
503520 ( PowerState :: A0 , PowerState :: A2 )
504521 | ( PowerState :: A0PlusHP , PowerState :: A2 )
505- | ( PowerState :: A0Thermtrip , PowerState :: A2 ) => {
522+ | ( PowerState :: A0Thermtrip , PowerState :: A2 )
523+ | ( PowerState :: A0Reset , PowerState :: A2 ) => {
506524 self . seq . power_ctrl . modify ( |m| m. set_a0_en ( false ) ) ;
507525 let mut okay = false ;
508526 for _ in 0 ..200 {
@@ -540,10 +558,15 @@ impl ServerImpl {
540558 _ => return Err ( CpuSeqError :: IllegalTransition ) ,
541559 }
542560
561+ self . set_state_internal ( state) ;
562+ Ok ( Transition :: Changed )
563+ }
564+
565+ /// Updates our internal `state` and the global state in `jefe`
566+ fn set_state_internal ( & mut self , state : PowerState ) {
543567 self . state = state;
544568 self . jefe . set_state ( state as u32 ) ;
545569 self . poke_timer ( ) ;
546- Ok ( Transition :: Changed )
547570 }
548571
549572 /// Returns the current timer interval, in milliseconds
@@ -628,13 +651,24 @@ impl NotificationHandler for ServerImpl {
628651 let state = self . log_state_registers ( ) ;
629652 use fmc_periph:: { A0Sm , NicSm } ;
630653
631- // Detect unexpected power-off
632- match ( self . state , state. seq ) {
633- ( PowerState :: A0 | PowerState :: A0PlusHP , Ok ( A0Sm :: Done ) ) => ( ) ,
634- ( PowerState :: A0 | PowerState :: A0PlusHP , seq_state) => {
654+ // Detect when the NIC comes online
655+ // TODO: should we handle the NIC powering down while the main CPU
656+ // power remains up?
657+ if self . state == PowerState :: A0 && state. nic == Ok ( NicSm :: Done ) {
658+ self . set_state_impl (
659+ PowerState :: A0PlusHP ,
660+ StateChangeReason :: InitialPowerOn ,
661+ )
662+ . unwrap ( ) ; // this should be infallible
663+ }
664+
665+ // If Hubris thinks the system is up, do some basic checks
666+ if matches ! ( self . state, PowerState :: A0 | PowerState :: A0PlusHP ) {
667+ // Detect the FPGA powering off without us
668+ if state. seq != Ok ( A0Sm :: Done ) {
635669 ringbuf_entry ! ( Trace :: UnexpectedPowerOff {
636670 our_state: self . state,
637- seq_state,
671+ seq_state: state . seq ,
638672 } ) ;
639673 self . log_pg_registers ( ) ;
640674
@@ -645,23 +679,26 @@ impl NotificationHandler for ServerImpl {
645679 {
646680 ringbuf_entry ! ( Trace :: PowerDownError ( e) )
647681 }
682+ } else {
683+ // Check that the FPGA has not logged any reset conditions from
684+ // the CPU.
685+ let ifr = self . seq . ifr . view ( ) ;
686+ if ifr. thermtrip {
687+ self . seq . ifr . modify ( |h| h. set_thermtrip ( false ) ) ;
688+ ringbuf_entry ! ( Trace :: Thermtrip ) ;
689+ self . set_state_internal ( PowerState :: A0Thermtrip )
690+ // this is a terminal state (for now)
691+ } else if ifr. amd_pwrok_fedge || ifr. amd_rstn_fedge {
692+ let rstn = self . seq . amd_reset_fedges . counts ( ) ;
693+ let pwrokn = self . seq . amd_pwrok_fedges . counts ( ) ;
694+ ringbuf_entry ! ( Trace :: ResetCounts { rstn, pwrokn } ) ;
695+ // counters are cleared in the A2 -> A0 transition
696+ self . set_state_internal ( PowerState :: A0Reset ) ;
697+ // host_sp_comms will be notified of this change and will
698+ // call back into this task to reboot the system (going to
699+ // A2 then back into A0)
700+ }
648701 }
649- // TODO are there other states that we should check here?
650- _ => ( ) ,
651- }
652-
653- // Detect when the NIC comes online
654- match ( self . state , state. nic ) {
655- ( PowerState :: A0 , Ok ( NicSm :: Done ) ) => {
656- self . set_state_impl (
657- PowerState :: A0PlusHP ,
658- StateChangeReason :: InitialPowerOn ,
659- )
660- . unwrap ( ) ; // this should be infallible
661- }
662- // TODO: should we handle the NIC powering down while the main CPU
663- // power remains up?
664- _ => ( ) ,
665702 }
666703
667704 self . poke_timer ( ) ;
0 commit comments