Re: Tx transfer not triggering corresponding Rx interrupt

From: Farhan Khan <farhan_at_farhan.codes>
Date: Tue, 17 May 2022 06:18:08 UTC
On Monday, May 16, 2022 9:52:14 AM EDT Hans Petter Selasky wrote:
> On 5/15/22 04:41, Farhan Khan wrote:
> > Hi all,
> > 
> > I am trying to understand why a USB Rx interrupt callback is not
> > triggering. I am sending a USB Tx interrupt packet. The immediate next
> > step is that the function will msleep(). The corresponding wakeup()
> > occurs after an Rx interrupt.
> > 
> > There is no explicit usbd_transfer_start() on the Rx interrupt. Elsewhere
> > in the code there is an instance where an Tx interrupt should eventually
> > result in a corresponding Rx interrupt that results in a wakeup(). That
> > does not occurs here and I do not understand why not.
> 
> Hi Farhan,
> 
> OpenBSD and NetBSD it is simply different than in FreeBSD, so you need
> to start all transfers that should receive or transmit data.

I did this. No change in behavior.
 
> > Problem:
> Can you use these terms instead:
> 
> IN packet (from device to host)
> OUT packet (from host to device)
> 
> Else I get confused what direction traffic is flowing.
> 
> RX/TX terms are always relative to the local code.
> 
> IN / OUT is fixed.

Pardon, I will use IN/OUT. But you are correct, I intended Tx and Rx to be 
relative to the host. So Tx means OUT (from Host to device) and Rx means IN 
(from device to host).

> > The msleep() located on line 1314 fails with EWOULDBLOCK.
> > This sleep seems to be the equivalent of the acknowledgement that the Tx
> > interrupt packet was received.
> > 
> > -----------
> > Expected:
> > 
> > I expect this to somehow result in the Rx interrupt, which runs the
> > corresponding handler athn_usb_intr(). This function contains the wakeup()
> > line on line 2556 (the AR_HTC_MSG_CONN_SVC case).
> > 
> > -----------
> > This happens elsewhere:
> > 
> > In athn_usb_load_firmware(), line 1011, there is a usbd_do_request(),
> > followed by an msleep(). The wait_msg_id is AR_HTC_MSG_READY. The wakeup
> > for this occurs only after an Rx interrupt is called on line 2538.
> > 
> > -----------
> > Question rephrased:
> > 
> > Why is a USB transfer resulting in an Rx interrupt in one place, even
> > though a usbd_transfer_start() is not called on the Rx interrupt, but not
> > for athn_usb_htc_connect_svc()/athn_usb_htc_msg()?
> > 
> > How do I make this Tx transfer result in an Rx interrupt without having to
> > manually call usbd_transfer_start() (OpenBSD does not appear to do this?)
> 
> Because the USB stack is not the same! You need to study FreeBSD's USB
> stack a bit more and you'll figure out.

I have been reading example code and documentation for weeks now. This 
behavior is not documented anywhere.

> > I do not understand the differences between usbd_do_request,
> > usb_transfer_start and usbd_setup_xfer/usbd_transfer that might be
> > resulting in different behavior, so any light on that would also help.
> 
> usbd_do_request() is only for synchronous transfers on endpoint zero,
> the control endpoint. It is a handy function to avoid allocating and
> freeing USB transfers over and over again.

Does this also result in automatic Rx/IN interrupt callbacks? If not, why is 
this happening?

> 
> Function names might be similar, but the behaviour is very different!
> 
> > -----------
> > Been stuck for some time, so any assistance is appreciated.
> > Thank you!
> :
> :-)
> 
> --HPS


Do you have office hours during which we can speak? Perhaps IRC? I have asked 
this question a few times and I'm not getting it sufficiently answered. I 
suspect it is due to us getting lost in the details rather than focusing on 
the question. I apologize, my emails have been very verbose and perhaps 
unfocused.

I'll try to keep this simple:

In my driver I call usbd_do_transfer() followed by a msleep() **WITHOUT** 
calling usbd_transfer_start on the Rx/IN interrupt. The Rx/IN interrupt is 
necessary to run the associated wakeup(). This suggests the Rx/IN callback is 
happening, yet I see the callback for the Rx/IN interrupt happening. This is 
what I want to occur, but why is this happening **WITHOUT** being called?

Similarly, is there a way to have an Rx/IN interrupt trigger after receiving a 
USB packet **WITHOUT** manually calling usbd_transfer_start() the way it is 
done with usbd_transfer_start()? The `interval` parameter, which seems like it 
should execute the callback on a regular interval, does not do anything at 
all.

If I can get this question explained, I can hopefully make progress. 
Otherwise, I'm stuck and this seems like undocumented or inconsistent 
behavior.

Failed strategies so far:
* Manually calling the Rx/IN interrupt, changing msleep time to 10 seconds - 
Rx/IN callback happening late for some reason. And this just seems wrong.
* Calling Rx/IN from within the Tx/OUT callback - Not possible due to mutex.

Just to confirm, the device is sending the host an Rx/IN packet, I confirmed 
this with wireshark.

Very stuck and confused :(
- Farhan