Skip to content

Commit c782e57

Browse files
committed
Merge branch 'feature/usb_host_hub_support_collective_backport_v5.3' into 'release/v5.3'
refactor(usb/host): Prerequisite Refactoring For Hub Collective backport (v5.3) See merge request espressif/esp-idf!30480
2 parents 0019a9f + 7db459d commit c782e57

File tree

16 files changed

+1074
-774
lines changed

16 files changed

+1074
-774
lines changed

components/hal/include/hal/usb_dwc_hal.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ typedef struct {
205205
* - The peripheral must have been reset and clock un-gated
206206
* - The USB PHY (internal or external) and associated GPIOs must already be configured
207207
* - GPIO pins configured
208-
* - Interrupt allocated but DISABLED (in case of an unknown interupt state)
208+
* - Interrupt allocated but DISABLED (in case of an unknown interrupt state)
209209
* Exit:
210210
* - Checks to see if DWC_OTG is alive, and if HW version/config is correct
211211
* - HAl context initialized
@@ -290,7 +290,7 @@ static inline void usb_dwc_hal_port_init(usb_dwc_hal_context_t *hal)
290290
/**
291291
* @brief Deinitialize the host port
292292
*
293-
* - Will disable the host port's interrupts preventing further port aand channel events from ocurring
293+
* - Will disable the host port's interrupts preventing further port aand channel events from occurring
294294
*
295295
* @param hal Context of the HAL layer
296296
*/
@@ -333,7 +333,6 @@ static inline void usb_dwc_hal_port_toggle_power(usb_dwc_hal_context_t *hal, boo
333333
*/
334334
static inline void usb_dwc_hal_port_toggle_reset(usb_dwc_hal_context_t *hal, bool enable)
335335
{
336-
HAL_ASSERT(hal->channels.num_allocd == 0); //Cannot reset if there are still allocated channels
337336
usb_dwc_ll_hprt_set_port_reset(hal->dev, enable);
338337
}
339338

@@ -447,7 +446,7 @@ static inline void usb_dwc_hal_port_periodic_enable(usb_dwc_hal_context_t *hal)
447446
/**
448447
* @brief Disable periodic scheduling
449448
*
450-
* Disabling periodic scheduling will save a bit of DMA bandwith (as the controller will no longer fetch the schedule
449+
* Disabling periodic scheduling will save a bit of DMA bandwidth (as the controller will no longer fetch the schedule
451450
* from the frame list).
452451
*
453452
* @note Before disabling periodic scheduling, it is the user's responsibility to ensure that all periodic channels have
@@ -505,17 +504,17 @@ static inline usb_dwc_speed_t usb_dwc_hal_port_get_conn_speed(usb_dwc_hal_contex
505504
* @brief Disable the debounce lock
506505
*
507506
* This function must be called after calling usb_dwc_hal_port_check_if_connected() and will allow connection/disconnection
508-
* events to occur again. Any pending connection or disconenction interrupts are cleared.
507+
* events to occur again. Any pending connection or disconnection interrupts are cleared.
509508
*
510509
* @param hal Context of the HAL layer
511510
*/
512511
static inline void usb_dwc_hal_disable_debounce_lock(usb_dwc_hal_context_t *hal)
513512
{
514513
hal->flags.dbnc_lock_enabled = 0;
515-
//Clear Conenction and disconenction interrupt in case it triggered again
514+
//Clear Connection and disconnection interrupt in case it triggered again
516515
usb_dwc_ll_gintsts_clear_intrs(hal->dev, USB_DWC_LL_INTR_CORE_DISCONNINT);
517516
usb_dwc_ll_hprt_intr_clear(hal->dev, USB_DWC_LL_INTR_HPRT_PRTCONNDET);
518-
//Reenable the hprt (connection) and disconnection interrupts
517+
//Re-enable the hprt (connection) and disconnection interrupts
519518
usb_dwc_ll_gintmsk_en_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_DISCONNINT);
520519
}
521520

@@ -672,10 +671,10 @@ bool usb_dwc_hal_chan_request_halt(usb_dwc_hal_chan_t *chan_obj);
672671
/**
673672
* @brief Indicate that a channel is halted after a port error
674673
*
675-
* When a port error occurs (e.g., discconect, overcurrent):
674+
* When a port error occurs (e.g., disconnect, overcurrent):
676675
* - Any previously active channels will remain active (i.e., they will not receive a channel interrupt)
677676
* - Attempting to disable them using usb_dwc_hal_chan_request_halt() will NOT generate an interrupt for ISOC channels
678-
* (probalby something to do with the periodic scheduling)
677+
* (probably something to do with the periodic scheduling)
679678
*
680679
* However, the channel's enable bit can be left as 1 since after a port error, a soft reset will be done anyways.
681680
* This function simply updates the channels internal state variable to indicate it is halted (thus allowing it to be

components/usb/hcd_dwc.c

Lines changed: 45 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,7 @@ struct pipe_obj {
214214
uint32_t waiting_halt: 1;
215215
uint32_t pipe_cmd_processing: 1;
216216
uint32_t has_urb: 1; // Indicates there is at least one URB either pending, in-flight, or done
217-
uint32_t persist: 1; // indicates that this pipe should persist through a run-time port reset
218-
uint32_t reset_lock: 1; // Indicates that this pipe is undergoing a run-time reset
219-
uint32_t reserved27: 27;
217+
uint32_t reserved29: 29;
220218
};
221219
uint32_t val;
222220
} cs_flags;
@@ -560,28 +558,6 @@ static esp_err_t _pipe_cmd_clear(pipe_t *pipe);
560558

561559
// ------------------------ Port ---------------------------
562560

563-
/**
564-
* @brief Prepare persistent pipes for reset
565-
*
566-
* This function checks if all pipes are reset persistent and proceeds to free their underlying HAL channels for the
567-
* persistent pipes. This should be called before a run time reset
568-
*
569-
* @param port Port object
570-
* @return true All pipes are persistent and their channels are freed
571-
* @return false Not all pipes are persistent
572-
*/
573-
static bool _port_persist_all_pipes(port_t *port);
574-
575-
/**
576-
* @brief Recovers all persistent pipes after a reset
577-
*
578-
* This function will recover all persistent pipes after a reset and reallocate their underlying HAl channels. This
579-
* function should be called after a reset.
580-
*
581-
* @param port Port object
582-
*/
583-
static void _port_recover_all_pipes(port_t *port);
584-
585561
/**
586562
* @brief Checks if all pipes are in the halted state
587563
*
@@ -1162,44 +1138,6 @@ esp_err_t hcd_uninstall(void)
11621138

11631139
// ----------------------- Helpers -------------------------
11641140

1165-
static bool _port_persist_all_pipes(port_t *port)
1166-
{
1167-
if (port->num_pipes_queued > 0) {
1168-
// All pipes must be idle before we run-time reset
1169-
return false;
1170-
}
1171-
bool all_persist = true;
1172-
pipe_t *pipe;
1173-
// Check that each pipe is persistent
1174-
TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) {
1175-
if (!pipe->cs_flags.persist) {
1176-
all_persist = false;
1177-
break;
1178-
}
1179-
}
1180-
if (!all_persist) {
1181-
// At least one pipe is not persistent. All pipes must be freed or made persistent before we can reset
1182-
return false;
1183-
}
1184-
TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) {
1185-
pipe->cs_flags.reset_lock = 1;
1186-
usb_dwc_hal_chan_free(port->hal, pipe->chan_obj);
1187-
}
1188-
return true;
1189-
}
1190-
1191-
static void _port_recover_all_pipes(port_t *port)
1192-
{
1193-
pipe_t *pipe;
1194-
TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) {
1195-
pipe->cs_flags.persist = 0;
1196-
pipe->cs_flags.reset_lock = 0;
1197-
usb_dwc_hal_chan_alloc(port->hal, pipe->chan_obj, (void *)pipe);
1198-
usb_dwc_hal_chan_set_ep_char(port->hal, pipe->chan_obj, &pipe->ep_char);
1199-
}
1200-
CACHE_SYNC_FRAME_LIST(port->frame_list);
1201-
}
1202-
12031141
static bool _port_check_all_pipes_halted(port_t *port)
12041142
{
12051143
bool all_halted = true;
@@ -1276,20 +1214,26 @@ static esp_err_t _port_cmd_power_off(port_t *port)
12761214
static esp_err_t _port_cmd_reset(port_t *port)
12771215
{
12781216
esp_err_t ret;
1279-
// Port can only a reset when it is in the enabled or disabled states (in case of new connection)
1217+
1218+
// Port can only a reset when it is in the enabled or disabled (in the case of a new connection)states.
12801219
if (port->state != HCD_PORT_STATE_ENABLED && port->state != HCD_PORT_STATE_DISABLED) {
12811220
ret = ESP_ERR_INVALID_STATE;
12821221
goto exit;
12831222
}
1284-
bool is_runtime_reset = (port->state == HCD_PORT_STATE_ENABLED) ? true : false;
1285-
if (is_runtime_reset && !_port_persist_all_pipes(port)) {
1286-
// If this is a run time reset, check all pipes that are still allocated can persist the reset
1223+
// Port can only be reset if all pipes are idle
1224+
if (port->num_pipes_queued > 0) {
12871225
ret = ESP_ERR_INVALID_STATE;
12881226
goto exit;
12891227
}
1290-
// All pipes (if any_) are guaranteed to be persistent at this point. Proceed to resetting the bus
1228+
/*
1229+
Proceed to resetting the bus
1230+
- Update the port's state variable
1231+
- Hold the bus in the reset state for RESET_HOLD_MS.
1232+
- Return the bus to the idle state for RESET_RECOVERY_MS
1233+
*/
12911234
port->state = HCD_PORT_STATE_RESETTING;
1292-
// Put and hold the bus in the reset state. If the port was previously enabled, a disabled event will occur after this
1235+
1236+
// Place the bus into the reset state. If the port was previously enabled, a disabled event will occur after this
12931237
usb_dwc_hal_port_toggle_reset(port->hal, true);
12941238
HCD_EXIT_CRITICAL();
12951239
vTaskDelay(pdMS_TO_TICKS(RESET_HOLD_MS));
@@ -1299,7 +1243,8 @@ static esp_err_t _port_cmd_reset(port_t *port)
12991243
ret = ESP_ERR_INVALID_RESPONSE;
13001244
goto bailout;
13011245
}
1302-
// Return the bus to the idle state and hold it for the required reset recovery time. Port enabled event should occur
1246+
1247+
// Return the bus to the idle state. Port enabled event should occur
13031248
usb_dwc_hal_port_toggle_reset(port->hal, false);
13041249
HCD_EXIT_CRITICAL();
13051250
vTaskDelay(pdMS_TO_TICKS(RESET_RECOVERY_MS));
@@ -1309,16 +1254,20 @@ static esp_err_t _port_cmd_reset(port_t *port)
13091254
ret = ESP_ERR_INVALID_RESPONSE;
13101255
goto bailout;
13111256
}
1312-
// Set FIFO sizes based on the selected biasing
1313-
usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias);
1314-
// We start periodic scheduling only after a RESET command since SOFs only start after a reset
1315-
usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN);
1316-
usb_dwc_hal_port_periodic_enable(port->hal);
1257+
1258+
// Reinitialize port registers.
1259+
usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias); // Set FIFO biases
1260+
usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); // Set periodic frame list
1261+
usb_dwc_hal_port_periodic_enable(port->hal); // Enable periodic scheduling
1262+
13171263
ret = ESP_OK;
13181264
bailout:
1319-
if (is_runtime_reset) {
1320-
_port_recover_all_pipes(port);
1265+
// Reinitialize channel registers
1266+
pipe_t *pipe;
1267+
TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) {
1268+
usb_dwc_hal_chan_set_ep_char(port->hal, pipe->chan_obj, &pipe->ep_char);
13211269
}
1270+
CACHE_SYNC_FRAME_LIST(port->frame_list);
13221271
exit:
13231272
return ret;
13241273
}
@@ -1987,8 +1936,7 @@ esp_err_t hcd_pipe_free(hcd_pipe_handle_t pipe_hdl)
19871936
HCD_ENTER_CRITICAL();
19881937
// Check that all URBs have been removed and pipe has no pending events
19891938
HCD_CHECK_FROM_CRIT(!pipe->multi_buffer_control.buffer_is_executing
1990-
&& !pipe->cs_flags.has_urb
1991-
&& !pipe->cs_flags.reset_lock,
1939+
&& !pipe->cs_flags.has_urb,
19921940
ESP_ERR_INVALID_STATE);
19931941
// Remove pipe from the list of idle pipes (it must be in the idle list because it should have no queued URBs)
19941942
TAILQ_REMOVE(&pipe->port->pipes_idle_tailq, pipe, tailq_entry);
@@ -2011,8 +1959,7 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps)
20111959
HCD_ENTER_CRITICAL();
20121960
// Check if pipe is in the correct state to be updated
20131961
HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing &&
2014-
!pipe->cs_flags.has_urb &&
2015-
!pipe->cs_flags.reset_lock,
1962+
!pipe->cs_flags.has_urb,
20161963
ESP_ERR_INVALID_STATE);
20171964
pipe->ep_char.mps = mps;
20181965
// Update the underlying channel's registers
@@ -2027,8 +1974,7 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr)
20271974
HCD_ENTER_CRITICAL();
20281975
// Check if pipe is in the correct state to be updated
20291976
HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing &&
2030-
!pipe->cs_flags.has_urb &&
2031-
!pipe->cs_flags.reset_lock,
1977+
!pipe->cs_flags.has_urb,
20321978
ESP_ERR_INVALID_STATE);
20331979
pipe->ep_char.dev_addr = dev_addr;
20341980
// Update the underlying channel's registers
@@ -2037,35 +1983,6 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr)
20371983
return ESP_OK;
20381984
}
20391985

