Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SiVal, usbdev] Suspend and Resume test. #25728

Merged
merged 5 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hw/top_earlgrey/data/ip/chip_usbdev_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@
si_stage: SV3
lc_states: ["PROD"]
tests: []
bazel: []
bazel: ["//sw/device/tests:usbdev_suspend_resume_test"]
}
{
name: chip_sw_usbdev_aon_wake_reset
Expand Down
2 changes: 2 additions & 0 deletions sw/device/lib/dif/dif_usbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,8 @@ dif_result_t dif_usbdev_get_wake_status(const dif_usbdev_t *usbdev,
bitfield_bit32_read(reg_val, USBDEV_WAKE_EVENTS_DISCONNECTED_BIT);
status->bus_reset =
bitfield_bit32_read(reg_val, USBDEV_WAKE_EVENTS_BUS_RESET_BIT);
status->bus_not_idle =
bitfield_bit32_read(reg_val, USBDEV_WAKE_EVENTS_BUS_NOT_IDLE_BIT);
return kDifOk;
}

Expand Down
2 changes: 2 additions & 0 deletions sw/device/lib/dif/dif_usbdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,8 @@ typedef struct dif_usbdev_wake_status {
bool disconnected;
/** Whether the USB was reset while the AON wake module was active. */
bool bus_reset;
/** Whether the USB became non-Idle whilst the AON wake module was active. */
bool bus_not_idle;
} dif_usbdev_wake_status_t;

/**
Expand Down
40 changes: 40 additions & 0 deletions sw/device/lib/testing/usb_testutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ status_t usb_testutils_poll(usb_testutils_ctx_t *ctx) {
ctx->got_frame = true;
}

// Report all link events to the registered callback handler, if any
if (ctx->link_callback) {
const dif_usbdev_irq_state_snapshot_t kIrqsLink =
(1u << kDifUsbdevIrqPowered) | (1u << kDifUsbdevIrqDisconnected) |
(1u << kDifUsbdevIrqHostLost) | (1u << kDifUsbdevIrqLinkReset) |
(1u << kDifUsbdevIrqLinkSuspend) | (1u << kDifUsbdevIrqLinkResume) |
(1u << kDifUsbdevIrqFrame);
if (istate & kIrqsLink) {
// Retrieve and report the current link state, since this should help
// resolve any confusion caused by delayed reporting of earlier link
// events (eg. disconnect/powered, suspend/resume)
dif_usbdev_link_state_t link_state;
TRY(dif_usbdev_status_get_link_state(ctx->dev, &link_state));

// Indicate only the link-related interrupts
TRY(ctx->link_callback(ctx->ctx_link, istate & kIrqsLink, link_state));
}
}

// Note: LinkInErr will be raised in response to a packet being NAKed by the
// host which is not expected behavior on a physical USB but this is something
// that the DPI model does to exercise packet resending when running
Expand Down Expand Up @@ -250,6 +269,20 @@ status_t usb_testutils_poll(usb_testutils_ctx_t *ctx) {
return OK_STATUS();
}

status_t usb_testutils_link_callback_register(usb_testutils_ctx_t *ctx,
usb_testutils_link_handler_t link,
void *ctx_link) {
CHECK(ctx != NULL);

// Retain the new link callback handler and its context pointer; either of
// these may be NULL, respectively to deregister a handler or because no
// context is required.
ctx->link_callback = link;
ctx->ctx_link = ctx_link;

return OK_STATUS();
}

status_t usb_testutils_transfer_send(usb_testutils_ctx_t *ctx, uint8_t ep,
const uint8_t *data, uint32_t length,
usb_testutils_xfr_flags_t flags) {
Expand Down Expand Up @@ -423,6 +456,9 @@ status_t usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
ctx->got_frame = false;
ctx->frame = 0u;

// No callback handler for link events
ctx->link_callback = NULL;

TRY(dif_usbdev_init(mmio_region_from_addr(USBDEV_BASE_ADDR), ctx->dev));

dif_usbdev_config_t config = {
Expand All @@ -446,6 +482,10 @@ status_t usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
// All about polling...
TRY(dif_usbdev_irq_disable_all(ctx->dev, NULL));

// Clear any outstanding interrupts such as Powered/Disconnected interrupts
// from when the usbdev came out of reset
TRY(dif_usbdev_irq_acknowledge_all(ctx->dev));

// Provide buffers for any packet reception
TRY(dif_usbdev_fill_available_fifos(ctx->dev, ctx->buffer_pool));

Expand Down
28 changes: 28 additions & 0 deletions sw/device/lib/testing/usb_testutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#include "sw/device/lib/testing/test_framework/check.h"
#include "usb_testutils_diags.h"

// Have Data Toggle Restore functionality (Prod)?
#define USBDEV_HAVE_TOGGLE_STATE 0
// Have separated Available OUT and SETUP Buffer FIFOs (Prod)?
#define USBDEV_HAVE_SEPARATED_FIFOS 0

// Result codes to rx/tx callback handlers
typedef enum {
/**
Expand Down Expand Up @@ -87,6 +92,9 @@ typedef status_t (*usb_testutils_rx_handler_t)(void *,
typedef status_t (*usb_testutils_tx_flush_handler_t)(void *);
/* Called when a USB link reset is detected */
typedef status_t (*usb_testutils_reset_handler_t)(void *);
/* Called when a link event has been detected */
typedef status_t (*usb_testutils_link_handler_t)(
void *, dif_usbdev_irq_state_snapshot_t, dif_usbdev_link_state_t);

// In-progress larger buffer transfer to/from host
typedef struct usb_testutils_transfer {
Expand Down Expand Up @@ -140,6 +148,14 @@ struct usb_testutils_ctx {
* Most recent bus frame number received from host
*/
uint16_t frame;
/**
* Link event callback
*/
usb_testutils_link_handler_t link_callback;
/**
* Context pointer for link event callkback
*/
void *ctx_link;

/**
* IN endpoints
Expand Down Expand Up @@ -324,6 +340,18 @@ OT_WARN_UNUSED_RESULT
status_t usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
bool en_diff_rcvr, bool tx_use_d_se0);

/**
* Register a callback function to be notified of link events
*
* @param ctx initialized usb test utils context pointer
* @param link link event callback handler
* @param ctx_link context pointer for link event callback
*/
OT_WARN_UNUSED_RESULT
status_t usb_testutils_link_callback_register(usb_testutils_ctx_t *ctx,
usb_testutils_link_handler_t link,
void *ctx_link);

/**
* Send a larger data transfer from the given endpoint
*
Expand Down
3 changes: 3 additions & 0 deletions sw/device/lib/testing/usb_testutils_controlep.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ static usb_testutils_ctstate_t setup_req(usb_testutils_controlep_ctx_t *ctctx,
if (wValue == kUsbFeatureEndpointHalt) {
CHECK_DIF_OK(dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint,
kDifToggleDisabled));
// Clearing the Halt feature on an endpoint that is using Data Toggling
// also requires us to clear the Data Toggle for that endpoint
CHECK_DIF_OK(dif_usbdev_clear_data_toggle(ctx->dev, endpoint.number));
// send zero length packet for status phase
CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
return kUsbTestutilsCtStatIn;
Expand Down
90 changes: 85 additions & 5 deletions sw/device/lib/testing/usb_testutils_streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@

#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/usb_testutils_controlep.h"
#include "sw/device/lib/testing/usb_testutils_diags.h"

#define MODULE_ID MAKE_MODULE_ID('u', 't', 's')

// Maximum length of the configuration descriptor.
#define CFG_DSCR_LEN_MAX \
(USB_CFG_DSCR_LEN + \
USBUTILS_STREAMS_MAX * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN))

/**
* Read method to be employed
*/
Expand Down Expand Up @@ -673,11 +679,10 @@ status_t usb_testutils_stream_service(usb_testutils_streams_ctx_t *ctx,
return OK_STATUS();
}

status_t usb_testutils_streams_init(usb_testutils_streams_ctx_t *ctx,
unsigned nstreams,
usb_testutils_transfer_type_t xfr_types[],
uint32_t num_bytes,
usbdev_stream_flags_t flags, bool verbose) {
status_t usb_testutils_streams_init(
usb_testutils_streams_ctx_t *ctx, unsigned nstreams,
const usb_testutils_transfer_type_t xfr_types[], uint32_t num_bytes,
usbdev_stream_flags_t flags, bool verbose) {
TRY_CHECK(nstreams <= USBUTILS_STREAMS_MAX);
TRY_CHECK(nstreams <= UINT8_MAX);

Expand All @@ -697,6 +702,81 @@ status_t usb_testutils_streams_init(usb_testutils_streams_ctx_t *ctx,
return OK_STATUS();
}

status_t usb_testutils_streams_typed_init(
usb_testutils_streams_ctx_t *ctx, uint8_t *cfg, uint16_t len,
unsigned nstreams, const usb_testutils_transfer_type_t xfr_types[],
uint32_t num_bytes, usbdev_stream_flags_t flags, bool verbose,
uint32_t *types) {
TRY_CHECK(nstreams <= USBUTILS_STREAMS_MAX);

// Does the caller require a bitmap of the transfer type(s) collected?
if (types) {
*types = 0U;
}

// Total length of the configuration descriptor; validate caller buffer.
size_t cfg_len = USB_CFG_DSCR_LEN +
nstreams * (USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN);
TRY_CHECK(cfg && cfg_len <= len);

// Configuration Descriptor header.
uint8_t head[CFG_DSCR_LEN_MAX] = {
USB_CFG_DSCR_HEAD((uint16_t)cfg_len, (uint8_t)nstreams)};
memcpy(cfg, head, USB_CFG_DSCR_LEN);
cfg += USB_CFG_DSCR_LEN;

// Followed by programmatically-generated list of interface descriptors.
for (uint8_t id = 0U; id < nstreams; id++) {
usb_testutils_transfer_type_t xfr_type = xfr_types[id];
// Return to the caller the transfer type of each stream in turn.
if (types) {
*types |= xfr_type << (id * 2U);
}

uint8_t ep_in = (uint8_t)(id + 1U);
uint8_t ep_out = (uint8_t)(id + 1U);
TRY(usb_testutils_stream_init(ctx, id, xfr_type, ep_in, ep_out, num_bytes,
flags, verbose));

// Isochronous and Interrupt endpoints require a bInterval value of 1.
uint8_t bInterval = (xfr_type == kUsbTransferTypeIsochronous ||
xfr_type == kUsbTransferTypeInterrupt);

// Description of a single interface.
uint8_t int_dscr[USB_INTERFACE_DSCR_LEN + 2 * USB_EP_DSCR_LEN] = {
VEND_INTERFACE_DSCR(id, 2, 0x50, 1),
USB_EP_DSCR(0, ep_out, (uint8_t)xfr_type, USBDEV_MAX_PACKET_SIZE,
bInterval),
USB_EP_DSCR(1, ep_in, (uint8_t)xfr_type, USBDEV_MAX_PACKET_SIZE,
bInterval),
};

// Append interface descriptor to the configuration descriptor.
memcpy(cfg, int_dscr, sizeof(int_dscr));
cfg += sizeof(int_dscr);

if (verbose) {
/**
* Indexed by usb_testutils_transfer_type_t
*/
static const char *xfr_name[] = {
"Control",
"Isochronous",
"Bulk",
"Interrupt",
};
TRY_CHECK(xfr_type <= ARRAYSIZE(xfr_name));
LOG_INFO("S%u: IN %u:OUT %u : %s - 0x%x bytes flags 0x%x", id, ep_in,
ep_out, xfr_name[xfr_type], num_bytes, flags);
}
}

// Remember the stream count and apportion the available tx buffers
TRY_CHECK(usb_testutils_streams_count_set(ctx, nstreams));

return OK_STATUS();
}

status_t usb_testutils_streams_service(usb_testutils_streams_ctx_t *ctx) {
TRY_CHECK(ctx->nstreams <= UINT8_MAX);

Expand Down
33 changes: 28 additions & 5 deletions sw/device/lib/testing/usb_testutils_streams.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,10 @@ struct usb_testutils_streams_ctx {
* @return The result status of the operation.
*/
OT_WARN_UNUSED_RESULT
status_t usb_testutils_streams_init(usb_testutils_streams_ctx_t *ctx,
unsigned nstreams,
usb_testutils_transfer_type_t xfr_types[],
uint32_t num_bytes,
usbdev_stream_flags_t flags, bool verbose);
status_t usb_testutils_streams_init(
usb_testutils_streams_ctx_t *ctx, unsigned nstreams,
const usb_testutils_transfer_type_t xfr_types[], uint32_t num_bytes,
usbdev_stream_flags_t flags, bool verbose);

/**
* Service all streams, preparing and/or sending any data that we can, as well
Expand Down Expand Up @@ -343,6 +342,30 @@ status_t usb_testutils_stream_init(usb_testutils_streams_ctx_t *ctx, uint8_t id,
uint32_t num_bytes,
usbdev_stream_flags_t flags, bool verbose);

/**
* Initialize a set of streams of specified types, dynamically constructing a
* standard USB configuration descriptor for the caller. The transfer types of
* the streams may optionally be returned via `types` for passing to the DPI
* model/host.
*
* @param ctx Context state for streaming test.
* @param cfg Receives the configuration descriptor.
* @param len Size of buffer receiving the configuration descriptor.
* @param nstreams Number of streams to be initialized.
* @param xfr_types The transfer types of the streams.
* @param num_bytes Number of bytes to be transferred by stream
* @param flags Stream/test flags
* @param verbose Whether to perform verbose logging for this stream
* @param types Optionally receives the bitmap of transfer types.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
status_t usb_testutils_streams_typed_init(
usb_testutils_streams_ctx_t *ctx, uint8_t *cfg, uint16_t len,
unsigned nstreams, const usb_testutils_transfer_type_t xfr_types[],
uint32_t num_bytes, usbdev_stream_flags_t flags, bool verbose,
uint32_t *types);

/**
* Specify the number of already-initialized streams, and apportion the
* available tx buffers among them. To be called after usb_testutils_stream_init
Expand Down
Loading
Loading