@@ -70,6 +70,11 @@ enum Trace {
7070 our_state : PowerState ,
7171 seq_state : Result < fmc_periph:: A0Sm , u8 > ,
7272 } ,
73+ SequencerInterrupt {
74+ our_state : PowerState ,
75+ seq_state : Result < fmc_periph:: A0Sm , u8 > ,
76+ ifr : fmc_periph:: IfrView ,
77+ } ,
7378 PowerDownError ( drv_cpu_seq_api:: SeqError ) ,
7479 Coretype {
7580 coretype0 : bool ,
@@ -85,6 +90,9 @@ enum Trace {
8590 pwrokn : u8 ,
8691 } ,
8792 Thermtrip ,
93+ A0MapoInterrupt ,
94+ SmerrInterrupt ,
95+ UnexpectedInterrupt ,
8896}
8997counted_ringbuf ! ( Trace , 128 , Trace :: None ) ;
9098
@@ -133,6 +141,8 @@ const SP5R2_PULL: sys_api::Pull = sys_api::Pull::None;
133141const SP5R3_PULL : sys_api:: Pull = sys_api:: Pull :: None ;
134142const SP5R4_PULL : sys_api:: Pull = sys_api:: Pull :: None ;
135143
144+ use gpio_irq_pins:: SEQ_IRQ ;
145+
136146////////////////////////////////////////////////////////////////////////////////
137147
138148/// Helper type which includes both sequencer and NIC state machine states
@@ -223,6 +233,10 @@ fn init() -> Result<ServerImpl, SeqError> {
223233 sys. gpio_configure_input ( SP5_TO_SP_SP5R3 , SP5R3_PULL ) ;
224234 sys. gpio_configure_input ( SP5_TO_SP_SP5R4 , SP5R4_PULL ) ;
225235
236+ // Sequencer interrupt
237+ sys. gpio_configure_input ( SEQ_IRQ , sys_api:: Pull :: None ) ;
238+ sys. gpio_irq_configure ( notifications:: SEQ_IRQ_MASK , sys_api:: Edge :: Falling ) ;
239+
226240 let spi_front = drv_spi_api:: Spi :: from ( SPI_FRONT . get_task_id ( ) ) ;
227241 let aux = drv_auxflash_api:: AuxFlash :: from ( AUXFLASH . get_task_id ( ) ) ;
228242
@@ -390,6 +404,7 @@ impl ServerImpl {
390404 fn log_state_registers ( & self ) -> StateMachineStates {
391405 let seq_api_status = ( & self . seq . seq_api_status ) . into ( ) ;
392406 let nic_api_status = ( & self . seq . nic_api_status ) . into ( ) ;
407+
393408 ringbuf_entry ! ( Trace :: RegStateValues {
394409 seq_api_status,
395410 seq_raw_status: ( & self . seq. seq_raw_status) . into( ) ,
@@ -513,6 +528,7 @@ impl ServerImpl {
513528 }
514529 } ;
515530
531+ self . enable_sequencer_interrupts ( ) ;
516532 // Flip the host flash mux so the CPU can read from it
517533 // (this is secretly infallible on Cosmo, so we can unwrap it)
518534 self . hf . set_mux ( drv_hf_api:: HfMuxState :: HostCPU ) . unwrap ( ) ;
@@ -521,6 +537,8 @@ impl ServerImpl {
521537 | ( PowerState :: A0PlusHP , PowerState :: A2 )
522538 | ( PowerState :: A0Thermtrip , PowerState :: A2 )
523539 | ( PowerState :: A0Reset , PowerState :: A2 ) => {
540+ // Disable our interrupts before we shutdown
541+ self . disable_sequencer_interrupts ( ) ;
524542 self . seq . power_ctrl . modify ( |m| m. set_a0_en ( false ) ) ;
525543 let mut okay = false ;
526544 for _ in 0 ..200 {
@@ -543,7 +561,6 @@ impl ServerImpl {
543561 // We can't do much else here, since we already cleared the
544562 // a0_en flag to disable the sequencer.
545563 }
546-
547564 // Flip the host flash mux so the SP can read from it
548565 // (this is secretly infallible on Cosmo, so we can unwrap it)
549566 self . hf . set_mux ( drv_hf_api:: HfMuxState :: SP ) . unwrap ( ) ;
@@ -571,13 +588,14 @@ impl ServerImpl {
571588
572589 /// Returns the current timer interval, in milliseconds
573590 ///
574- /// If we are in `A0`, then we are waiting for the NIC to come up; if we are
575- /// in `A0PlusHP`, we're polling for a thermtrip or for someone disabling
576- /// the NIC. In other states, there's no need to poll.
591+ /// If we are in `A0`, then we are waiting for the NIC to come up;
592+ /// Once we are in `A0PlusHP` we rely on sequencer interrupts for
593+ /// all our state transitions. We still want to catch an unexpected
594+ /// case of sequencer failure so poll for that case specifically.
577595 fn poll_interval ( & self ) -> Option < u32 > {
578596 match self . state {
579597 PowerState :: A0 => Some ( 10 ) ,
580- PowerState :: A0PlusHP => Some ( 100 ) ,
598+ PowerState :: A0PlusHP => Some ( 1000 ) ,
581599 _ => None ,
582600 }
583601 }
@@ -588,6 +606,150 @@ impl ServerImpl {
588606 set_timer_relative ( interval, notifications:: TIMER_MASK ) ;
589607 }
590608 }
609+
610+ /// Powers down to A2, if that fails for some reason just
611+ /// log an error
612+ fn emergency_a2 ( & mut self , reason : StateChangeReason ) {
613+ // Power down to A2, updating our internal state. We can't
614+ // handle errors here, so log them and continue.
615+ if let Err ( e) = self . set_state_impl ( PowerState :: A2 , reason) {
616+ ringbuf_entry ! ( Trace :: PowerDownError ( e) )
617+ }
618+ }
619+
620+ fn enable_sequencer_interrupts ( & mut self ) {
621+ // Clear `ifr` in case spurious flags accumulated while disabled
622+ self . seq . ifr . modify ( |m| {
623+ m. set_fanfault ( false ) ;
624+ m. set_thermtrip ( false ) ;
625+ m. set_smerr_assert ( false ) ;
626+ m. set_a0mapo ( false ) ;
627+ m. set_nicmapo ( false ) ;
628+ m. set_amd_pwrok_fedge ( false ) ;
629+ m. set_amd_rstn_fedge ( false ) ;
630+ } ) ;
631+
632+ let _ = self . sys . gpio_irq_control (
633+ notifications:: SEQ_IRQ_MASK ,
634+ sys_api:: IrqControl :: Enable ,
635+ ) ;
636+ self . seq . ier . modify ( |m| {
637+ m. set_fanfault ( true ) ;
638+ m. set_thermtrip ( true ) ;
639+ m. set_smerr_assert ( true ) ;
640+ m. set_a0mapo ( true ) ;
641+ m. set_nicmapo ( true ) ;
642+ m. set_amd_pwrok_fedge ( true ) ;
643+ m. set_amd_rstn_fedge ( true ) ;
644+ } ) ;
645+ }
646+
647+ fn disable_sequencer_interrupts ( & mut self ) {
648+ self . seq . ier . modify ( |m| {
649+ m. set_fanfault ( false ) ;
650+ m. set_thermtrip ( false ) ;
651+ m. set_smerr_assert ( false ) ;
652+ m. set_a0mapo ( false ) ;
653+ m. set_nicmapo ( false ) ;
654+ m. set_amd_pwrok_fedge ( false ) ;
655+ m. set_amd_rstn_fedge ( false ) ;
656+ } ) ;
657+ let _ = self . sys . gpio_irq_control (
658+ notifications:: SEQ_IRQ_MASK ,
659+ sys_api:: IrqControl :: Disable ,
660+ ) ;
661+ }
662+
663+ fn handle_sequencer_interrupt ( & mut self ) {
664+ let ifr = self . seq . ifr . view ( ) ;
665+
666+ let state = self . log_state_registers ( ) ;
667+ ringbuf_entry ! ( Trace :: SequencerInterrupt {
668+ our_state: self . state,
669+ seq_state: state. seq,
670+ ifr,
671+ } ) ;
672+
673+ enum InternalAction {
674+ Reset ,
675+ ThermTrip ,
676+ Smerr ,
677+ Mapo ,
678+ None ,
679+ }
680+
681+ // We check these in lowest to highest priority. We start with
682+ // reset since we expect the CPU to handle that nicely.
683+ // Thermal trip is a terminal state in that we log it but don't
684+ // actually make any changes to the sequencer.
685+ // SMERR is treated as a higher priority than MAPO arbitrarily.
686+ // we probably(?) won't see multiple of these set at a time but
687+ // it's important to account for that case;
688+
689+ let mut action = InternalAction :: None ;
690+
691+ 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+
695+ // counters and ifr are cleared in the A2 -> A0 transition
696+ // host_sp_comms will be notified of this change and will
697+ // call back into this task to reboot the system (going to
698+ // A2 then back into A0)
699+ ringbuf_entry ! ( Trace :: ResetCounts { rstn, pwrokn } ) ;
700+ action = InternalAction :: Reset ;
701+ }
702+
703+ if ifr. thermtrip {
704+ self . seq . ifr . modify ( |h| h. set_thermtrip ( false ) ) ;
705+ ringbuf_entry ! ( Trace :: Thermtrip ) ;
706+ action = InternalAction :: ThermTrip ;
707+ // Great place for an ereport?
708+ }
709+
710+ if ifr. a0mapo {
711+ self . log_pg_registers ( ) ;
712+ self . seq . ifr . modify ( |h| h. set_a0mapo ( false ) ) ;
713+ ringbuf_entry ! ( Trace :: A0MapoInterrupt ) ;
714+ action = InternalAction :: Mapo ;
715+ // Great place for an ereport?
716+ }
717+
718+ if ifr. smerr_assert {
719+ self . seq . ifr . modify ( |h| h. set_smerr_assert ( false ) ) ;
720+ ringbuf_entry ! ( Trace :: SmerrInterrupt ) ;
721+ action = InternalAction :: Smerr ;
722+ // Great place for an ereport?
723+ }
724+ // Fan Fault is unconnected
725+ // NIC MAPO is unconnected
726+
727+ match action {
728+ InternalAction :: Reset => {
729+ // host_sp_comms will be notified of this change and will
730+ // call back into this task to reboot the system (going to
731+ // A2 then back into A0)
732+ self . set_state_internal ( PowerState :: A0Reset ) ;
733+ }
734+ InternalAction :: ThermTrip => {
735+ // This is a terminal state; we set our state to `A0Thermtrip`
736+ // but do not expect any other task to take action right now
737+ self . set_state_internal ( PowerState :: A0Thermtrip ) ;
738+ }
739+ InternalAction :: Mapo => {
740+ // This is a terminal state (for now)
741+ self . emergency_a2 ( StateChangeReason :: A0Mapo ) ;
742+ }
743+ InternalAction :: Smerr => {
744+ // This is a terminal state (for now)
745+ self . emergency_a2 ( StateChangeReason :: SmerrAssert ) ;
746+ }
747+ InternalAction :: None => {
748+ // This is unexpected, logging is the best we can do
749+ ringbuf_entry ! ( Trace :: UnexpectedInterrupt ) ;
750+ }
751+ } ;
752+ }
591753}
592754
593755impl idl:: InOrderSequencerImpl for ServerImpl {
@@ -641,10 +803,14 @@ impl idl::InOrderSequencerImpl for ServerImpl {
641803
642804impl NotificationHandler for ServerImpl {
643805 fn current_notification_mask ( & self ) -> u32 {
644- notifications:: TIMER_MASK
806+ notifications:: TIMER_MASK | notifications :: SEQ_IRQ_MASK
645807 }
646808
647809 fn handle_notification ( & mut self , bits : u32 ) {
810+ if ( bits & notifications:: SEQ_IRQ_MASK ) != 0 {
811+ self . handle_sequencer_interrupt ( ) ;
812+ }
813+
648814 if ( bits & notifications:: TIMER_MASK ) == 0 {
649815 return ;
650816 }
@@ -672,32 +838,7 @@ impl NotificationHandler for ServerImpl {
672838 } ) ;
673839 self . log_pg_registers ( ) ;
674840
675- // Power down to A2, updating our internal state. We can't
676- // handle errors here, so log them and continue.
677- if let Err ( e) = self
678- . set_state_impl ( PowerState :: A2 , StateChangeReason :: Other )
679- {
680- ringbuf_entry ! ( Trace :: PowerDownError ( e) )
681- }
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- }
841+ self . emergency_a2 ( StateChangeReason :: Unknown ) ;
701842 }
702843 }
703844
@@ -721,3 +862,4 @@ mod fmc_periph {
721862}
722863
723864include ! ( concat!( env!( "OUT_DIR" ) , "/notifications.rs" ) ) ;
865+ include ! ( concat!( env!( "OUT_DIR" ) , "/gpio_irq_pins.rs" ) ) ;
0 commit comments