Software APIs
usb_testutils_streams.h
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_STREAMS_H_
6 #define OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_STREAMS_H_
7 #include <stdbool.h>
8 #include <stdint.h>
9 
10 #include "sw/device/lib/testing/usb_testutils.h"
11 
12 // Maximum number of concurrent streams
13 #ifndef USBUTILS_STREAMS_MAX
14 #ifdef USBDEV_NUM_ENDPOINTS
15 // Endpoint zero implements the default control pipe
16 #define USBUTILS_STREAMS_MAX (USBDEV_NUM_ENDPOINTS - 1U)
17 #else
18 #define USBUTILS_STREAMS_MAX 11U
19 #endif
20 #endif
21 
22 // Maximum number of buffer simultaneously awaiting transmission
23 // (we must leave some available for packet reception)
24 #ifndef USBUTILS_STREAMS_TXBUF_MAX
25 #define USBUTILS_STREAMS_TXBUF_MAX 24U
26 #endif
27 
28 // Stream signature words
29 #define USBDEV_STREAM_SIGNATURE_HEAD 0x579EA01AU
30 #define USBDEV_STREAM_SIGNATURE_TAIL 0x160AE975U
31 
32 // Seed numbers for the LFSR generators in each transfer direction for
33 // the given stream number
34 #define USBTST_LFSR_SEED(s) (uint8_t)(0x10U + (s)*7U)
35 #define USBDPI_LFSR_SEED(s) (uint8_t)(0x9BU - (s)*7U)
36 
37 // Buffer size randomization
38 #define BUFSZ_LFSR_SEED(s) (uint8_t)(0x17U + (s)*7U)
39 
40 // Simple LFSR for 8-bit sequences
41 /// Note: zero is an isolated state that shall be avoided
42 #define LFSR_ADVANCE(lfsr) \
43  (uint8_t)( \
44  (uint8_t)((lfsr) << 1) ^ \
45  ((((lfsr) >> 1) ^ ((lfsr) >> 2) ^ ((lfsr) >> 3) ^ ((lfsr) >> 7)) & 1U))
46 
47 // Test/stream flags
48 typedef enum {
49  /**
50  * Host shall retrieve IN data from the device for this stream
51  */
52  kUsbdevStreamFlagRetrieve = 0x10U,
53  /**
54  * Host shall check that IN data matches as expected
55  */
56  kUsbdevStreamFlagCheck = 0x20U,
57  /**
58  * DPI model (or Host) shall retry IN data fetches, where possible
59  */
60  kUsbdevStreamFlagRetry = 0x40U,
61  /**
62  * Host shall send OUT data to the device for this stream
63  */
64  kUsbdevStreamFlagSend = 0x80U,
65  /**
66  * Transmit only maximal length packets
67  */
68  kUsbdevStreamFlagMaxPackets = 0x100U,
69 } usbdev_stream_flags_t;
70 
71 // Forward declaration to context state
73 
74 /**
75  * Stream signature
76  * Note: this needs to be transferred over a byte stream
77  */
78 typedef struct __attribute__((packed)) usbdev_stream_sig {
79  /**
80  * Head signature word
81  */
82  uint32_t head_sig;
83  /**
84  * Initial value of LFSR
85  * Note: for Isochronous Transfers, this is the initial value of the sender's
86  * LFSR for _this packet_
87  */
88  uint8_t init_lfsr;
89  /**
90  * Stream number (bits 3:0) and flags (bits 7:4)
91  */
92  uint8_t stream;
93  /**
94  * Sequence number, low part; for non-Isochronous streams this will always be
95  * zero because a signature is used only at the start of the data stream.
96  */
97  uint8_t seq_lo;
98  /**
99  * Sequence number, high part; for non-Isochronous streams this will always be
100  * zero because a signature is used only at the start of the data stream.
101  */
102  uint8_t seq_hi;
103  /**
104  * Number of bytes to be transferred; for Isochronous streams this
105  * is the count of remaining bytes and it wraps when reaching zero
106  */
107  uint32_t num_bytes;
108  /**
109  * Tail signature word
110  */
111  uint32_t tail_sig;
112 } usbdev_stream_sig_t;
113 
114 // Sanity check because the host-side code relies upon the same structure
115 static_assert(sizeof(usbdev_stream_sig_t) == 0x10U,
116  "Host-side code relies upon signature structure");
117 
118 /**
119  * Transmission state.
120  */
121 typedef struct usbdev_stream_tx {
122  /**
123  * Is a signature required at the start of the next packet?
124  */
126  /**
127  * Transmission Sequence Number (for Isochronous streams)
128  */
129  uint16_t seq;
130  /**
131  * Transmission Linear Feedback Shift Register (for PRND data generation)
132  */
133  uint8_t lfsr;
134  /**
135  * Total number of bytes presented to the USB device for transmission
136  */
137  uint32_t bytes;
138  /**
139  * Transmission-side LFSR for selection of buffer size
140  */
141  uint8_t buf_size;
143 
144 /**
145  * Context state for a single stream
146  *
147  * Note: this state information is stored/loaded as-is over suspend/resume
148  * operations.
149  */
150 typedef struct usbdev_stream {
151  /**
152  * Stream IDentifier
153  */
154  uint8_t id;
155  /**
156  * USB transfer type
157  */
158  usb_testutils_transfer_type_t xfr_type;
159  /**
160  * USB device endpoint being used for data transmission
161  */
162  uint8_t tx_ep;
163  /**
164  * Current transmission state.
165  */
167  /**
168  * Committed transmission state.
169  */
171  /**
172  * USB device endpoint being used for data reception
173  */
174  uint8_t rx_ep;
175  /**
176  * Reception Sequence Number (for Isochronous streams)
177  */
178  uint16_t rx_seq;
179  /**
180  * Reception-side LFSR state (mirrors USBDPI generation of PRND data)
181  */
182  uint8_t rx_lfsr;
183  /**
184  * Reception-side shadow of transmission LFSR
185  */
186  uint8_t rxtx_lfsr;
187  /**
188  * Total number of bytes received from the USB device
189  */
190  uint32_t rx_bytes;
191  /**
192  * Reception-side LFSR for determination of expected buffer size
193  * (for Isochronous streams where packets may be dropped)
194  */
195  uint8_t rx_buf_size;
196  /**
197  * Size of transfer in bytes
198  */
199  uint32_t transfer_bytes;
200  /**
201  * Stream flags
202  */
203  usbdev_stream_flags_t flags;
204  /**
205  * Are we sending data?
206  */
207  bool sending;
208  /**
209  * Are we generating a valid byte sequence?
210  */
212  /**
213  * Specify whether to perform verbose logging, for visibility
214  * (Note that this substantially alters the timing of interactions with the
215  * DPI model and will increase the simulation time)
216  */
217  bool verbose;
219 
220 /**
221  * Context state for callback function; callback is stream-specific but also
222  * needs to locate the enclosing streaming context.
223  */
224 typedef struct {
225  /**
226  * Pointer to the enclosing streaming context; callback functions receive
227  * only per-stream pointer
228  */
230  /**
231  * Pointer to the stream itself.
232  */
235 
236 /**
237  * Context state for streaming test
238  */
240  /**
241  * Context pointer
242  */
244  /**
245  * Number of streams in use
246  */
247  uint8_t nstreams;
248  /**
249  * State information for each of the test streams
250  */
251  usbdev_stream_t streams[USBUTILS_STREAMS_MAX];
252  /**
253  * Callback information for each of the test streamms
254  */
255  usbdev_stream_cb_ctx_t cb[USBUTILS_STREAMS_MAX];
256  /**
257  * Per-endpoint limits on the number of buffers that may be queued for
258  * transmission
259  */
261  /**
262  * Per-endpoint counts of completed buffers queued for transmission
263  */
265  /**
266  * Total number of completed buffers
267  */
269  /**
270  * Buffers that have been filled but cannot yet be presented for transmission
271  */
272  // 12 X 24 X 4 (or 8?)( BYTES... could perhaps simplify this at some point
273  struct {
274  /**
275  * USB device packet buffer
276  */
278  /**
279  * Transmission state _after_ this buffer was filled.
280  */
282  } tx_bufs[USBDEV_NUM_ENDPOINTS][USBUTILS_STREAMS_TXBUF_MAX];
283 };
284 
285 /**
286  * Initialize a number of concurrent streams with the same properties;
287  * this set of streams is assigned endpoints from endpoint 1 upwards, in order.
288  *
289  * @param ctx Context state for streaming test
290  * @param nstreams Number of streams
291  * @param xfr_types Transfer types to be used for the individual streams
292  * @param num_bytes Number of bytes to be transferred by each stream
293  * @param flags Stream/test flags to be used for each stream
294  * @param verbose Whether to perform verbose logging for each stream
295  * @return The result status of the operation.
296  */
298 status_t usb_testutils_streams_init(
299  usb_testutils_streams_ctx_t *ctx, unsigned nstreams,
300  const usb_testutils_transfer_type_t xfr_types[], uint32_t num_bytes,
301  usbdev_stream_flags_t flags, bool verbose);
302 
303 /**
304  * Service all streams, preparing and/or sending any data that we can, as well
305  * as handling received data.
306  *
307  * Note: this calls usb_testutils_poll() internally to keep that layer alive
308  * and handling packet reception.
309  *
310  * @param ctx Context state for streaming test
311  * @return The result status of the operation.
312  */
314 status_t usb_testutils_streams_service(usb_testutils_streams_ctx_t *ctx);
315 
316 /**
317  * Returns an indication of whether all streams have completed their data
318  * transfers.
319  *
320  * @param ctx Context state for streaming test
321  */
323 bool usb_testutils_streams_completed(const usb_testutils_streams_ctx_t *ctx);
324 
325 /**
326  * Initialize a stream, preparing it for use.
327  *
328  * @param ctx Context state for streaming test
329  * @param id Stream identifier (0-based)
330  * @param xfr_type Transfer type to be usd for this stream
331  * @param ep_in Endpoint to be used for IN traffic (to host)
332  * @param ep_out Endpoint to be used for OUT traffic (from host)
333  * @param num_bytes Number of bytes to be transferred by stream
334  * @param flags Stream/test flags
335  * @param verbose Whether to perform verbose logging for this stream
336  * @return The result status of the operation.
337  */
339 status_t usb_testutils_stream_init(usb_testutils_streams_ctx_t *ctx, uint8_t id,
340  usb_testutils_transfer_type_t xfr_type,
341  uint8_t ep_in, uint8_t ep_out,
342  uint32_t num_bytes,
343  usbdev_stream_flags_t flags, bool verbose);
344 
345 /**
346  * Initialize a set of streams of specified types, dynamically constructing a
347  * standard USB configuration descriptor for the caller. The transfer types of
348  * the streams may optionally be returned via `types` for passing to the DPI
349  * model/host.
350  *
351  * @param ctx Context state for streaming test.
352  * @param cfg Receives the configuration descriptor.
353  * @param len Size of buffer receiving the configuration descriptor.
354  * @param nstreams Number of streams to be initialized.
355  * @param xfr_types The transfer types of the streams.
356  * @param num_bytes Number of bytes to be transferred by stream
357  * @param flags Stream/test flags
358  * @param verbose Whether to perform verbose logging for this stream
359  * @param types Optionally receives the bitmap of transfer types.
360  * @return The result of the operation.
361  */
363 status_t usb_testutils_streams_typed_init(
364  usb_testutils_streams_ctx_t *ctx, uint8_t *cfg, uint16_t len,
365  unsigned nstreams, const usb_testutils_transfer_type_t xfr_types[],
366  uint32_t num_bytes, usbdev_stream_flags_t flags, bool verbose,
367  uint32_t *types);
368 
369 /**
370  * Specify the number of already-initialized streams, and apportion the
371  * available tx buffers among them. To be called after usb_testutils_stream_init
372  *
373  * @param ctx Context state for streaming test.
374  * @param nstreams Number of streams.
375  * @return Success or otherwise of the request.
376  */
377 bool usb_testutils_streams_count_set(usb_testutils_streams_ctx_t *ctx,
378  unsigned nstreams);
379 
380 /**
381  * Service the given stream, preparing and/or sending any data that we can.
382  *
383  * Note: the caller must invoke usb_testutils_poll() itself in order to ensure
384  * that packet reception continues to occur.
385  *
386  * @param ctx Context state for streaming test
387  * @param id Stream identifier (0-based)
388  * @return The result status of the operation.
389  */
391 status_t usb_testutils_stream_service(usb_testutils_streams_ctx_t *ctx,
392  uint8_t id);
393 
394 /**
395  * Save the current state of the streams into the supplied buffer for resuming
396  * after sleep. Additionally, prevent further state changes that would
397  * invalidate the stored state.
398  *
399  * The format/content of the stored state is opaque to the caller.
400  *
401  * @param ctx Context state for streaming test.
402  * @param buf Buffer for receiving streaming state.
403  * @param size Size of supplied buffer (maximum size of stored state).
404  * @param used Receives the size in bytes of the streaming state.
405  * @return The result of the operation.
406  */
408 status_t usb_testutils_streams_suspend(usb_testutils_streams_ctx_t *ctx,
409  uint8_t *buf, unsigned size,
410  unsigned *used);
411 
412 /**
413  * Restore the state of the streams from the supplied data.
414  *
415  * The format/content of the stored state is opaque to the caller.
416  *
417  * @param ctx Context state for streaming test.
418  * @param data Stored streaming state.
419  * @param len Size in bytes of the stored streaming state.
420  * @return The result of the operation.
421  */
423 status_t usb_testutils_streams_resume(usb_testutils_streams_ctx_t *ctx,
424  const uint8_t *data, unsigned len);
425 
426 /**
427  * Return the current progress/status of the given stream.
428  *
429  * @param ctx Context state for streaming test.
430  * @param id Stream IDentifier (0-based).
431  * @param num_bytes Receives number of bytes to be transferred by this stream.
432  * @param tx_bytes Receives number of bytes transmitted.
433  * @param rx_bytes Receives number of bytes received.
434  * @return The result of the operation.
435  */
437 status_t usb_testutils_stream_status(usb_testutils_streams_ctx_t *ctx,
438  uint8_t id, uint32_t *num_bytes,
439  uint32_t *tx_bytes, uint32_t *rx_bytes);
440 
441 /**
442  * Returns an indication of whether a stream has completed its data transfer.
443  *
444  * @param ctx Context state for streaming test
445  * @param id Stream identifier (0-based)
446  */
448 bool usb_testutils_stream_completed(const usb_testutils_streams_ctx_t *ctx,
449  uint8_t id);
450 
451 #endif // OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_STREAMS_H_