2040-
esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback_t callback, void *user_arg)
2041-
{
2042-
pipe_t *pipe = (pipe_t *)pipe_hdl;
2043-
HCD_ENTER_CRITICAL();
2044-
// Check if pipe is in the correct state to be updated
2045-
HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing &&
2046-
!pipe->cs_flags.has_urb &&
2047-
!pipe->cs_flags.reset_lock,
2048-
ESP_ERR_INVALID_STATE);
2049-
pipe->callback = callback;
2050-
pipe->callback_arg = user_arg;
2051-
HCD_EXIT_CRITICAL();
2052-
return ESP_OK;
2053-
}
2054-
2055-
esp_err_t hcd_pipe_set_persist_reset(hcd_pipe_handle_t pipe_hdl)
2056-
{
2057-
pipe_t *pipe = (pipe_t *)pipe_hdl;
2058-
HCD_ENTER_CRITICAL();
2059-
// Check if pipe is in the correct state to be updated
2060-
HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing &&
2061-
!pipe->cs_flags.has_urb &&
2062-
!pipe->cs_flags.reset_lock,
2063-
ESP_ERR_INVALID_STATE);
2064-
pipe->cs_flags.persist = 1;
2065-
HCD_EXIT_CRITICAL();
2066-
return ESP_OK;
2067-
}
2068-
20691986
void *hcd_pipe_get_context(hcd_pipe_handle_t pipe_hdl)
20701987
{
20711988
pipe_t *pipe = (pipe_t *)pipe_hdl;
@@ -2102,27 +2019,22 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command)
21022019
esp_err_t ret = ESP_OK;
21032020

