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

[rp2040] Make writes to SIE_CTRL aware of concurrent access #2024

Merged
merged 1 commit into from Apr 21, 2023

Conversation

jfedor2
Copy link
Contributor

@jfedor2 jfedor2 commented Apr 13, 2023

This fixes #1830

Some context: raspberrypi/pico-feedback#324

This commit makes it so that when setting the START_TRANS bit in the SIE_CTRL register, along with some other bits, we first set all the other bits, then wait some cycles, and then set the START_TRANS bit.

Doing so protects against a situation where the USB controller is reading the register at the same time and gets an incorrect value.

The assembler parts I just copied from _hw_endpoint_buffer_control_update32 where a similar procedure is already followed for the buffer control registers.

@liamfraser
Copy link
Collaborator

I approve this change so please merge if you are happy @hathach

Copy link
Owner

@hathach hathach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for the PR, I have an question whether we could rewrite the asm to do nop instead since that what I would write when wanting to kill a few cycles.

@@ -562,6 +562,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
(ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS) |
(need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
// write everything except the START_TRANS bit first, then wait
usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
__asm volatile ("b 1f\n1: b 1f\n1: b 1f\n1: b 1f\n1: b 1f\n1: b 1f\n1:\n" : : : "memory");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this 6 nop instruction, could we just write it as folows.

__asm volatile("nop; nop; nop; nop; nop; nop;" : : : "memory")

Also It would be nice to add comment why we need this e.g `START_TRANS "seems" to have the same behavior as AVAILABLE bit described in section 4.1.2.5.1 Concurrent access rp2040 datasheet v2.1" etc...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have an opinion on this, I just followed what's already in _hw_endpoint_buffer_control_update32 in rp2040_usb.c. That was written by @kilograham I believe. I don't know if it makes any difference. If you want NOPs tell me if you want 6 or 12 of them as existing code delays for 12 cycles and a single NOP is 1 cycle (I think). This should only make a difference on massively overclocked chips as 3 cycles should be enough at 133MHz.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nop is 1 cycle, b 1f is 2 cyles so they aren't the same (and the b 1f is smaller`)

as of SDK1.3.1 there is a busy_wait_at_least_cycles(cycles) method which could be used instead (i.e. busy_wait_at_least_cycles(12)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @kilograham for explanation, @jfedor2 what do you think, would you mind chaing it to busy_wait_at_least_cycles(12) as suggested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course!

This commit makes it so that when setting the START_TRANS bit in the
SIE_CTRL register, along with some other bits, we first set all the
other bits, then wait some cycles, and then set the START_TRANS bit.

Doing so protects against a situation where the USB controller is
reading the register at the same time and gets an incorrect value.

This mirrors the procedure already applied to buffer control
registers.
Copy link
Owner

@hathach hathach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect, thank you

@hathach hathach merged commit 0871238 into hathach:master Apr 21, 2023
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

tuh_hid_set_report fails after multple calls to change a keyboards LEDs. Number of calls is non determinsitic
4 participants