Software APIs
usbdev_iso_test.c
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 // USB Isochronous streaming data test
6 //
7 // This test requires interaction with the USB DPI model or a test application
8 // on the USB host. The test initializes the USB device and configures a set of
9 // endpoints for data streaming using bulk transfers.
10 //
11 // The DPI model mimicks a USB host. After device initialization, it detects
12 // the assertion of the pullup and first assigns an address to the device.
13 // For this test it will then repeatedly fetch data via IN requests to
14 // each stream and propagate that data to the corresponding OUT endpoints.
15 //
16 // The data itself is pseudo-randomly generated by the sender and,
17 // independently, by the receiving code to check that the data has been
18 // propagated unmodified and without data loss, corruption, replication etc.
19 
23 #include "sw/device/lib/testing/pinmux_testutils.h"
24 #include "sw/device/lib/testing/test_framework/check.h"
26 #include "sw/device/lib/testing/usb_testutils.h"
27 #include "sw/device/lib/testing/usb_testutils_controlep.h"
28 #include "sw/device/lib/testing/usb_testutils_diags.h"
29 #include "sw/device/lib/testing/usb_testutils_streams.h"
30 
31 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
32 
33 // Number of streams to be tested
34 //
35 // Note: because Isochronous streams are guaranteed the requested amount of
36 // bus bandwidth, the number of concurrent streams that may be supported is
37 // limited to four if connected through a hub (6 without hub(s)).
38 #if !defined(NUM_STREAMS) || NUM_STREAMS > 4U
39 #define NUM_STREAMS 4U
40 #endif
41 
42 #define TRANSFER_BYTES_SILICON (4U << 20)
43 #define TRANSFER_BYTES_FPGA (8U << 16)
44 
45 // This is appropriate for a Verilator chip simulation with 15 min timeout
46 #define TRANSFER_BYTES_VERILATOR 0x2400U
47 
48 // For top-level DV simulation (regression runs, deterministic behavior)
49 #define TRANSFER_BYTES_DVSIM 0x800U
50 
51 /**
52  * Configuration values for USB.
53  */
54 static const uint8_t config_descriptors[] = {
55  USB_CFG_DSCR_HEAD(USB_CFG_DSCR_LEN + NUM_STREAMS * (USB_INTERFACE_DSCR_LEN +
56  2 * USB_EP_DSCR_LEN),
57  NUM_STREAMS),
58 
59  // Up to 11 interfaces and NUM_STREAMS in the descriptor head specifies how
60  // many of the interfaces will be declared to the host
61  VEND_INTERFACE_DSCR(0, 2, 0x50, 1),
62  USB_EP_DSCR(0, 1U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
63  USB_EP_DSCR(1, 1U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
64 
65  VEND_INTERFACE_DSCR(1, 2, 0x50, 1),
66  USB_EP_DSCR(0, 2U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
67  USB_EP_DSCR(1, 2U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
68 
69  VEND_INTERFACE_DSCR(2, 2, 0x50, 1),
70  USB_EP_DSCR(0, 3U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
71  USB_EP_DSCR(1, 3U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
72 
73  VEND_INTERFACE_DSCR(3, 2, 0x50, 1),
74  USB_EP_DSCR(0, 4U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
75  USB_EP_DSCR(1, 4U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
76 
77  VEND_INTERFACE_DSCR(4, 2, 0x50, 1),
78  USB_EP_DSCR(0, 5U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
79  USB_EP_DSCR(1, 5U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
80 
81  VEND_INTERFACE_DSCR(5, 2, 0x50, 1),
82  USB_EP_DSCR(0, 6U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
83  USB_EP_DSCR(1, 6U, kUsbTransferTypeIsochronous, USBDEV_MAX_PACKET_SIZE, 1),
84 };
85 
86 /**
87  * Test flags specifying the nature and direction of the data stream(s)
88  */
89 static usbdev_stream_flags_t test_flags;
90 
91 /**
92  * Test descriptor
93  */
94 static uint8_t test_descriptor[USB_TESTUTILS_TEST_DSCR_LEN];
95 
96 /**
97  * USB device context types.
98  */
99 static usb_testutils_ctx_t usbdev;
100 static usb_testutils_controlep_ctx_t usbdev_control;
101 
102 /**
103  * Pinmux handle
104  */
105 static dif_pinmux_t pinmux;
106 
107 /**
108  * State information for streaming data test
109  */
110 static usb_testutils_streams_ctx_t stream_test;
111 
112 /**
113  * Specify whether to perform verbose logging, for visibility
114  * (Note that this substantially alters the timing of interactions with the
115  * DPI model and will increase the simulation time)
116  */
117 static const bool kVerbose = false;
118 
119 /*
120  * These switches may be modified manually to experimentally measure the
121  * performance of IN traffic in isolation, or IN/OUT together etc.
122  *
123  * Are we sending data?
124  */
125 static const bool kSending = true;
126 
127 /**
128  * Are we generating a valid byte sequence?
129  */
130 static const bool kGenerating = true;
131 
132 /**
133  * Retrying is meaningless for this test since we have only Isochronous streams.
134  */
135 static const bool kRetrying = false;
136 
137 /**
138  * Are we expecting to receive data?
139  */
140 static const bool kRecving = true;
141 
142 /**
143  * Send only maximal length packets?
144  * (important for performance measurements on the USB, but obviously undesirable
145  * for testing reliability/function)
146  */
147 static const bool kMaxPackets = false;
148 
149 /**
150  * Number of streams to be created
151  */
152 static const unsigned nstreams = NUM_STREAMS;
153 
154 OTTF_DEFINE_TEST_CONFIG();
155 
156 bool test_main(void) {
157  // Context state for streaming test
158  usb_testutils_streams_ctx_t *ctx = &stream_test;
159 
160  LOG_INFO("Running USBDEV ISO Test");
161 
162  // Check we can support the requested number of streams
163  CHECK(nstreams && nstreams < USBDEV_NUM_ENDPOINTS);
164 
165  // Decide upon the number of bytes to be transferred for the entire test
166  uint32_t transfer_bytes = TRANSFER_BYTES_FPGA;
167  switch (kDeviceType) {
168  case kDeviceSimVerilator:
169  transfer_bytes = TRANSFER_BYTES_VERILATOR;
170  break;
171  case kDeviceSimDV:
172  transfer_bytes = TRANSFER_BYTES_DVSIM;
173  break;
174  case kDeviceSilicon:
175  transfer_bytes = TRANSFER_BYTES_SILICON;
176  break;
177  case kDeviceFpgaCw340:
178  break;
179  default:
180  CHECK(kDeviceType == kDeviceFpgaCw310);
181  break;
182  }
183  transfer_bytes = (transfer_bytes + nstreams - 1) / nstreams;
184  LOG_INFO(" - %u stream(s), 0x%x bytes each", nstreams, transfer_bytes);
185 
186  CHECK_DIF_OK(dif_pinmux_init(
188  pinmux_testutils_init(&pinmux);
189  CHECK_DIF_OK(dif_pinmux_input_select(
192 
193  // Construct the test/stream flags to be used
194  test_flags = (kSending ? kUsbdevStreamFlagRetrieve : 0U) |
195  (kGenerating ? kUsbdevStreamFlagCheck : 0U) |
196  (kRetrying ? kUsbdevStreamFlagRetry : 0U) |
197  (kRecving ? kUsbdevStreamFlagSend : 0U) |
198  // Note: the 'max packets' test flag is not required by the DPI
199  (kMaxPackets ? kUsbdevStreamFlagMaxPackets : 0U);
200 
201  // Initialize the test descriptor
202  // Note: the 'max packets' test flag is not required by the DPI model
203  const uint8_t desc[] = {USB_TESTUTILS_TEST_DSCR(
204  kUsbTestNumberIso, NUM_STREAMS | (uint8_t)test_flags, 0, 0, 0)};
205  memcpy(test_descriptor, desc, sizeof(test_descriptor));
206 
207  // Remember context state for usb_testutils context
208  ctx->usbdev = &usbdev;
209 
210  // Call `usbdev_init` here so that DPI will not start until the
211  // simulation has finished all of the printing, which takes a while
212  // if `--trace` was passed in.
213  CHECK_STATUS_OK(usb_testutils_init(ctx->usbdev, /*pinflip=*/false,
214  /*en_diff_rcvr=*/true,
215  /*tx_use_d_se0=*/false));
216  CHECK_STATUS_OK(usb_testutils_controlep_init(
217  &usbdev_control, ctx->usbdev, 0, config_descriptors,
218  sizeof(config_descriptors), test_descriptor, sizeof(test_descriptor)));
219 
220  // Proceed only when the device has been configured; this allows host-side
221  // software to establish communication.
222  CHECK_STATUS_OK(
223  usb_testutils_controlep_config_wait(&usbdev_control, &usbdev));
224 
225  // Describe the transfer type of each stream;
226  // Note: make all of the streams Isochronous streams for now, but later we
227  // shall want to test a mix of different transfer types concurrently.
228  usb_testutils_transfer_type_t xfr_types[USBUTILS_STREAMS_MAX];
229  for (unsigned s = 0U; s < nstreams; s++) {
230  xfr_types[s] = kUsbTransferTypeIsochronous;
231  }
232 
233  // Initialise the state of the streams
234  CHECK_STATUS_OK(usb_testutils_streams_init(
235  ctx, nstreams, xfr_types, transfer_bytes, test_flags, kVerbose));
236 
237  USBUTILS_USER_PROMPT("Start host-side streaming software");
238 
239  // Streaming loop; most of the work is done by the usb_testutils_streams base
240  // code and we don't need to specialize its behavior for this test.
241  bool done = false;
242  do {
243  CHECK_STATUS_OK(usb_testutils_streams_service(ctx));
244 
245  // See whether any streams still have more work to do
246  done = usb_testutils_streams_completed(ctx);
247  } while (!done);
248 
249  // Determine the total counts of bytes sent and received
250  uint32_t tx_bytes = 0U;
251  uint32_t rx_bytes = 0U;
252  for (uint8_t s = 0U; s < nstreams; s++) {
253  uint32_t tx, rx;
254  CHECK_STATUS_OK(usb_testutils_stream_status(ctx, s, NULL, &tx, &rx));
255  tx_bytes += tx;
256  rx_bytes += rx;
257  }
258 
259  LOG_INFO("USB sent 0x%x byte(s), received and checked 0x%x byte(s)", tx_bytes,
260  rx_bytes);
261 
262  // Note: since Isochronous streams are susceptible to packet loss we can only
263  // perform a lower bounds check on the transmitted and received byte counts.
264  if (kSending) {
265  CHECK(tx_bytes >= nstreams * transfer_bytes,
266  "Unexpected count of byte(s) sent to USB host");
267  }
268  if (kRecving) {
269  CHECK(rx_bytes >= nstreams * transfer_bytes,
270  "Unexpected count of byte(s) received from USB host");
271  }
272 
273  return true;
274 }