devices/usb/xhci/
intr_resample_handler.rs

1// Copyright 2019 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
5use std::sync::Arc;
6
7use anyhow::Context;
8use base::debug;
9use base::error;
10use base::Event;
11use base::EventType;
12use sync::Mutex;
13
14use super::interrupter::Interrupter;
15use crate::utils::EventHandler;
16use crate::utils::EventLoop;
17
18/// Interrupt Resample handler handles resample event. It will reassert interrupt if needed.
19pub struct IntrResampleHandler {
20    interrupter: Arc<Mutex<Interrupter>>,
21    resample_evt: Event,
22}
23
24impl IntrResampleHandler {
25    /// Start resample handler.
26    pub fn start(
27        event_loop: &EventLoop,
28        interrupter: Arc<Mutex<Interrupter>>,
29        resample_evt: Event,
30    ) -> Option<Arc<IntrResampleHandler>> {
31        let handler = Arc::new(IntrResampleHandler {
32            interrupter,
33            resample_evt,
34        });
35        let tmp_handler: Arc<dyn EventHandler> = handler.clone();
36        if let Err(e) = event_loop.add_event(
37            &handler.resample_evt,
38            EventType::Read,
39            Arc::downgrade(&tmp_handler),
40        ) {
41            error!("cannot add intr resample handler to event loop: {}", e);
42            return None;
43        }
44        Some(handler)
45    }
46}
47
48impl EventHandler for IntrResampleHandler {
49    fn on_event(&self) -> anyhow::Result<()> {
50        self.resample_evt
51            .wait()
52            .context("cannot read resample evt")?;
53        let mut interrupter = self.interrupter.lock();
54        if !interrupter.event_ring_is_empty() {
55            debug!("irq resample re-assert irq event");
56            // There could be a race condition. When we get resample_evt and other
57            // component is sending interrupt at the same time.
58            // This might result in one more interrupt than we want. It's handled by
59            // kernel correctly.
60            interrupter.interrupt().context("cannot send interrupt")?;
61        }
62        Ok(())
63    }
64}