On 21-08-10 15:02:28, Jeaho Hwang wrote: > hw_ep_prime sometimes fails if irq occurs while it rus on RT kernel. > to prevent local_irq_save should keep the function from irqs. > > I am not sure where is the best to submit this patch, between RT and USB > community so sending to both. thanks. Greg, do you have any suggestions about it, the RT kernel schedules the interrupt handler (top-half) out which causes the USB hardware atomic sequences are broken, these hardware operations needs to be executed within limited time. Peter > > Signed-off-by: Jeaho Hwang <jhhwang@xxxxxxxxxx> > --- > drivers/usb/chipidea/udc.c | 31 +++++++++++++++++++++++++------ > 1 file changed, 25 insertions(+), 6 deletions(-) > > diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c > index 5f35cdd2cf1d..a90498f17cc4 100644 > --- a/drivers/usb/chipidea/udc.c > +++ b/drivers/usb/chipidea/udc.c > @@ -102,6 +102,9 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) > { > int n = hw_ep_bit(num, dir); > > + /* From zynq-7000 TRM, It can take a long time > + * so irq disable is not a good option for RT > + */ > do { > /* flush any pending transfer */ > hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n)); > @@ -190,22 +193,32 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir) > static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) > { > int n = hw_ep_bit(num, dir); > + unsigned long flags; > + int ret = 0; > > /* Synchronize before ep prime */ > wmb(); > > - if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) > - return -EAGAIN; > + /* irq affects this routine so irq should be disabled on RT. > + * on standard kernel, irq is already disabled by callers. > + */ > + local_irq_save(flags); > + if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) { > + ret = -EAGAIN; > + goto out; > + } > > hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n)); > > while (hw_read(ci, OP_ENDPTPRIME, BIT(n))) > cpu_relax(); > if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) > - return -EAGAIN; > + ret = -EAGAIN; > > +out: > + local_irq_restore(flags); > /* status shoult be tested according with manual but it doesn't work */ > - return 0; > + return ret; > } > > /** > -- > 2.25.1 > -- Thanks, Peter Chen