git: kernel - Hack fixes for EHCI issues in U4B

Matthew Dillon dillon at
Wed Jan 8 15:43:25 PST 2014

commit ccb00b061096e6e171caac3b88267135ed3d7f1e
Author: Matthew Dillon <dillon at>
Date:   Wed Jan 8 15:31:00 2014 -0800

    kernel - Hack fixes for EHCI issues in U4B
    * These changes fix several issues with the U4B EHCI.  Insertion and Removal
      events through hubs no longer crash the controller and/or the machine.
      And heavy bulk traffic no longer crashes the controller or has weird
      failures.  Probing works more reliably as well.
    * The main problem is the U4B design for QH/TD descriptors.  It allocates
      and frees them with the xfer.  For the EHCI controller it rips out the
      QH's from the chain and doesn't do the right interactions with the
      controller to ensure that the controller is not still iterating through
      the chain.
      It is possible for the controller to wind up iterating through a long
      chain of removed (finished or timed-out) QH's.  If any of them are
      kfree()'d or free/reallocated/reused before their time, BOOM!  The
      controller can chain right through into random memory and blow up.
    * The first hack is to delay kfree()ing the xfer rollup buffer.  I just
      threw in a 256-slot delay.  I'm not even doing it right (it isn't time-based
      or doorbell-based).  Note that linux uses the doorbell-based method,
      where the structures are left intact until the next doorbell interrupt.
    * The second hack is to issue doorbells (EHCI_CMD_IAAD) after every new
      transfer is queued and after each transfer is removed.  The doorbell is
      PARTICULARLY important after a removal, because the controller can
      wind up sitting on a removed QH indefinitely otherwise.
      Removed chains can cause the controller to miss newly added chains, thus
      the doorbell is needed for that reason as well.
      Also reorder the cpu flushes a little when coding the above.
    * Add numerous new structural fields and assertions to ensure that the
      EHCI code doesn't try to remove requests from HW that were never queued
      to HW.  The U4B API's are *VERY* loose in this regard so I added a
      double check.
    * DragonFly: The ugen*.* devices need a dev d_open and d_close routine.
      Our default d_open/d_close is not the same as FreeBSD's.
    * Fix a major bug in usb_open() where the 'cpd' structure can get lost
      if multiple open()'s occur on the same ugen device.
      Allow multiple opens as long as the permissions are the same.  This
      is really a hack to fix an issue where 'usbconfig list' opens ugen0.1
      twice (i.e. has two open descriptors on the same device).
      Also properly NULL-out dev->si_drv2 on (last) close.
    * Replace two cv_signal/cv_wait calls with wakeup/lksleep, and place a
      timeout on the lksleep loop because the two places in question have
      a SMP race which the locks don't handle.  Basically the callback is
      made BEFORE all the conditions potentially preventing an xfer from
      being flagged as completed are met, so the cv_signal() was waking up
      the waiter potentially before its time (and the lock is not held through
      the whole thing so it doesn't interlock the race).
    * In usbd_req_get_desc() reload the req fresh on each loop.
    * In usbd_req_get_desc() increase the timeout from 0.5 seconds to 1 second.

Summary of changes:
 sys/bus/u4b/controller/ehci.c | 176 ++++++++++++++++++++++++++++++++----------
 sys/bus/u4b/usb_bus.h         |   1 +
 sys/bus/u4b/usb_core.h        |   1 +
 sys/bus/u4b/usb_dev.c         |  36 ++++++++-
 sys/bus/u4b/usb_request.c     |  20 ++---
 sys/bus/u4b/usb_transfer.c    |  77 +++++++++++++++---
 6 files changed, 246 insertions(+), 65 deletions(-)

DragonFly BSD source repository

More information about the Commits mailing list