@@ -12,10 +12,9 @@ use log::Level;
1212#[ cfg( feature = "linux_pio" ) ]
1313use nix:: unistd:: Uid ;
1414use num:: FromPrimitive ;
15- #[ cfg( feature = "linux_pio" ) ]
16- use std:: sync:: { Arc , Mutex } ;
15+ use spin:: Mutex ;
1716
18- use crate :: chromium_ec:: { has_mec , portio_mec } ;
17+ use crate :: chromium_ec:: { portio_mec , EC_MEMMAP_ID } ;
1918use crate :: os_specific;
2019use crate :: util;
2120
@@ -172,65 +171,68 @@ fn transfer_read(port: u16, address: u16, size: u16) -> Vec<u8> {
172171 buffer
173172}
174173
175- #[ cfg( feature = "linux_pio" ) ]
174+ #[ derive( PartialEq ) ]
175+ #[ allow( dead_code) ]
176176enum Initialized {
177177 NotYet ,
178+ SucceededMec ,
178179 Succeeded ,
179180 Failed ,
180181}
181182
182- #[ cfg( feature = "linux_pio" ) ]
183183lazy_static ! {
184- static ref INITIALIZED : Arc < Mutex <Initialized >> = Arc :: new ( Mutex :: new( Initialized :: NotYet ) ) ;
184+ static ref INITIALIZED : Mutex <Initialized > = Mutex :: new( Initialized :: NotYet ) ;
185185}
186186
187- #[ cfg( not( feature = "linux_pio" ) ) ]
188- fn init ( ) -> bool {
189- // Nothing to do for bare-metal (UEFI) port I/O
190- true
187+ fn has_mec ( ) -> bool {
188+ let init = INITIALIZED . lock ( ) ;
189+ * init != Initialized :: Succeeded
191190}
192191
193- // In Linux userspace has to first request access to ioports
194- // TODO: Close these again after we're done
195- #[ cfg( feature = "linux_pio" ) ]
196192fn init ( ) -> bool {
197- let mut init = INITIALIZED . lock ( ) . unwrap ( ) ;
193+ let mut init = INITIALIZED . lock ( ) ;
198194 match * init {
199195 // Can directly give up, trying again won't help
200196 Initialized :: Failed => return false ,
201197 // Already initialized, no need to do anything.
202- Initialized :: Succeeded => return true ,
198+ Initialized :: Succeeded | Initialized :: SucceededMec => return true ,
203199 Initialized :: NotYet => { }
204200 }
205201
202+ // First try on MEC
203+ portio_mec:: init ( ) ;
204+ let ec_id = portio_mec:: transfer_read ( MEC_MEMMAP_OFFSET + EC_MEMMAP_ID , 2 ) ;
205+ if ec_id[ 0 ] == b'E' && ec_id[ 1 ] == b'C' {
206+ * init = Initialized :: SucceededMec ;
207+ return true ;
208+ }
209+
210+ // In Linux userspace has to first request access to ioports
211+ // TODO: Close these again after we're done
212+ #[ cfg( feature = "linux_pio" ) ]
206213 if !Uid :: effective ( ) . is_root ( ) {
207214 error ! ( "Must be root to use port based I/O for EC communication." ) ;
208215 * init = Initialized :: Failed ;
209216 return false ;
210217 }
211-
218+ # [ cfg ( feature = "linux_pio" ) ]
212219 unsafe {
213- if has_mec ( ) {
214- portio_mec:: mec_init ( ) ;
215- } else {
216- // 8 for request/response header, 0xFF for response
217- let res = ioperm ( EC_LPC_ADDR_HOST_ARGS as u64 , 8 + 0xFF , 1 ) ;
218- if res != 0 {
219- error ! (
220- "ioperm failed. portio driver is likely block by Linux kernel lockdown mode"
221- ) ;
222- return false ;
223- }
224-
225- let res = ioperm ( EC_LPC_ADDR_HOST_CMD as u64 , 1 , 1 ) ;
226- assert_eq ! ( res, 0 ) ;
227- let res = ioperm ( EC_LPC_ADDR_HOST_DATA as u64 , 1 , 1 ) ;
228- assert_eq ! ( res, 0 ) ;
229-
230- let res = ioperm ( NPC_MEMMAP_OFFSET as u64 , super :: EC_MEMMAP_SIZE as u64 , 1 ) ;
231- assert_eq ! ( res, 0 ) ;
220+ // 8 for request/response header, 0xFF for response
221+ let res = ioperm ( EC_LPC_ADDR_HOST_ARGS as u64 , 8 + 0xFF , 1 ) ;
222+ if res != 0 {
223+ error ! ( "ioperm failed. portio driver is likely block by Linux kernel lockdown mode" ) ;
224+ return false ;
232225 }
226+
227+ let res = ioperm ( EC_LPC_ADDR_HOST_CMD as u64 , 1 , 1 ) ;
228+ assert_eq ! ( res, 0 ) ;
229+ let res = ioperm ( EC_LPC_ADDR_HOST_DATA as u64 , 1 , 1 ) ;
230+ assert_eq ! ( res, 0 ) ;
231+
232+ let res = ioperm ( NPC_MEMMAP_OFFSET as u64 , super :: EC_MEMMAP_SIZE as u64 , 1 ) ;
233+ assert_eq ! ( res, 0 ) ;
233234 }
235+
234236 * init = Initialized :: Succeeded ;
235237 true
236238}
0 commit comments