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