• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use crate::{BusAccessInfo, BusDevice};
6 use acpi_tables::{aml, aml::Aml};
7 use base::{
8     error, warn, AsRawDescriptor, Descriptor, Event, PollToken, RawDescriptor, Tube, WaitContext,
9 };
10 use power_monitor::{BatteryStatus, CreatePowerMonitorFn};
11 use std::fmt::{self, Display};
12 use std::sync::Arc;
13 use std::thread;
14 use sync::Mutex;
15 use vm_control::{BatControlCommand, BatControlResult};
16 
17 /// Errors for battery devices.
18 #[derive(Debug)]
19 pub enum BatteryError {
20     Non32BitMmioAddress,
21 }
22 
23 impl Display for BatteryError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result24     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25         use self::BatteryError::*;
26 
27         match self {
28             Non32BitMmioAddress => write!(f, "Non 32-bit mmio address space"),
29         }
30     }
31 }
32 
33 type Result<T> = std::result::Result<T, BatteryError>;
34 
35 /// the GoldFish Battery MMIO length.
36 pub const GOLDFISHBAT_MMIO_LEN: u64 = 0x1000;
37 
38 struct GoldfishBatteryState {
39     // interrupt state
40     int_status: u32,
41     int_enable: u32,
42     // AC state
43     ac_online: u32,
44     // Battery state
45     status: u32,
46     health: u32,
47     present: u32,
48     capacity: u32,
49     voltage: u32,
50     current: u32,
51     charge_counter: u32,
52     charge_full: u32,
53 }
54 
55 macro_rules! create_battery_func {
56     // $property: the battery property which is going to be modified.
57     // $int: the interrupt status which is going to be set to notify the guest.
58     ($fn:ident, $property:ident, $int:ident) => {
59         fn $fn(&mut self, value: u32) -> bool {
60             let old = std::mem::replace(&mut self.$property, value);
61             old != self.$property && self.set_int_status($int)
62         }
63     };
64 }
65 
66 impl GoldfishBatteryState {
set_int_status(&mut self, mask: u32) -> bool67     fn set_int_status(&mut self, mask: u32) -> bool {
68         if ((self.int_enable & mask) != 0) && ((self.int_status & mask) == 0) {
69             self.int_status |= mask;
70             return true;
71         }
72         false
73     }
74 
int_status(&self) -> u3275     fn int_status(&self) -> u32 {
76         self.int_status
77     }
78 
79     create_battery_func!(set_ac_online, ac_online, AC_STATUS_CHANGED);
80 
81     create_battery_func!(set_status, status, BATTERY_STATUS_CHANGED);
82 
83     create_battery_func!(set_health, health, BATTERY_STATUS_CHANGED);
84 
85     create_battery_func!(set_present, present, BATTERY_STATUS_CHANGED);
86 
87     create_battery_func!(set_capacity, capacity, BATTERY_STATUS_CHANGED);
88 
89     create_battery_func!(set_voltage, voltage, BATTERY_STATUS_CHANGED);
90 
91     create_battery_func!(set_current, current, BATTERY_STATUS_CHANGED);
92 
93     create_battery_func!(set_charge_counter, charge_counter, BATTERY_STATUS_CHANGED);
94 
95     create_battery_func!(set_charge_full, charge_full, BATTERY_STATUS_CHANGED);
96 }
97 
98 /// GoldFish Battery state
99 pub struct GoldfishBattery {
100     state: Arc<Mutex<GoldfishBatteryState>>,
101     mmio_base: u32,
102     irq_num: u32,
103     irq_evt: Event,
104     irq_resample_evt: Event,
105     activated: bool,
106     monitor_thread: Option<thread::JoinHandle<()>>,
107     kill_evt: Option<Event>,
108     tube: Option<Tube>,
109     create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
110 }
111 
112 /// Goldfish Battery MMIO offset
113 const BATTERY_INT_STATUS: u32 = 0;
114 const BATTERY_INT_ENABLE: u32 = 0x4;
115 const BATTERY_AC_ONLINE: u32 = 0x8;
116 const BATTERY_STATUS: u32 = 0xC;
117 const BATTERY_HEALTH: u32 = 0x10;
118 const BATTERY_PRESENT: u32 = 0x14;
119 const BATTERY_CAPACITY: u32 = 0x18;
120 const BATTERY_VOLTAGE: u32 = 0x1C;
121 const BATTERY_TEMP: u32 = 0x20;
122 const BATTERY_CHARGE_COUNTER: u32 = 0x24;
123 const BATTERY_VOLTAGE_MAX: u32 = 0x28;
124 const BATTERY_CURRENT_MAX: u32 = 0x2C;
125 const BATTERY_CURRENT_NOW: u32 = 0x30;
126 const BATTERY_CURRENT_AVG: u32 = 0x34;
127 const BATTERY_CHARGE_FULL_UAH: u32 = 0x38;
128 const BATTERY_CYCLE_COUNT: u32 = 0x40;
129 
130 /// Goldfish Battery interrupt bits
131 const BATTERY_STATUS_CHANGED: u32 = 1 << 0;
132 const AC_STATUS_CHANGED: u32 = 1 << 1;
133 const BATTERY_INT_MASK: u32 = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED;
134 
135 /// Goldfish Battery status
136 const BATTERY_STATUS_VAL_UNKNOWN: u32 = 0;
137 const BATTERY_STATUS_VAL_CHARGING: u32 = 1;
138 const BATTERY_STATUS_VAL_DISCHARGING: u32 = 2;
139 const BATTERY_STATUS_VAL_NOT_CHARGING: u32 = 3;
140 
141 /// Goldfish Battery health
142 const BATTERY_HEALTH_VAL_UNKNOWN: u32 = 0;
143 
command_monitor( tube: Tube, irq_evt: Event, irq_resample_evt: Event, kill_evt: Event, state: Arc<Mutex<GoldfishBatteryState>>, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, )144 fn command_monitor(
145     tube: Tube,
146     irq_evt: Event,
147     irq_resample_evt: Event,
148     kill_evt: Event,
149     state: Arc<Mutex<GoldfishBatteryState>>,
150     create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
151 ) {
152     let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
153         (&Descriptor(tube.as_raw_descriptor()), Token::Commands),
154         (
155             &Descriptor(irq_resample_evt.as_raw_descriptor()),
156             Token::Resample,
157         ),
158         (&Descriptor(kill_evt.as_raw_descriptor()), Token::Kill),
159     ]) {
160         Ok(pc) => pc,
161         Err(e) => {
162             error!("failed to build WaitContext: {}", e);
163             return;
164         }
165     };
166 
167     let mut power_monitor = match create_power_monitor {
168         Some(f) => match f() {
169             Ok(p) => match wait_ctx.add(&Descriptor(p.poll_fd()), Token::Monitor) {
170                 Ok(()) => Some(p),
171                 Err(e) => {
172                     error!("failed to add power monitor to poll context: {}", e);
173                     None
174                 }
175             },
176             Err(e) => {
177                 error!("failed to create power monitor: {}", e);
178                 None
179             }
180         },
181         None => None,
182     };
183 
184     #[derive(PollToken)]
185     enum Token {
186         Commands,
187         Resample,
188         Kill,
189         Monitor,
190     }
191 
192     'poll: loop {
193         let events = match wait_ctx.wait() {
194             Ok(v) => v,
195             Err(e) => {
196                 error!("error while polling for events: {}", e);
197                 break;
198             }
199         };
200 
201         for event in events.iter().filter(|e| e.is_readable) {
202             match event.token {
203                 Token::Commands => {
204                     let req = match tube.recv() {
205                         Ok(req) => req,
206                         Err(e) => {
207                             error!("failed to receive request: {}", e);
208                             continue;
209                         }
210                     };
211 
212                     let mut bat_state = state.lock();
213                     let inject_irq = match req {
214                         BatControlCommand::SetStatus(status) => bat_state.set_status(status.into()),
215                         BatControlCommand::SetHealth(health) => bat_state.set_health(health.into()),
216                         BatControlCommand::SetPresent(present) => {
217                             let v = if present != 0 { 1 } else { 0 };
218                             bat_state.set_present(v)
219                         }
220                         BatControlCommand::SetCapacity(capacity) => {
221                             let v = std::cmp::min(capacity, 100);
222                             bat_state.set_capacity(v)
223                         }
224                         BatControlCommand::SetACOnline(ac_online) => {
225                             let v = if ac_online != 0 { 1 } else { 0 };
226                             bat_state.set_ac_online(v)
227                         }
228                     };
229 
230                     if inject_irq {
231                         let _ = irq_evt.write(1);
232                     }
233 
234                     if let Err(e) = tube.send(&BatControlResult::Ok) {
235                         error!("failed to send response: {}", e);
236                     }
237                 }
238 
239                 Token::Monitor => {
240                     // Safe because power_monitor must be populated if Token::Monitor is triggered.
241                     let data = match power_monitor.as_mut().unwrap().read_message() {
242                         Ok(Some(d)) => d,
243                         Ok(None) => continue,
244                         Err(e) => {
245                             error!("failed to read new power data: {}", e);
246                             continue;
247                         }
248                     };
249 
250                     let mut bat_state = state.lock();
251 
252                     // Each set_* function called below returns true when interrupt bits
253                     // (*_STATUS_CHANGED) changed. If `inject_irq` is true after we attempt to
254                     // update each field, inject an interrupt.
255                     let mut inject_irq =
256                         bat_state.set_ac_online(if data.ac_online { 1 } else { 0 });
257 
258                     match data.battery {
259                         Some(battery_data) => {
260                             inject_irq |= bat_state.set_capacity(battery_data.percent);
261                             let battery_status = match battery_data.status {
262                                 BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
263                                 BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
264                                 BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
265                                 BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
266                             };
267                             inject_irq |= bat_state.set_status(battery_status);
268                             inject_irq |= bat_state.set_voltage(battery_data.voltage);
269                             inject_irq |= bat_state.set_current(battery_data.current);
270                             inject_irq |= bat_state.set_charge_counter(battery_data.charge_counter);
271                             inject_irq |= bat_state.set_charge_full(battery_data.charge_full);
272                         }
273                         None => {
274                             inject_irq |= bat_state.set_present(0);
275                         }
276                     }
277 
278                     if inject_irq {
279                         let _ = irq_evt.write(1);
280                     }
281                 }
282 
283                 Token::Resample => {
284                     let _ = irq_resample_evt.read();
285                     if state.lock().int_status() != 0 {
286                         let _ = irq_evt.write(1);
287                     }
288                 }
289 
290                 Token::Kill => break 'poll,
291             }
292         }
293     }
294 }
295 
296 impl GoldfishBattery {
297     /// Create GoldfishBattery device model
298     ///
299     /// * `mmio_base` - The 32-bit mmio base address.
300     /// * `irq_num` - The corresponding interrupt number of the irq_evt
301     ///               which will be put into the ACPI DSDT.
302     /// * `irq_evt` - The interrupt event used to notify driver about
303     ///               the battery properties changing.
304     /// * `irq_resample_evt` - Resample interrupt event notified at EOI.
305     /// * `socket` - Battery control socket
new( mmio_base: u64, irq_num: u32, irq_evt: Event, irq_resample_evt: Event, tube: Tube, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, ) -> Result<Self>306     pub fn new(
307         mmio_base: u64,
308         irq_num: u32,
309         irq_evt: Event,
310         irq_resample_evt: Event,
311         tube: Tube,
312         create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
313     ) -> Result<Self> {
314         if mmio_base + GOLDFISHBAT_MMIO_LEN - 1 > u32::MAX as u64 {
315             return Err(BatteryError::Non32BitMmioAddress);
316         }
317         let state = Arc::new(Mutex::new(GoldfishBatteryState {
318             capacity: 50,
319             health: BATTERY_HEALTH_VAL_UNKNOWN,
320             present: 1,
321             status: BATTERY_STATUS_VAL_UNKNOWN,
322             ac_online: 1,
323             int_enable: 0,
324             int_status: 0,
325             voltage: 0,
326             current: 0,
327             charge_counter: 0,
328             charge_full: 0,
329         }));
330 
331         Ok(GoldfishBattery {
332             state,
333             mmio_base: mmio_base as u32,
334             irq_num,
335             irq_evt,
336             irq_resample_evt,
337             activated: false,
338             monitor_thread: None,
339             kill_evt: None,
340             tube: Some(tube),
341             create_power_monitor,
342         })
343     }
344 
345     /// return the fds used by this device
keep_rds(&self) -> Vec<RawDescriptor>346     pub fn keep_rds(&self) -> Vec<RawDescriptor> {
347         let mut rds = vec![
348             self.irq_evt.as_raw_descriptor(),
349             self.irq_resample_evt.as_raw_descriptor(),
350         ];
351 
352         if let Some(tube) = &self.tube {
353             rds.push(tube.as_raw_descriptor());
354         }
355 
356         rds
357     }
358 
359     /// start a monitor thread to monitor the events from host
start_monitor(&mut self)360     fn start_monitor(&mut self) {
361         if self.activated {
362             return;
363         }
364 
365         let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
366             Ok(v) => v,
367             Err(e) => {
368                 error!(
369                     "{}: failed to create kill EventFd pair: {}",
370                     self.debug_label(),
371                     e
372                 );
373                 return;
374             }
375         };
376 
377         if let Some(tube) = self.tube.take() {
378             let irq_evt = self.irq_evt.try_clone().unwrap();
379             let irq_resample_evt = self.irq_resample_evt.try_clone().unwrap();
380             let bat_state = self.state.clone();
381 
382             let create_monitor_fn = self.create_power_monitor.take();
383             let monitor_result = thread::Builder::new()
384                 .name(self.debug_label())
385                 .spawn(move || {
386                     command_monitor(
387                         tube,
388                         irq_evt,
389                         irq_resample_evt,
390                         kill_evt,
391                         bat_state,
392                         create_monitor_fn,
393                     );
394                 });
395 
396             self.monitor_thread = match monitor_result {
397                 Err(e) => {
398                     error!(
399                         "{}: failed to spawn PowerIO monitor: {}",
400                         self.debug_label(),
401                         e
402                     );
403                     return;
404                 }
405                 Ok(join_handle) => Some(join_handle),
406             };
407             self.kill_evt = Some(self_kill_evt);
408             self.activated = true;
409         }
410     }
411 }
412 
413 impl Drop for GoldfishBattery {
drop(&mut self)414     fn drop(&mut self) {
415         if let Some(kill_evt) = self.kill_evt.take() {
416             // Ignore the result because there is nothing we can do with a failure.
417             let _ = kill_evt.write(1);
418         }
419         if let Some(thread) = self.monitor_thread.take() {
420             let _ = thread.join();
421         }
422     }
423 }
424 
425 impl BusDevice for GoldfishBattery {
debug_label(&self) -> String426     fn debug_label(&self) -> String {
427         "GoldfishBattery".to_owned()
428     }
429 
read(&mut self, info: BusAccessInfo, data: &mut [u8])430     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
431         if data.len() != std::mem::size_of::<u32>() {
432             warn!(
433                 "{}: unsupported read length {}, only support 4bytes read",
434                 self.debug_label(),
435                 data.len()
436             );
437             return;
438         }
439 
440         let val = match info.offset as u32 {
441             BATTERY_INT_STATUS => {
442                 // read to clear the interrupt status
443                 std::mem::replace(&mut self.state.lock().int_status, 0)
444             }
445             BATTERY_INT_ENABLE => self.state.lock().int_enable,
446             BATTERY_AC_ONLINE => self.state.lock().ac_online,
447             BATTERY_STATUS => self.state.lock().status,
448             BATTERY_HEALTH => self.state.lock().health,
449             BATTERY_PRESENT => self.state.lock().present,
450             BATTERY_CAPACITY => self.state.lock().capacity,
451             BATTERY_VOLTAGE => self.state.lock().voltage,
452             BATTERY_TEMP => 0,
453             BATTERY_CHARGE_COUNTER => self.state.lock().charge_counter,
454             BATTERY_VOLTAGE_MAX => 0,
455             BATTERY_CURRENT_MAX => 0,
456             BATTERY_CURRENT_NOW => self.state.lock().current,
457             BATTERY_CURRENT_AVG => 0,
458             BATTERY_CHARGE_FULL_UAH => self.state.lock().charge_full,
459             BATTERY_CYCLE_COUNT => 0,
460             _ => {
461                 warn!("{}: unsupported read address {}", self.debug_label(), info);
462                 return;
463             }
464         };
465 
466         let val_arr = val.to_ne_bytes();
467         data.copy_from_slice(&val_arr);
468     }
469 
write(&mut self, info: BusAccessInfo, data: &[u8])470     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
471         if data.len() != std::mem::size_of::<u32>() {
472             warn!(
473                 "{}: unsupported write length {}, only support 4bytes write",
474                 self.debug_label(),
475                 data.len()
476             );
477             return;
478         }
479 
480         let mut val_arr = u32::to_ne_bytes(0u32);
481         val_arr.copy_from_slice(data);
482         let val = u32::from_ne_bytes(val_arr);
483 
484         match info.offset as u32 {
485             BATTERY_INT_ENABLE => {
486                 self.state.lock().int_enable = val;
487                 if (val & BATTERY_INT_MASK) != 0 && !self.activated {
488                     self.start_monitor();
489                 }
490             }
491             _ => {
492                 warn!("{}: Bad write to address {}", self.debug_label(), info);
493             }
494         };
495     }
496 }
497 
498 impl Aml for GoldfishBattery {
to_aml_bytes(&self, bytes: &mut Vec<u8>)499     fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
500         aml::Device::new(
501             "GFBY".into(),
502             vec![
503                 &aml::Name::new("_HID".into(), &"GFSH0001"),
504                 &aml::Name::new(
505                     "_CRS".into(),
506                     &aml::ResourceTemplate::new(vec![
507                         &aml::Memory32Fixed::new(true, self.mmio_base, GOLDFISHBAT_MMIO_LEN as u32),
508                         &aml::Interrupt::new(true, false, false, true, self.irq_num),
509                     ]),
510                 ),
511             ],
512         )
513         .to_aml_bytes(bytes);
514     }
515 }
516