Re: [RFC 10/22] usb: Make core allocate resources per PCI-device.

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

 



On Fri, Dec 31, 2010 at 12:38:37PM -0500, Alan Stern wrote:
> On Thu, 30 Dec 2010, Sarah Sharp wrote:
> 
> > Introduce the notion of a PCI device that may be associated with more than
> > one USB host controller driver (struct usb_hcd).  This patch is the start
> > of the work to separate the xHCI host controller into two roothubs: a USB
> > 3.0 roothub with SuperSpeed-only ports, and a USB 2.0 roothub with
> > HS/FS/LS ports.
> > 
> > One usb_hcd structure is designated to be the "primary HCD", and a pointer
> > is added to the usb_hcd structure to keep track of that.  A new function
> > call, usb_hcd_is_primary_hcd() is added to check whether the USB hcd is
> > marked as the primary HCD (or if it is not part of a roothub pair).  To
> > allow the USB core and xHCI driver to access either roothub in a pair, a
> > "shared_hcd" pointer is added to the usb_hcd structure.
> 
> I'm not sure this "shared_hcd" pointer is needed.  Does it ever get 
> used in a non-trivial way?

I'm not sure what you mean by "non-trivial".  The USB core needs it, for
instance, to make sure that both buses are suspended before suspending
the PCI device:

        if (hcd->driver->pci_suspend) {
                /* Optimization: Don't suspend if a root-hub wakeup is
                 * pending and it would cause the HCD to wake up anyway.
                 */
                if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
                        return -EBUSY;
                if (do_wakeup && hcd->shared_hcd &&
                                HCD_WAKEUP_PENDING(hcd->shared_hcd))
                        return -EBUSY;
                retval = hcd->driver->pci_suspend(hcd, do_wakeup);

Since there's only one usb_hcd stored in the PCI device pointer, there
needs to be a way to access the second usb_hcd.  Other functions also
need to use shared_hcd to set various flags that are part of the usb_hcd
state.  Do you have a different suggestion as to how to do that?

> > Add a new function, usb_create_shared_hcd(), that does roothub allocation
> > for paired roothubs.  It will act just like usb_create_hcd() did if the
> > primary_hcd pointer argument is NULL.  If it is passed a non-NULL
> > primary_hcd pointer, it sets usb_hcd->shared_hcd and usb_hcd->primary_hcd
> > fields.  It will also skip the bandwidth_mutex allocation, and set the
> > secondary hcd's bandwidth_mutex pointer to the primary HCD's mutex.
> > 
> > IRQs are only allocated once for the primary roothub.
> > 
> > Introduce a new usb_hcd driver flag that indicates the host controller
> > driver wants to create two roothubs.  If the HCD_SHARED flag is set, then
> > the USB core PCI probe methods will allocate a second roothub, and make
> > sure that second roothub gets freed during rmmod and in initialization
> > error paths.
> 
> This doesn't seem like the right approach.  The creation of a secondary 
> usb_hcd should be handled by the driver that needs it; it isn't such a 
> common activity that we need to implement it in the USB core.  In 
> particular, hcd-pci.c shouldn't be changed.

I have thought about your suggestion to make the xHCI driver call
usb_create_shared_hcd() instead of having the USB PCI layer do the
allocation and registering of the second roothub.  However, I wanted to
ensure that the shared_hcd pointer was set before the first usb_hcd was
registered, and I don't think I can do that if I push the call into the
xHCI driver.

I need to set the shared_hcd pointer before the first usb_hcd is
registered so that, for example, the PCI device wouldn't get suspended
until the initialization process completed for both roothubs and both
buses are suspended.  Things like flags also need to get set for both
host controllers, and I want to make sure the shared_hcd pointer is set
before the bus is used by the USB core at all.

I could potentially allocate the shared HCD in one of the xHCI
initialization routines, before usb_add_hcd() has a chance to call
register_root_hub().  But I'm not sure how the USB core will react to
being called recursively, i.e. usb_register_bus() calls xhci_run() which
calls usb_alloc_shared_hcd() and usb_register_bus().  And what if
someone decides to add a new lock to the USB core functions later?  If
they don't have an xHCI device to test with, then they may not notice
some obscure code in the xHCI driver that calls the functions
recursively.

I agree that it's code that's not likely to be used by any other host
controller, but I think this code needs to be visible in the USB core.

> > If the driver that wants to create two roothubs is an xHCI driver, the
> > roothub that is allocated last is marked as the USB 2.0 roothub.
> 
> Didn't we agree earlier that xhci-hcd needs to register its USB-2 root 
> hub first?

Yes, you're right, that suggestion got lost in the mass of other changes
I had to make since then.  But now that there's a usb_hcd->bcdUSB flag
(or usb_hcd->version, once I rename it), it should be trivial to fix.

> 
> > diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> > index 79bad2c..a061c31 100644
> > --- a/drivers/usb/core/hcd.c
> > +++ b/drivers/usb/core/hcd.c
> 
> > @@ -2184,13 +2195,49 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
> >  			"USB Host Controller";
> >  	return hcd;
> >  }
> > +EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
> > +
> > +/**
> > + * usb_create_hcd - create and initialize an HCD structure
> > + * @driver: HC driver that will use this hcd
> > + * @dev: device for this HC, stored in hcd->self.controller
> > + * @bus_name: value to store in hcd->self.bus_name
> > + * @shared_hcd: a pointer to the usb_hcd structure that is sharing the
> > + *              PCI device.  Used for allocating two usb_hcd structures
> > + *              under one xHCI host controller PCI device (a USB 2.0 bus
> > + *              and a USB 3.0 bus).
> 
> This last argument doesn't really exist, as you can see below.

You're correct, that's leftover from the previous patchset.  I'll remove it.

> 
> > + * Context: !in_interrupt()
> > + *
> > + * Allocate a struct usb_hcd, with extra space at the end for the
> > + * HC driver's private data.  Initialize the generic members of the
> > + * hcd structure.
> > + *
> > + * If memory is unavailable, returns NULL.
> > + */
> > +struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
> > +		struct device *dev, const char *bus_name)
> > +{
> > +	return usb_create_shared_hcd(driver, dev, bus_name, NULL);
> > +}
> >  EXPORT_SYMBOL_GPL(usb_create_hcd);
> 
> > @@ -2209,6 +2256,14 @@ void usb_put_hcd (struct usb_hcd *hcd)
> >  }
> >  EXPORT_SYMBOL_GPL(usb_put_hcd);
> >  
> > +inline int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
> > +{
> > +	if (!hcd->primary_hcd)
> > +		return 1;
> > +	return hcd == hcd->primary_hcd;
> 
> Do you really need to set hcd->primary_hcd to point to hcd itself?  My 
> inclination would be to leave it unset.

I do use it in the xHCI driver initialization code, to ensure I'm only
starting the host controller when the second (i.e. non-primary) host
controller is registered.  I would have to see if I can just test for
NULL instead, but I feel that it's more symmetrical somehow to set
primary_hcd for both HCDs.

Sarah Sharp
--
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