xref: /aosp_15_r20/external/crosvm/devices/src/usb/xhci/ring_buffer.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 use std::fmt;
6 use std::fmt::Display;
7 use std::mem::size_of;
8 
9 use base::debug;
10 use remain::sorted;
11 use thiserror::Error;
12 use vm_memory::GuestAddress;
13 use vm_memory::GuestMemory;
14 use vm_memory::GuestMemoryError;
15 
16 use super::xhci_abi::AddressedTrb;
17 use super::xhci_abi::Error as TrbError;
18 use super::xhci_abi::LinkTrb;
19 use super::xhci_abi::TransferDescriptor;
20 use super::xhci_abi::Trb;
21 use super::xhci_abi::TrbCast;
22 use super::xhci_abi::TrbType;
23 
24 #[sorted]
25 #[derive(Error, Debug)]
26 pub enum Error {
27     #[error("bad dequeue pointer: {0}")]
28     BadDequeuePointer(GuestAddress),
29     #[error("cannot cast trb: {0}")]
30     CastTrb(TrbError),
31     #[error("cannot read guest memory: {0}")]
32     ReadGuestMemory(GuestMemoryError),
33     #[error("cannot get trb chain bit: {0}")]
34     TrbChain(TrbError),
35 }
36 
37 type Result<T> = std::result::Result<T, Error>;
38 
39 /// Ring Buffer is segmented circular buffer in guest memory containing work items
40 /// called transfer descriptors, each of which consists of one or more TRBs.
41 /// Ring buffer logic is shared between transfer ring and command ring.
42 /// Transfer Ring management is defined in xHCI spec 4.9.2.
43 pub struct RingBuffer {
44     name: String,
45     mem: GuestMemory,
46     dequeue_pointer: GuestAddress,
47     // Used to check if the ring is empty. Toggled when looping back to the begining
48     // of the buffer.
49     consumer_cycle_state: bool,
50 }
51 
52 impl Display for RingBuffer {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result53     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54         write!(f, "RingBuffer `{}`", self.name)
55     }
56 }
57 
58 // Public interfaces for Ring buffer.
59 impl RingBuffer {
60     /// Create a new RingBuffer.
new(name: String, mem: GuestMemory) -> Self61     pub fn new(name: String, mem: GuestMemory) -> Self {
62         RingBuffer {
63             name,
64             mem,
65             dequeue_pointer: GuestAddress(0),
66             consumer_cycle_state: false,
67         }
68     }
69 
70     /// Dequeue next transfer descriptor from the transfer ring.
dequeue_transfer_descriptor(&mut self) -> Result<Option<TransferDescriptor>>71     pub fn dequeue_transfer_descriptor(&mut self) -> Result<Option<TransferDescriptor>> {
72         let mut td: TransferDescriptor = TransferDescriptor::new();
73         while let Some(addressed_trb) = self.get_current_trb()? {
74             if let Ok(TrbType::Link) = addressed_trb.trb.get_trb_type() {
75                 let link_trb = addressed_trb
76                     .trb
77                     .cast::<LinkTrb>()
78                     .map_err(Error::CastTrb)?;
79                 self.dequeue_pointer = GuestAddress(link_trb.get_ring_segment_pointer());
80                 self.consumer_cycle_state =
81                     self.consumer_cycle_state != link_trb.get_toggle_cycle();
82                 continue;
83             }
84 
85             self.dequeue_pointer = match self.dequeue_pointer.checked_add(size_of::<Trb>() as u64) {
86                 Some(addr) => addr,
87                 None => {
88                     return Err(Error::BadDequeuePointer(self.dequeue_pointer));
89                 }
90             };
91 
92             xhci_trace!(
93                 "{}: adding trb to td {}",
94                 self.name.as_str(),
95                 addressed_trb.trb
96             );
97             td.push(addressed_trb);
98             if !addressed_trb.trb.get_chain_bit().map_err(Error::TrbChain)? {
99                 debug!("xhci: trb chain is false returning");
100                 break;
101             }
102         }
103         // A valid transfer descriptor contains at least one addressed trb and the last trb has
104         // chain bit != 0.
105         match td.last() {
106             Some(t) => {
107                 if t.trb.get_chain_bit().map_err(Error::TrbChain)? {
108                     return Ok(None);
109                 }
110             }
111             None => return Ok(None),
112         }
113         Ok(Some(td))
114     }
115 
116     /// Get dequeue pointer of the ring buffer.
get_dequeue_pointer(&self) -> GuestAddress117     pub fn get_dequeue_pointer(&self) -> GuestAddress {
118         self.dequeue_pointer
119     }
120 
121     /// Set dequeue pointer of the ring buffer.
set_dequeue_pointer(&mut self, addr: GuestAddress)122     pub fn set_dequeue_pointer(&mut self, addr: GuestAddress) {
123         xhci_trace!("{}: set dequeue pointer {:x}", self.name.as_str(), addr.0);
124 
125         self.dequeue_pointer = addr;
126     }
127 
128     /// Get consumer cycle state of the ring buffer.
get_consumer_cycle_state(&self) -> bool129     pub fn get_consumer_cycle_state(&self) -> bool {
130         self.consumer_cycle_state
131     }
132 
133     /// Set consumer cycle state of the ring buffer.
set_consumer_cycle_state(&mut self, state: bool)134     pub fn set_consumer_cycle_state(&mut self, state: bool) {
135         xhci_trace!("{}: set consumer cycle state {}", self.name.as_str(), state);
136         self.consumer_cycle_state = state;
137     }
138 
139     // Read trb pointed by dequeue pointer. Does not proceed dequeue pointer.
get_current_trb(&self) -> Result<Option<AddressedTrb>>140     fn get_current_trb(&self) -> Result<Option<AddressedTrb>> {
141         let trb: Trb = self
142             .mem
143             .read_obj_from_addr(self.dequeue_pointer)
144             .map_err(Error::ReadGuestMemory)?;
145         xhci_trace!("{}: trb read from memory {:?}", self.name.as_str(), trb);
146         // If cycle bit of trb does not equal consumer cycle state, the ring is empty.
147         // This trb is invalid.
148         if trb.get_cycle() != self.consumer_cycle_state {
149             debug!(
150                 "xhci: cycle bit does not match, self cycle {}",
151                 self.consumer_cycle_state
152             );
153             Ok(None)
154         } else {
155             Ok(Some(AddressedTrb {
156                 trb,
157                 gpa: self.dequeue_pointer.0,
158             }))
159         }
160     }
161 }
162 
163 #[cfg(test)]
164 mod test {
165     use base::pagesize;
166 
167     use super::*;
168     use crate::usb::xhci::xhci_abi::*;
169 
170     #[test]
ring_test_dequeue()171     fn ring_test_dequeue() {
172         let trb_size = size_of::<Trb>() as u64;
173         let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
174         let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
175 
176         // Structure of ring buffer:
177         //  0x100  --> 0x200  --> 0x300
178         //  trb 1  |   trb 3  |   trb 5
179         //  trb 2  |   trb 4  |   trb 6
180         //  l trb  -   l trb  -   l trb to 0x100
181         let mut trb = NormalTrb::new();
182         trb.set_trb_type(TrbType::Normal);
183         trb.set_data_buffer(1);
184         trb.set_chain(true);
185         gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
186 
187         trb.set_data_buffer(2);
188         gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
189             .unwrap();
190 
191         let mut ltrb = LinkTrb::new();
192         ltrb.set_trb_type(TrbType::Link);
193         ltrb.set_ring_segment_pointer(0x200);
194         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
195             .unwrap();
196 
197         trb.set_data_buffer(3);
198         gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
199 
200         // Chain bit is false.
201         trb.set_data_buffer(4);
202         trb.set_chain(false);
203         gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
204             .unwrap();
205 
206         ltrb.set_ring_segment_pointer(0x300);
207         gm.write_obj_at_addr(ltrb, GuestAddress(0x200 + 2 * trb_size))
208             .unwrap();
209 
210         trb.set_data_buffer(5);
211         trb.set_chain(true);
212         gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
213 
214         // Chain bit is false.
215         trb.set_data_buffer(6);
216         trb.set_chain(false);
217         gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
218             .unwrap();
219 
220         ltrb.set_ring_segment_pointer(0x100);
221         gm.write_obj_at_addr(ltrb, GuestAddress(0x300 + 2 * trb_size))
222             .unwrap();
223 
224         transfer_ring.set_dequeue_pointer(GuestAddress(0x100));
225         transfer_ring.set_consumer_cycle_state(false);
226 
227         // Read first transfer descriptor.
228         let descriptor = transfer_ring
229             .dequeue_transfer_descriptor()
230             .unwrap()
231             .unwrap();
232         assert_eq!(descriptor.len(), 4);
233         assert_eq!(descriptor[0].trb.get_parameter(), 1);
234         assert_eq!(descriptor[1].trb.get_parameter(), 2);
235         assert_eq!(descriptor[2].trb.get_parameter(), 3);
236         assert_eq!(descriptor[3].trb.get_parameter(), 4);
237 
238         // Read second transfer descriptor.
239         let descriptor = transfer_ring
240             .dequeue_transfer_descriptor()
241             .unwrap()
242             .unwrap();
243         assert_eq!(descriptor.len(), 2);
244         assert_eq!(descriptor[0].trb.get_parameter(), 5);
245         assert_eq!(descriptor[1].trb.get_parameter(), 6);
246     }
247 
248     #[test]
transfer_ring_test_dequeue_failure()249     fn transfer_ring_test_dequeue_failure() {
250         let trb_size = size_of::<Trb>() as u64;
251         let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
252         let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
253 
254         let mut trb = NormalTrb::new();
255         trb.set_trb_type(TrbType::Normal);
256         trb.set_data_buffer(1);
257         trb.set_chain(true);
258         gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
259 
260         trb.set_data_buffer(2);
261         gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
262             .unwrap();
263 
264         let mut ltrb = LinkTrb::new();
265         ltrb.set_trb_type(TrbType::Link);
266         ltrb.set_ring_segment_pointer(0x200);
267         ltrb.set_toggle_cycle(true);
268         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
269             .unwrap();
270 
271         trb.set_data_buffer(3);
272         gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
273 
274         transfer_ring.set_dequeue_pointer(GuestAddress(0x100));
275         transfer_ring.set_consumer_cycle_state(false);
276 
277         // Read first transfer descriptor.
278         let descriptor = transfer_ring.dequeue_transfer_descriptor().unwrap();
279         assert_eq!(descriptor.is_none(), true);
280     }
281 
282     #[test]
ring_test_toggle_cycle()283     fn ring_test_toggle_cycle() {
284         let trb_size = size_of::<Trb>() as u64;
285         let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
286         let mut transfer_ring = RingBuffer::new(String::new(), gm.clone());
287 
288         let mut trb = NormalTrb::new();
289         trb.set_trb_type(TrbType::Normal);
290         trb.set_data_buffer(1);
291         trb.set_chain(false);
292         trb.set_cycle(false);
293         gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
294 
295         let mut ltrb = LinkTrb::new();
296         ltrb.set_trb_type(TrbType::Link);
297         ltrb.set_ring_segment_pointer(0x100);
298         ltrb.set_toggle_cycle(true);
299         ltrb.set_cycle(false);
300         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + trb_size))
301             .unwrap();
302 
303         // Initial state: consumer cycle = false
304         transfer_ring.set_dequeue_pointer(GuestAddress(0x100));
305         transfer_ring.set_consumer_cycle_state(false);
306 
307         // Read first transfer descriptor.
308         let descriptor = transfer_ring
309             .dequeue_transfer_descriptor()
310             .unwrap()
311             .unwrap();
312         assert_eq!(descriptor.len(), 1);
313         assert_eq!(descriptor[0].trb.get_parameter(), 1);
314 
315         // Cycle bit should be unchanged since we haven't advanced past the Link TRB yet.
316         assert_eq!(transfer_ring.consumer_cycle_state, false);
317 
318         // Overwrite the first TRB with a new one (data = 2)
319         // with the new producer cycle bit state (true).
320         let mut trb = NormalTrb::new();
321         trb.set_trb_type(TrbType::Normal);
322         trb.set_data_buffer(2);
323         trb.set_cycle(true); // Link TRB toggled the cycle.
324         gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
325 
326         // Read new transfer descriptor.
327         let descriptor = transfer_ring
328             .dequeue_transfer_descriptor()
329             .unwrap()
330             .unwrap();
331         assert_eq!(descriptor.len(), 1);
332         assert_eq!(descriptor[0].trb.get_parameter(), 2);
333 
334         assert_eq!(transfer_ring.consumer_cycle_state, true);
335 
336         // Update the Link TRB with the new cycle bit.
337         let mut ltrb = LinkTrb::new();
338         ltrb.set_trb_type(TrbType::Link);
339         ltrb.set_ring_segment_pointer(0x100);
340         ltrb.set_toggle_cycle(true);
341         ltrb.set_cycle(true); // Producer cycle state is now 1.
342         gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + trb_size))
343             .unwrap();
344 
345         // Overwrite the first TRB again with a new one (data = 3)
346         // with the new producer cycle bit state (false).
347         let mut trb = NormalTrb::new();
348         trb.set_trb_type(TrbType::Normal);
349         trb.set_data_buffer(3);
350         trb.set_cycle(false); // Link TRB toggled the cycle.
351         gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
352 
353         // Read new transfer descriptor.
354         let descriptor = transfer_ring
355             .dequeue_transfer_descriptor()
356             .unwrap()
357             .unwrap();
358         assert_eq!(descriptor.len(), 1);
359         assert_eq!(descriptor[0].trb.get_parameter(), 3);
360 
361         assert_eq!(transfer_ring.consumer_cycle_state, false);
362     }
363 }
364