Re: Tx transfer not triggering corresponding Rx interrupt
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