• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #![allow(clippy::result_large_err)]
6 
7 use std::sync::Arc;
8 
9 use anyhow::Context;
10 use base::error;
11 use base::warn;
12 use base::Error as SysError;
13 use base::Event;
14 use remain::sorted;
15 use sync::Mutex;
16 use thiserror::Error;
17 use vm_memory::GuestAddress;
18 use vm_memory::GuestMemory;
19 
20 use super::device_slot::DeviceSlot;
21 use super::device_slot::DeviceSlots;
22 use super::device_slot::Error as DeviceSlotError;
23 use super::interrupter::Error as InterrupterError;
24 use super::interrupter::Interrupter;
25 use super::ring_buffer_controller::Error as RingBufferControllerError;
26 use super::ring_buffer_controller::RingBufferController;
27 use super::ring_buffer_controller::TransferDescriptorHandler;
28 use super::xhci_abi::AddressDeviceCommandTrb;
29 use super::xhci_abi::AddressedTrb;
30 use super::xhci_abi::ConfigureEndpointCommandTrb;
31 use super::xhci_abi::DisableSlotCommandTrb;
32 use super::xhci_abi::Error as TrbError;
33 use super::xhci_abi::EvaluateContextCommandTrb;
34 use super::xhci_abi::ResetDeviceCommandTrb;
35 use super::xhci_abi::SetTRDequeuePointerCommandTrb;
36 use super::xhci_abi::StopEndpointCommandTrb;
37 use super::xhci_abi::TransferDescriptor;
38 use super::xhci_abi::TrbCast;
39 use super::xhci_abi::TrbCompletionCode;
40 use super::xhci_abi::TrbType;
41 use super::xhci_regs::valid_slot_id;
42 use super::xhci_regs::MAX_SLOTS;
43 use crate::utils::EventLoop;
44 
45 #[sorted]
46 #[derive(Error, Debug)]
47 pub enum Error {
48     #[error("bad slot id: {0}")]
49     BadSlotId(u8),
50     #[error("failed to cast trb: {0}")]
51     CastTrb(TrbError),
52     #[error("failed to config endpoint: {0}")]
53     ConfigEndpoint(DeviceSlotError),
54     #[error("failed to disable slot: {0}")]
55     DisableSlot(DeviceSlotError),
56     #[error("failed to evaluate context: {0}")]
57     EvaluateContext(DeviceSlotError),
58     #[error("failed to reset slot: {0}")]
59     ResetSlot(DeviceSlotError),
60     #[error("failed to send interrupt: {0}")]
61     SendInterrupt(InterrupterError),
62     #[error("failed to set address: {0}")]
63     SetAddress(DeviceSlotError),
64     #[error("failed to set dequeue pointer: {0}")]
65     SetDequeuePointer(DeviceSlotError),
66     #[error("failed to stop endpoint: {0}")]
67     StopEndpoint(DeviceSlotError),
68     #[error("failed to write event: {0}")]
69     WriteEvent(SysError),
70 }
71 
72 type Result<T> = std::result::Result<T, Error>;
73 
74 pub type CommandRingController = RingBufferController<CommandRingTrbHandler>;
75 pub type CommandRingControllerError = RingBufferControllerError;
76 
77 impl CommandRingController {
new( mem: GuestMemory, event_loop: Arc<EventLoop>, slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>, ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError>78     pub fn new(
79         mem: GuestMemory,
80         event_loop: Arc<EventLoop>,
81         slots: DeviceSlots,
82         interrupter: Arc<Mutex<Interrupter>>,
83     ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError> {
84         RingBufferController::new_with_handler(
85             String::from("command ring"),
86             mem,
87             event_loop,
88             CommandRingTrbHandler::new(slots, interrupter),
89         )
90     }
91 }
92 
93 pub struct CommandRingTrbHandler {
94     slots: DeviceSlots,
95     interrupter: Arc<Mutex<Interrupter>>,
96 }
97 
98 impl CommandRingTrbHandler {
new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self99     fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self {
100         CommandRingTrbHandler { slots, interrupter }
101     }
102 
slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>>103     fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> {
104         self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id))
105     }
106 
command_completion_callback( interrupter: &Arc<Mutex<Interrupter>>, completion_code: TrbCompletionCode, slot_id: u8, trb_addr: u64, event: &Event, ) -> Result<()>107     fn command_completion_callback(
108         interrupter: &Arc<Mutex<Interrupter>>,
109         completion_code: TrbCompletionCode,
110         slot_id: u8,
111         trb_addr: u64,
112         event: &Event,
113     ) -> Result<()> {
114         interrupter
115             .lock()
116             .send_command_completion_trb(completion_code, slot_id, GuestAddress(trb_addr))
117             .map_err(Error::SendInterrupt)?;
118         event.signal().map_err(Error::WriteEvent)
119     }
120 
enable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()>121     fn enable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
122         for slot_id in 1..=MAX_SLOTS {
123             if self.slot(slot_id)?.enable() {
124                 return CommandRingTrbHandler::command_completion_callback(
125                     &self.interrupter,
126                     TrbCompletionCode::Success,
127                     slot_id,
128                     atrb.gpa,
129                     &event,
130                 );
131             }
132         }
133 
134         CommandRingTrbHandler::command_completion_callback(
135             &self.interrupter,
136             TrbCompletionCode::NoSlotsAvailableError,
137             0,
138             atrb.gpa,
139             &event,
140         )
141     }
142 
disable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()>143     fn disable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
144         let trb = atrb
145             .trb
146             .cast::<DisableSlotCommandTrb>()
147             .map_err(Error::CastTrb)?;
148         let slot_id = trb.get_slot_id();
149         if valid_slot_id(slot_id) {
150             let gpa = atrb.gpa;
151             let interrupter = self.interrupter.clone();
152             self.slots
153                 .disable_slot(slot_id, move |completion_code| {
154                     CommandRingTrbHandler::command_completion_callback(
155                         &interrupter,
156                         completion_code,
157                         slot_id,
158                         gpa,
159                         &event,
160                     )
161                     .map_err(|e| {
162                         error!("failed to run command completion callback: {}", e);
163                     })
164                 })
165                 .map_err(Error::DisableSlot)
166         } else {
167             CommandRingTrbHandler::command_completion_callback(
168                 &self.interrupter,
169                 TrbCompletionCode::TrbError,
170                 slot_id,
171                 atrb.gpa,
172                 &event,
173             )
174         }
175     }
176 
address_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()>177     fn address_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
178         let trb = atrb
179             .trb
180             .cast::<AddressDeviceCommandTrb>()
181             .map_err(Error::CastTrb)?;
182         let slot_id = trb.get_slot_id();
183         let completion_code = {
184             if valid_slot_id(slot_id) {
185                 self.slot(slot_id)?
186                     .set_address(trb)
187                     .map_err(Error::SetAddress)?
188             } else {
189                 TrbCompletionCode::TrbError
190             }
191         };
192         CommandRingTrbHandler::command_completion_callback(
193             &self.interrupter,
194             completion_code,
195             slot_id,
196             atrb.gpa,
197             &event,
198         )
199     }
200 
configure_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()>201     fn configure_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
202         let trb = atrb
203             .trb
204             .cast::<ConfigureEndpointCommandTrb>()
205             .map_err(Error::CastTrb)?;
206         let slot_id = trb.get_slot_id();
207         let completion_code = {
208             if valid_slot_id(slot_id) {
209                 self.slot(slot_id)?
210                     .configure_endpoint(trb)
211                     .map_err(Error::ConfigEndpoint)?
212             } else {
213                 TrbCompletionCode::TrbError
214             }
215         };
216         CommandRingTrbHandler::command_completion_callback(
217             &self.interrupter,
218             completion_code,
219             slot_id,
220             atrb.gpa,
221             &event,
222         )
223     }
224 
evaluate_context(&self, atrb: &AddressedTrb, event: Event) -> Result<()>225     fn evaluate_context(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
226         let trb = atrb
227             .trb
228             .cast::<EvaluateContextCommandTrb>()
229             .map_err(Error::CastTrb)?;
230         let slot_id = trb.get_slot_id();
231         let completion_code = {
232             if valid_slot_id(slot_id) {
233                 self.slot(slot_id)?
234                     .evaluate_context(trb)
235                     .map_err(Error::EvaluateContext)?
236             } else {
237                 TrbCompletionCode::TrbError
238             }
239         };
240         CommandRingTrbHandler::command_completion_callback(
241             &self.interrupter,
242             completion_code,
243             slot_id,
244             atrb.gpa,
245             &event,
246         )
247     }
248 
reset_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()>249     fn reset_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
250         let trb = atrb
251             .trb
252             .cast::<ResetDeviceCommandTrb>()
253             .map_err(Error::CastTrb)?;
254         let slot_id = trb.get_slot_id();
255         if valid_slot_id(slot_id) {
256             let gpa = atrb.gpa;
257             let interrupter = self.interrupter.clone();
258             self.slots
259                 .reset_slot(slot_id, move |completion_code| {
260                     CommandRingTrbHandler::command_completion_callback(
261                         &interrupter,
262                         completion_code,
263                         slot_id,
264                         gpa,
265                         &event,
266                     )
267                     .map_err(|e| {
268                         error!("command completion callback failed: {}", e);
269                     })
270                 })
271                 .map_err(Error::ResetSlot)
272         } else {
273             CommandRingTrbHandler::command_completion_callback(
274                 &self.interrupter,
275                 TrbCompletionCode::TrbError,
276                 slot_id,
277                 atrb.gpa,
278                 &event,
279             )
280         }
281     }
282 
stop_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()>283     fn stop_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
284         let trb = atrb
285             .trb
286             .cast::<StopEndpointCommandTrb>()
287             .map_err(Error::CastTrb)?;
288         let slot_id = trb.get_slot_id();
289         let endpoint_id = trb.get_endpoint_id();
290         if valid_slot_id(slot_id) {
291             let gpa = atrb.gpa;
292             let interrupter = self.interrupter.clone();
293             self.slots
294                 .stop_endpoint(slot_id, endpoint_id, move |completion_code| {
295                     CommandRingTrbHandler::command_completion_callback(
296                         &interrupter,
297                         completion_code,
298                         slot_id,
299                         gpa,
300                         &event,
301                     )
302                     .map_err(|e| {
303                         error!("command completion callback failed: {}", e);
304                     })
305                 })
306                 .map_err(Error::StopEndpoint)?;
307             Ok(())
308         } else {
309             error!("stop endpoint trb has invalid slot id {}", slot_id);
310             CommandRingTrbHandler::command_completion_callback(
311                 &self.interrupter,
312                 TrbCompletionCode::TrbError,
313                 slot_id,
314                 atrb.gpa,
315                 &event,
316             )
317         }
318     }
319 
set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event: Event) -> Result<()>320     fn set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {
321         let trb = atrb
322             .trb
323             .cast::<SetTRDequeuePointerCommandTrb>()
324             .map_err(Error::CastTrb)?;
325         let slot_id = trb.get_slot_id();
326         let endpoint_id = trb.get_endpoint_id();
327         // See Set TR Dequeue Pointer Trb in spec.
328         let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset();
329         let completion_code = {
330             if valid_slot_id(slot_id) {
331                 self.slot(slot_id)?
332                     .set_tr_dequeue_ptr(endpoint_id, dequeue_ptr)
333                     .map_err(Error::SetDequeuePointer)?
334             } else {
335                 error!("stop endpoint trb has invalid slot id {}", slot_id);
336                 TrbCompletionCode::TrbError
337             }
338         };
339         CommandRingTrbHandler::command_completion_callback(
340             &self.interrupter,
341             completion_code,
342             slot_id,
343             atrb.gpa,
344             &event,
345         )
346     }
347 }
348 
349 impl TransferDescriptorHandler for CommandRingTrbHandler {
handle_transfer_descriptor( &self, descriptor: TransferDescriptor, complete_event: Event, ) -> anyhow::Result<()>350     fn handle_transfer_descriptor(
351         &self,
352         descriptor: TransferDescriptor,
353         complete_event: Event,
354     ) -> anyhow::Result<()> {
355         // Command descriptor always consist of a single TRB.
356         assert_eq!(descriptor.len(), 1);
357         let atrb = &descriptor[0];
358         let command_result = match atrb.trb.get_trb_type() {
359             Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event),
360             Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event),
361             Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event),
362             Ok(TrbType::ConfigureEndpointCommand) => self.configure_endpoint(atrb, complete_event),
363             Ok(TrbType::EvaluateContextCommand) => self.evaluate_context(atrb, complete_event),
364             Ok(TrbType::ResetDeviceCommand) => self.reset_device(atrb, complete_event),
365             Ok(TrbType::NoopCommand) => CommandRingTrbHandler::command_completion_callback(
366                 &self.interrupter,
367                 TrbCompletionCode::Success,
368                 0,
369                 atrb.gpa,
370                 &complete_event,
371             ),
372             Ok(TrbType::ResetEndpointCommand) => {
373                 error!(
374                     "Receiving reset endpoint command. \
375                      It should only happen when cmd ring stall"
376                 );
377                 CommandRingTrbHandler::command_completion_callback(
378                     &self.interrupter,
379                     TrbCompletionCode::TrbError,
380                     0,
381                     atrb.gpa,
382                     &complete_event,
383                 )
384             }
385             Ok(TrbType::StopEndpointCommand) => self.stop_endpoint(atrb, complete_event),
386             Ok(TrbType::SetTRDequeuePointerCommand) => {
387                 self.set_tr_dequeue_ptr(atrb, complete_event)
388             }
389             _ => {
390                 warn!(
391                     // We are not handling type 14,15,16. See table 6.4.6.
392                     "Unexpected command ring trb type: {}",
393                     atrb.trb
394                 );
395                 match self.interrupter.lock().send_command_completion_trb(
396                     TrbCompletionCode::TrbError,
397                     0,
398                     GuestAddress(atrb.gpa),
399                 ) {
400                     Err(e) => Err(Error::SendInterrupt(e)),
401                     Ok(_) => complete_event.signal().map_err(Error::WriteEvent),
402                 }
403             }
404         };
405         command_result.context("command ring TRB failed")
406     }
407 }
408