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