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