xref: /aosp_15_r20/external/crosvm/devices/src/sys/linux/acpi.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 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 base::debug;
8 use base::error;
9 use base::info;
10 use base::AcpiNotifyEvent;
11 use base::NetlinkGenericSocket;
12 use sync::Mutex;
13 
14 use crate::acpi::ACPIPMError;
15 use crate::acpi::GpeResource;
16 use crate::acpi::ACPIPM_GPE_MAX;
17 use crate::AcAdapter;
18 use crate::IrqLevelEvent;
19 
get_acpi_event_sock() -> Result<Option<NetlinkGenericSocket>, ACPIPMError>20 pub(crate) fn get_acpi_event_sock() -> Result<Option<NetlinkGenericSocket>, ACPIPMError> {
21     // Get group id corresponding to acpi_mc_group of acpi_event family
22     let nl_groups: u32;
23     match get_acpi_event_group() {
24         Some(group) if group > 0 => {
25             nl_groups = 1 << (group - 1);
26             info!("Listening on acpi_mc_group of acpi_event family");
27         }
28         _ => {
29             return Err(ACPIPMError::AcpiMcGroupError);
30         }
31     }
32 
33     match NetlinkGenericSocket::new(nl_groups) {
34         Ok(acpi_sock) => Ok(Some(acpi_sock)),
35         Err(e) => Err(ACPIPMError::AcpiEventSockError(e)),
36     }
37 }
38 
get_acpi_event_group() -> Option<u32>39 fn get_acpi_event_group() -> Option<u32> {
40     // Create netlink generic socket which will be used to query about given family name
41     let netlink_ctrl_sock = match NetlinkGenericSocket::new(0) {
42         Ok(sock) => sock,
43         Err(e) => {
44             error!("netlink generic socket creation error: {}", e);
45             return None;
46         }
47     };
48 
49     let nlmsg_family_response = netlink_ctrl_sock
50         .family_name_query("acpi_event".to_string())
51         .unwrap();
52     nlmsg_family_response.get_multicast_group_id("acpi_mc_group".to_string())
53 }
54 
acpi_event_run( sci_evt: &IrqLevelEvent, acpi_event_sock: &Option<NetlinkGenericSocket>, gpe0: &Arc<Mutex<GpeResource>>, ignored_gpe: &[u32], ac_adapter: &Option<Arc<Mutex<AcAdapter>>>, )55 pub(crate) fn acpi_event_run(
56     sci_evt: &IrqLevelEvent,
57     acpi_event_sock: &Option<NetlinkGenericSocket>,
58     gpe0: &Arc<Mutex<GpeResource>>,
59     ignored_gpe: &[u32],
60     ac_adapter: &Option<Arc<Mutex<AcAdapter>>>,
61 ) {
62     let acpi_event_sock = acpi_event_sock.as_ref().unwrap();
63     let nl_msg = match acpi_event_sock.recv() {
64         Ok(msg) => msg,
65         Err(e) => {
66             error!("recv returned with error {}", e);
67             return;
68         }
69     };
70 
71     for netlink_message in nl_msg.iter() {
72         let acpi_event = match AcpiNotifyEvent::new(netlink_message) {
73             Ok(evt) => evt,
74             Err(e) => {
75                 error!("Received netlink message is not an acpi_event, error {}", e);
76                 continue;
77             }
78         };
79         match acpi_event.device_class.as_str() {
80             "gpe" => {
81                 acpi_event_handle_gpe(acpi_event.data, acpi_event._type, gpe0, ignored_gpe);
82             }
83             "ac_adapter" => {
84                 if let Some(ac_adapter) = ac_adapter {
85                     // Currently we only support Status change event - other are ignored
86                     if acpi_event._type == 0x80 {
87                         // Set acex
88                         let ac_gpe_nr = {
89                             let mut ac_adapter = ac_adapter.lock();
90                             ac_adapter.acex = acpi_event.data;
91                             ac_adapter.gpe_nr
92                         };
93 
94                         // Generate GPE
95                         debug!(
96                             "getting ac_adapter event {} type {} and triggering GPE {}",
97                             acpi_event.data, acpi_event._type, ac_gpe_nr
98                         );
99                         let mut gpe0 = gpe0.lock();
100                         match gpe0.set_active(ac_gpe_nr) {
101                             Ok(_) => gpe0.trigger_sci(sci_evt),
102                             Err(e) => error!("{}", e),
103                         }
104                     }
105                 }
106             }
107             c => debug!("ignored acpi event {}", c),
108         };
109     }
110 }
111 
acpi_event_handle_gpe( gpe_number: u32, _type: u32, gpe0: &Arc<Mutex<GpeResource>>, ignored_gpe: &[u32], )112 fn acpi_event_handle_gpe(
113     gpe_number: u32,
114     _type: u32,
115     gpe0: &Arc<Mutex<GpeResource>>,
116     ignored_gpe: &[u32],
117 ) {
118     // If gpe event fired in the host, notify registered GpeNotify listeners
119     if _type == 0 && gpe_number <= ACPIPM_GPE_MAX as u32 && !ignored_gpe.contains(&gpe_number) {
120         if let Some(notify_devs) = gpe0.lock().gpe_notify.get(&gpe_number) {
121             for notify_dev in notify_devs.iter() {
122                 notify_dev.lock().notify();
123             }
124         }
125     }
126 }
127