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