Re: Tx transfer not triggering corresponding Rx interrupt

From: Hans Petter Selasky <hps_at_selasky.org>
Date: Mon, 16 May 2022 13:52:14 UTC
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.

> -----------
> Background:
> 
> I am working on porting OpenBSD's athn(9) driver to FreeBSD. I loaded the
> firmware and I believe this is confirmed by sending a AR_HTC_MSG_READY
> message, which is https://github.com/khanzf/freebsd/blob/
> 0ba9a9b92df496847058008598139e92f5e60850/sys/dev/athn/usb/if_athn_usb.c#L1009.
> There is an associated msleep() and wakeup() that suggest the firmware was
> successfully loaded. The wakeup occurs in the Rx interrupt handler.
> 
> Then, there is a section where the driver sets up the Host Transport
> Communication (HTC) interface. The driver does a transfer of data of the Tx
> Interrupt, then immediately runs msleep(). The corresponding wakeup occurs
> when an Rx (not Tx) interrupt triggers and is processed.
> 
> The code for this is located in athn_usb_htc_connect_svc().
> My current implementation is here: https://github.com/khanzf/freebsd/blob/
> 0ba9a9b92df496847058008598139e92f5e60850/sys/dev/athn/usb/if_athn_usb.c#L1293
> 
> The OpenBSD implementation is here: https://github.com/openbsd/src/blob/
> 72a0854b669a0194895eeac5ffcdf5fc27bf2a30/sys/dev/usb/if_athn_usb.c#L809
> 
> Please note that in the OpenBSD implementation, the athn_usb_htc_msg()
> function calls usbd_setup_xfer/usbd_transfer, whereas my implementation calls
> usbd_transfer_start().
> 
> Also, OpenBSD opens the Rx Interrupt pipe with usbd_open_pipe_intr(), which
> gives the option for an interval. I suspect this is the same as the `interval`
> parameter in usb_config. I do not know if this is significant.

The usb_config structure allows you to override the default value which 
is taken from the bInterval field in the USB endpoint descriptor.

> 
> -----------
> 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.

> 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 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.

Function names might be similar, but the behaviour is very different!

> -----------
> Been stuck for some time, so any assistance is appreciated.
> Thank you!
> 

:-)

--HPS