summary refs log tree commit diff
path: root/devices/src/usb/xhci/intr_resample_handler.rs
blob: a2a40bb8fe7a69869cb34ccc0739ab2146361553 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::interrupter::Interrupter;
use crate::utils::{EventHandler, EventLoop};
use std::sync::Arc;
use sync::Mutex;
use sys_util::{error, EventFd, WatchingEvents};

/// Interrupt Resample handler handles resample event. It will reassert interrupt if needed.
pub struct IntrResampleHandler {
    interrupter: Arc<Mutex<Interrupter>>,
    resample_evt: EventFd,
}

impl IntrResampleHandler {
    /// Start resample handler.
    pub fn start(
        event_loop: &EventLoop,
        interrupter: Arc<Mutex<Interrupter>>,
        resample_evt: EventFd,
    ) -> Option<Arc<IntrResampleHandler>> {
        let handler = Arc::new(IntrResampleHandler {
            interrupter,
            resample_evt,
        });
        let tmp_handler: Arc<dyn EventHandler> = handler.clone();
        if let Err(e) = event_loop.add_event(
            &handler.resample_evt,
            WatchingEvents::empty().set_read(),
            Arc::downgrade(&tmp_handler),
        ) {
            error!("cannot add intr resample handler to event loop: {}", e);
            return None;
        }
        Some(handler)
    }
}
impl EventHandler for IntrResampleHandler {
    fn on_event(&self) -> Result<(), ()> {
        match self.resample_evt.read() {
            Ok(_) => {}
            Err(e) => {
                error!("cannot read resample evt: {}", e);
                return Err(());
            }
        }
        usb_debug!("resample triggered");
        let mut interrupter = self.interrupter.lock();
        if !interrupter.event_ring_is_empty() {
            usb_debug!("irq resample re-assert irq event");
            // There could be a race condition. When we get resample_evt and other
            // component is sending interrupt at the same time.
            // This might result in one more interrupt than we want. It's handled by
            // kernel correctly.
            if let Err(e) = interrupter.interrupt() {
                error!("cannot send interrupt: {}", e);
                return Err(());
            }
        }
        Ok(())
    }
}