21042021
HCD_ENTER_CRITICAL();
2105-
// Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid
2106-
if (pipe->cs_flags.reset_lock) {
2107-
ret = ESP_ERR_INVALID_STATE;
2108-
} else {
2109-
pipe->cs_flags.pipe_cmd_processing = 1;
2110-
switch (command) {
2111-
case HCD_PIPE_CMD_HALT: {
2112-
ret = _pipe_cmd_halt(pipe);
2113-
break;
2114-
}
2115-
case HCD_PIPE_CMD_FLUSH: {
2116-
ret = _pipe_cmd_flush(pipe);
2117-
break;
2118-
}
2119-
case HCD_PIPE_CMD_CLEAR: {
2120-
ret = _pipe_cmd_clear(pipe);
2121-
break;
2122-
}
2123-
}
2124-
pipe->cs_flags.pipe_cmd_processing = 0;
2022+
pipe->cs_flags.pipe_cmd_processing = 1;
2023+
switch (command) {
2024+
case HCD_PIPE_CMD_HALT: {
2025+
ret = _pipe_cmd_halt(pipe);
2026+
break;
2027+
}
2028+
case HCD_PIPE_CMD_FLUSH: {
2029+
ret = _pipe_cmd_flush(pipe);
2030+
break;
2031+
}
2032+
case HCD_PIPE_CMD_CLEAR: {
2033+
ret = _pipe_cmd_clear(pipe);
2034+
break;
2035+
}
21252036
}
2037+
pipe->cs_flags.pipe_cmd_processing = 0;
21262038
HCD_EXIT_CRITICAL();
21272039
return ret;
21282040
}
@@ -2673,8 +2585,7 @@ esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb)
26732585
// Check that pipe and port are in the correct state to receive URBs
26742586
HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED // The pipe's port must be in the correct state
26752587
&& pipe->state == HCD_PIPE_STATE_ACTIVE // The pipe must be in the correct state
2676-
&& !pipe->cs_flags.pipe_cmd_processing // Pipe cannot currently be processing a pipe command
2677-
&& !pipe->cs_flags.reset_lock, // Pipe cannot be persisting through a port reset
2588+
&& !pipe->cs_flags.pipe_cmd_processing, // Pipe cannot currently be processing a pipe command
26782589
ESP_ERR_INVALID_STATE);
26792590
// Use the URB's reserved_ptr to store the pipe's
26802591
urb->hcd_ptr = (void *)pipe;

0 commit comments

Comments
 (0)