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