mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
fix(uhci): fix uhci cache issue on ESP32-P4
This commit is contained in:
@@ -111,6 +111,7 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
|
||||
bool need_yield = false;
|
||||
uhci_controller_handle_t uhci_ctrl = (uhci_controller_handle_t) user_data;
|
||||
bool is_buf_from_psram = esp_ptr_external_ram(uhci_ctrl->rx_dir.buffer_pointers[uhci_ctrl->rx_dir.node_index]);
|
||||
size_t cache_line = uhci_ctrl->rx_dir.cache_line;
|
||||
// If the data is not all received, handle it in not normal_eof block. Otherwise, in eof block.
|
||||
if (!event_data->flags.normal_eof) {
|
||||
size_t rx_size = uhci_ctrl->rx_dir.buffer_size_per_desc_node[uhci_ctrl->rx_dir.node_index];
|
||||
@@ -123,6 +124,15 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
|
||||
if (is_buf_from_psram) {
|
||||
esp_psram_mspi_mb();
|
||||
}
|
||||
// DMA just finished writing the node's buffer. Because the descriptor link is circular,
|
||||
// the same buffer region gets overwritten on every loop. On targets where the buffer is
|
||||
// backed by a cache, the cache is not snooped by DMA, so the CPU must invalidate the range
|
||||
// before reading, otherwise it will return stale data from a previous loop.
|
||||
if (cache_line > 0) {
|
||||
// The per-node buffer base is aligned to cache_line (see uhci_receive), and rx_size here
|
||||
// equals buffer_size_per_desc_node[] which is also a multiple of cache_line.
|
||||
esp_cache_msync(evt_data.data, rx_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
}
|
||||
if (uhci_ctrl->rx_dir.on_rx_trans_event) {
|
||||
need_yield |= uhci_ctrl->rx_dir.on_rx_trans_event(uhci_ctrl, &evt_data, uhci_ctrl->user_data);
|
||||
}
|
||||
@@ -150,6 +160,15 @@ static bool uhci_gdma_rx_callback_done(gdma_channel_handle_t dma_chan, gdma_even
|
||||
esp_pm_lock_release(uhci_ctrl->pm_lock);
|
||||
}
|
||||
#endif
|
||||
// Same reasoning as the partial branch. rx_size here may not be a multiple of cache_line
|
||||
// because transfer can end mid-buffer on a UART idle EOF, so round up to the next cache
|
||||
// line (esp_cache_msync's M2C direction requires aligned size and doesn't accept the
|
||||
// UNALIGNED flag). The extra bytes still belong to the user buffer so invalidating them
|
||||
// is harmless.
|
||||
if (cache_line > 0) {
|
||||
size_t sync_size = (rx_size + cache_line - 1) & ~(cache_line - 1);
|
||||
esp_cache_msync(evt_data.data, sync_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||
}
|
||||
if (uhci_ctrl->rx_dir.on_rx_trans_event) {
|
||||
need_yield |= uhci_ctrl->rx_dir.on_rx_trans_event(uhci_ctrl, &evt_data, uhci_ctrl->user_data);
|
||||
}
|
||||
@@ -313,13 +332,13 @@ esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer,
|
||||
|
||||
size_t node_count = uhci_ctrl->rx_dir.rx_num_dma_nodes;
|
||||
|
||||
// Initialize the mount configurations for each DMA node, making sure every no
|
||||
// Initialize the mount configurations for each DMA node, making sure every node is properly aligned.
|
||||
size_t usable_size = (max_alignment_needed == 0) ? buffer_size : (buffer_size / max_alignment_needed) * max_alignment_needed;
|
||||
size_t base_size = (max_alignment_needed == 0) ? usable_size / node_count : (usable_size / node_count / max_alignment_needed) * max_alignment_needed;
|
||||
size_t remaining_size = usable_size - (base_size * node_count);
|
||||
|
||||
gdma_buffer_mount_config_t mount_configs[node_count];
|
||||
memset(mount_configs, 0, node_count);
|
||||
memset(mount_configs, 0, node_count * sizeof(gdma_buffer_mount_config_t));
|
||||
|
||||
for (size_t i = 0; i < node_count; i++) {
|
||||
uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] = base_size;
|
||||
|
||||
Reference in New Issue
Block a user