Re: Unlinking URBs before suspending USB

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Can you give any examples?  I haven't heard of this sort of problem
> before.

Yes, we implemented a USB driver which uses one BULK endpoint for OUT
transfer and one for IN transfer.
On the host side we have full control on the OUT transfers, but the
host doesn't know when the peripheral has data the send, so an IN
transfer is always pending, and once one IN transfer is completed,
another IN URB is submitted again right away.
We also implemented a power management scheme, where a 500ms timer is
started on each URB completion. So if there is any URB completion
within this 500ms, the timer would be restarted, otherwise the driver
calls usb_autopm_put_interface to suspend the bus when the timer
expires.

At the time the driver calls usb_autopm_put_interface, the pending IN
transfer is currently not terminated by the driver itself, so the
pending IN URB wouldn't be given back to the driver until
usb_hcd_flush_endpoint. This has been working fine except one problem
where an IN transfer gets split into two parts because sometimes
usb_autopm_put_interface is called right in the middle of an IN
transfer. Let's say this IN transfer has 5000 bytes data, at the time
the driver calls usb_autopm_put_interface the host has received 2
packets or 1024 bytes, the EHCI would guarantee the transfer to be
stopped at 512 bytes boundary, but the SUSPEND would still eventually
take effect so that the rest 3976 bytes could only be finished after
bus RESUME. This is OK as I implemented a mechanism to check for
partial transfer on bus SUSPEND, and buffer the data until the rest of
the transfer is received after bus RESUME.

Now if I do terminate the pending IN URB before calling
usb_autopm_put_interface, the same situation would still occur as the
driver doesn't really know if it's in the middle of an IN transfer or
not. However, comparing to the implementation mentioned above, I did
notice some difference. usb_kill_urb sometimes gives back the URB with
urb->actual_length equals to a number that is not integer multiple of
512, this has never happened if the URB is terminated only by
usb_hcd_flush_endpoint. So I'm confused if we really need to
1. call usb_kill_urb before calling usb_autopm_put_interface?
2. if yes to 1, why sometimes the actual_length is not multiple of
512, and how should we handle it.


Fei


On Fri, Feb 19, 2010 at 9:14 AM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> On Thu, 18 Feb 2010, FEI YANG wrote:
>
>> I have seen a discussion about unlinking URBs before suspending the
>> bus posted at
>>         http://marc.info/?l=linux-usb&m=126296327514946&w=2
>> I think I have a few more questions about this and would like to seek
>> for your opinion.
>>
>> 1. Is it really necessary to unlink pending URBs in driver's suspend
>> method? My observation is that once usb_autopm_put_interface is
>> called, the pending URB will eventually be cleaned up in function
>> usb_hcd_flush_endpoint.
>>         usb_autopm_put_interface -> usb_autopm_do_interface ->
>> usb_suspend_both ->usb_hcd_flush_endpoint
>
> That's true, and unlinking URBs in the suspend method isn't really
> necessary.  It is a good idea, however, because it means that the URBs
> will be cancelled at a time when the driver knows it is safe to do so.
> It also means that the driver won't see any URBs completing after the
> suspend method has returned.
>
>> 2. When the host decides to suspend the bus, in case there is a
>> pending IN URB, the driver doesn't really know if the IN URB is in the
>> middle of DATA transfer stage or the peripheral is NAK'ing the IN
>> token, the SUSPEND can potentially interrupt an ongoing transfer.
>
> This can't happen.  The host won't suspend the bus unless the drivers
> for all the devices on the bus have already been suspended, which means
> all the endpoint queues have been flushed and there are no pending
> URBs.
>
> But let's suppose for the moment that it can happen.
>
>> According to the EHCI spec, the hardware guarantees the current
>> transaction (512 bytes packet for high speed)
>
> For high-speed BULK.  Other types of transfer have different maxpacket
> sizes.
>
>>  to be finished before
>> the SUSPEND taking effect, this would result in an interrupted
>> transfer with the first half being an integer multiple of 512 bytes
>> and the second half being finished only after bus RESUME. I have
>> implement some code in my driver to put these two part together to
>> recover the interrupted transfer. However, if I do usb_kill_urb in the
>> suspend method of the driver, sometimes the URB would be given back
>> with actual_length equals to a number that is not integer multiple of
>> 512 (such as 33 or 66), this broke the mechanism I implemented to
>> re-assemble the interrupted transfer.
>
> That should not happen, unless the transfer was a short packet.
>
>> I don't know if that
>> actual_length is really the bytes received (it doesn't look like there
>> is expected data in the buffer) and how should I handle this kind of
>> returning URB. Do you know how such a urb->actual_length could happen?
>> Is it an artifact of usb_kill_urb?
>
> No.  If the packets aren't short then actual_length should always be a
> multiple of the maxpacket value.  If it isn't then something is wrong
> somewhere.  This holds even if usb_kill_urb() or usb_unlink_urb() is
> called.
>
> Alan Stern
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux