@@ -76,17 +76,6 @@ pub enum I2cControlResult {
7676 TimedOut ,
7777}
7878
79- ///
80- /// A structure that defines interrupt control flow functions that will be
81- /// used to pass control flow into the kernel to either enable or wait for
82- /// interrupts. Note that this is deliberately a struct and not a trait,
83- /// allowing the [`I2cMuxDriver`] trait to itself be a trait object.
84- ///
85- pub struct I2cControl {
86- pub enable : fn ( u32 ) ,
87- pub wfi : fn ( u32 , I2cTimeout ) -> I2cControlResult ,
88- }
89-
9079pub struct I2cTargetControl {
9180 pub enable : fn ( u32 ) ,
9281 pub wfi : fn ( u32 ) ,
@@ -109,7 +98,6 @@ pub trait I2cMuxDriver {
10998 mux : & I2cMux < ' _ > ,
11099 controller : & I2cController < ' _ > ,
111100 sys : & sys_api:: Sys ,
112- ctrl : & I2cControl ,
113101 ) -> Result < ( ) , drv_i2c_api:: ResponseCode > ;
114102
115103 /// Reset the mux
@@ -126,7 +114,6 @@ pub trait I2cMuxDriver {
126114 mux : & I2cMux < ' _ > ,
127115 controller : & I2cController < ' _ > ,
128116 segment : Option < drv_i2c_api:: Segment > ,
129- ctrl : & I2cControl ,
130117 ) -> Result < ( ) , drv_i2c_api:: ResponseCode > ;
131118}
132119
@@ -503,15 +490,18 @@ impl I2cController<'_> {
503490 }
504491
505492 ///
506- /// A common routine to wait for interrupts with a timeout.
493+ /// A common routine to wait for interrupts, panicking the driver if the
494+ /// interrupt doesn't arrive in an arbitrarily chosen period of time.
507495 ///
508- fn wfi ( & self , ctrl : & I2cControl ) -> Result < ( ) , drv_i2c_api:: ResponseCode > {
496+ fn wfi ( & self ) -> Result < ( ) , drv_i2c_api:: ResponseCode > {
509497 //
510- // A 100 ms timeout is much, much longer than the I2C timeouts.
498+ // A 100 ms timeout is 4x longer than the I2C timeouts, but much shorter
499+ // than potential context switches when dumps are being recorded by a
500+ // high priority task.
511501 //
512502 const TIMEOUT : I2cTimeout = I2cTimeout ( 100 ) ;
513503
514- match ( ctrl . wfi ) ( self . notification , TIMEOUT ) {
504+ match wfi_raw ( self . notification , TIMEOUT ) {
515505 I2cControlResult :: TimedOut => {
516506 //
517507 // This really shouldn't happen: it means that not only did
@@ -607,7 +597,6 @@ impl I2cController<'_> {
607597 getbyte : impl Fn ( usize ) -> Option < u8 > ,
608598 mut rlen : ReadLength ,
609599 mut putbyte : impl FnMut ( usize , u8 ) -> Option < ( ) > ,
610- ctrl : & I2cControl ,
611600 ) -> Result < ( ) , drv_i2c_api:: ResponseCode > {
612601 // Assert our preconditions as described above
613602 assert ! ( wlen > 0 || rlen != ReadLength :: Fixed ( 0 ) ) ;
@@ -652,8 +641,8 @@ impl I2cController<'_> {
652641 break ;
653642 }
654643
655- self . wfi ( ctrl ) ?;
656- ( ctrl . enable ) ( notification) ;
644+ self . wfi ( ) ?;
645+ sys_irq_control ( notification, true ) ;
657646 }
658647
659648 // Get a single byte.
@@ -682,8 +671,8 @@ impl I2cController<'_> {
682671 break ;
683672 }
684673
685- self . wfi ( ctrl ) ?;
686- ( ctrl . enable ) ( notification) ;
674+ self . wfi ( ) ?;
675+ sys_irq_control ( notification, true ) ;
687676 }
688677 }
689678
@@ -730,8 +719,8 @@ impl I2cController<'_> {
730719 }
731720
732721 loop {
733- self . wfi ( ctrl ) ?;
734- ( ctrl . enable ) ( notification) ;
722+ self . wfi ( ) ?;
723+ sys_irq_control ( notification, true ) ;
735724
736725 let isr = i2c. isr . read ( ) ;
737726 ringbuf_entry ! ( Trace :: Read ( Register :: ISR , isr. bits( ) ) ) ;
@@ -785,8 +774,8 @@ impl I2cController<'_> {
785774
786775 self . check_errors ( & isr) ?;
787776
788- self . wfi ( ctrl ) ?;
789- ( ctrl . enable ) ( notification) ;
777+ self . wfi ( ) ?;
778+ sys_irq_control ( notification, true ) ;
790779 }
791780 }
792781
@@ -820,7 +809,6 @@ impl I2cController<'_> {
820809 & self ,
821810 addr : u8 ,
822811 ops : & [ I2cKonamiCode ] ,
823- ctrl : & I2cControl ,
824812 ) -> Result < ( ) , drv_i2c_api:: ResponseCode > {
825813 let i2c = self . registers ;
826814 let notification = self . notification ;
@@ -864,8 +852,8 @@ impl I2cController<'_> {
864852 break ;
865853 }
866854
867- self . wfi ( ctrl ) ?;
868- ( ctrl . enable ) ( notification) ;
855+ self . wfi ( ) ?;
856+ sys_irq_control ( notification, true ) ;
869857 }
870858 }
871859
@@ -1191,3 +1179,35 @@ impl I2cController<'_> {
11911179 }
11921180 }
11931181}
1182+
1183+ /// Waits for `event_mask` or `timeout`, whichever comes first. This is
1184+ /// factored out of `wfi` above for clarity.
1185+ ///
1186+ /// This function, like `userlib::hl`, assumes that notification bit 31 is safe
1187+ /// to use for the timer. If `event_mask` also has bit 31 set, weird things
1188+ /// will happen, don't do that.
1189+ fn wfi_raw ( event_mask : u32 , timeout : I2cTimeout ) -> I2cControlResult {
1190+ const TIMER_NOTIFICATION : u32 = 1 << 31 ;
1191+
1192+ // If the driver passes in a timeout that is large enough that it would
1193+ // overflow the kernel's 64-bit timestamp space... well, we'll do the
1194+ // best we can without compiling in an unlikely panic.
1195+ let dead = sys_get_timer ( ) . now . saturating_add ( timeout. 0 ) ;
1196+
1197+ sys_set_timer ( Some ( dead) , TIMER_NOTIFICATION ) ;
1198+
1199+ let received = sys_recv_notification ( event_mask | TIMER_NOTIFICATION ) ;
1200+
1201+ // If the event arrived _and_ our timer went off, prioritize the event and
1202+ // ignore the timeout.
1203+ if received & event_mask != 0 {
1204+ // Attempt to clear our timer. Note that this does not protect against
1205+ // the race where the kernel decided to wake us up, but the timer went
1206+ // off before we got to this point.
1207+ sys_set_timer ( None , TIMER_NOTIFICATION ) ;
1208+ I2cControlResult :: Interrupted
1209+ } else {
1210+ // The event_mask bit was not set, so:
1211+ I2cControlResult :: TimedOut
1212+ }
1213+ }
0 commit comments