@@ -12,10 +12,9 @@ use log::Level;
12
12
#[ cfg( feature = "linux_pio" ) ]
13
13
use nix:: unistd:: Uid ;
14
14
use num:: FromPrimitive ;
15
- #[ cfg( feature = "linux_pio" ) ]
16
- use std:: sync:: { Arc , Mutex } ;
15
+ use spin:: Mutex ;
17
16
18
- use crate :: chromium_ec:: { has_mec , portio_mec } ;
17
+ use crate :: chromium_ec:: { portio_mec , EC_MEMMAP_ID } ;
19
18
use crate :: os_specific;
20
19
use crate :: util;
21
20
@@ -172,65 +171,68 @@ fn transfer_read(port: u16, address: u16, size: u16) -> Vec<u8> {
172
171
buffer
173
172
}
174
173
175
- #[ cfg( feature = "linux_pio" ) ]
174
+ #[ derive( PartialEq ) ]
175
+ #[ allow( dead_code) ]
176
176
enum Initialized {
177
177
NotYet ,
178
+ SucceededMec ,
178
179
Succeeded ,
179
180
Failed ,
180
181
}
181
182
182
- #[ cfg( feature = "linux_pio" ) ]
183
183
lazy_static ! {
184
- static ref INITIALIZED : Arc < Mutex <Initialized >> = Arc :: new ( Mutex :: new( Initialized :: NotYet ) ) ;
184
+ static ref INITIALIZED : Mutex <Initialized > = Mutex :: new( Initialized :: NotYet ) ;
185
185
}
186
186
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
191
190
}
192
191
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" ) ]
196
192
fn init ( ) -> bool {
197
- let mut init = INITIALIZED . lock ( ) . unwrap ( ) ;
193
+ let mut init = INITIALIZED . lock ( ) ;
198
194
match * init {
199
195
// Can directly give up, trying again won't help
200
196
Initialized :: Failed => return false ,
201
197
// Already initialized, no need to do anything.
202
- Initialized :: Succeeded => return true ,
198
+ Initialized :: Succeeded | Initialized :: SucceededMec => return true ,
203
199
Initialized :: NotYet => { }
204
200
}
205
201
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" ) ]
206
213
if !Uid :: effective ( ) . is_root ( ) {
207
214
error ! ( "Must be root to use port based I/O for EC communication." ) ;
208
215
* init = Initialized :: Failed ;
209
216
return false ;
210
217
}
211
-
218
+ # [ cfg ( feature = "linux_pio" ) ]
212
219
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 ;
232
225
}
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 ) ;
233
234
}
235
+
234
236
* init = Initialized :: Succeeded ;
235
237
true
236
238
}
0 commit comments