Re: USB power accounting at root hub level

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

 



On Tue, 26 Jul 2011, Thomas Petazzoni wrote:

> Hello,
> 
> Thanks again for the quick feedback.

There has been a lot of chatter on this thread, but I'm going to ignore 
most of it and try to cover the key points here.

> Le Mon, 25 Jul 2011 15:08:53 -0400 (EDT),
> Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> a écrit :
> 
> > > I would have expected udev->bus_mA to be 75 mA for the second device,
> > > so that the 100 mA configuration gets rejected.
> > 
> > No.  The USB stack doesn't enforce any scheme for dividing up power 
> > among a hub's children.  All it does is log a warning if the devices 
> > want more power than the total available.
> 
> Ok. This is also what I understood.

This is an important point.  We do not try to prevent people from
installing configurations that would violate a power budget.  This
would often be wrong because a high percentage of descriptors contain
errors -- especially in fields like bMaxPower that don't get examined
very closely by Windows.

It also would annoy people because devices often work well even when
they would appear to violate the power budget -- the bMaxPower value is
only an upper limit and most devices usually use less than that value.  
If the kernel did enforce the budget strictly, people would see devices
which used to work correctly suddenly stop working for no good reason.  
This actually happened at one point in the past.  See this comment in
generic.c:

	/*
	 * HP's USB bus-powered keyboard has only one configuration
	 * and it claims to be self-powered; other devices may have
	 * similar errors in their descriptors.  If the next test
	 * were allowed to execute, such configurations would always
	 * be rejected and the devices would not work as expected.
	 * In the meantime, we run the risk of selecting a config
	 * that requires external power at a time when that power
	 * isn't available.  It seems to be the lesser of two evils.
	 *

> > > However, looking at
> > > http://lxr.free-electrons.com/source/drivers/usb/core/hub.c#L1147, it
> > > appears that the hub->mA_per_port field is defined to hdev->bus_mA
> > > (i.e, the power budget). So it means that when we define a power budget
> > > of 175 mA, the USB core understands that it is 175 mA per port that is
> > > available, and not 175 mA globally for all ports of the root hub. I
> > > suspect this explains the behavior I'm seeing.
> > > 
> > > Unfortunately, this contradicts the computation done in
> > > hub_power_remaining() at
> > > http://lxr.free-electrons.com/source/drivers/usb/core/hub.c#L3014,
> > > which rightfully concludes that 25mA is missing. And this also seems to
> > > make it difficult to define a global root hub power limit.
> > 
> > There's no contradiction.  If 175 mA total are available, then one way
> > to apportion it is to plug in a single device requiring 175 mA.  In
> > other words, there really is up to 175 mA available for each port.
> 
> Hum, I'm sorry, but I still see a contradiction :
> 
>  * On one side, there is a computation that assumes that hdev->bus_mA
>    is a *per-port* current limit (and this computation is used to
>    reject new USB configurations from connecting) ;

No, you have misinterpreted the code.  hdev->bus_mA is the total
current supplied by the bus to the hub.  No device plugged into any
port should draw more current than that, obviously.

Furthermore, although that computation does reject new USB
configurations, it does _not_ prevent them from connecting.  All that
computation does is prevent a violating config from being installed by
default.  Indeed, if you want to use a config that violates the power
budget, it's easy to do so.  Plug the device in, then write to
/sys/bus/usb/devices/.../bConfigurationValue.

>  * On another side, there is a computation that assumes that
>    hdev->bus_mA is a *global hub* current limit (and this computation
>    is used to print a warning in the kernel messages).

Both computations make this assumption.

> If I set a global current limit of 175 mA, then two devices of 100 mA
> shouldn't be allowed to connect.

No.  They _must_ be allowed to connect, because we cannot trust the 
bMaxPower values in the config descriptors.

In addition, how can we know to prevent these devices from connecting?  
We don't know how much power a device requires until we have read its
config descriptors, and we can't do that if the device isn't allowed to
connect!

Indeed, how can we prevent a device from connecting at all?  We can't
physically prevent it -- we can't fill the USB ports with SuperGlue!  
On most desktop systems and most hubs, we can't even power-down the
ports.

> > > Isn't there a contradiction here ? Shouldn't the hdev->bus_mA be
> > > understood as a global hub power budget, and not a per-port power
> > > budget ?
> > 
> > That _is_ how it is interpreted.
> 
> Well, I don't think so, since by the example above, we have seen that
> two 100 mA devices (which accounts for 200 mA of power) can connect to
> a hub limited to 175 mA.

Yes.  To repeat, these values guide the selection of default configs 
and cause the kernel to log warning messages.  They do _not_ prevent 
users from violating power budgets.

> > It looks like your real problem is in hcd.c line 2467 (in 
> > usb_add_hcd()):
> > 
> > 	rhdev->bus_mA = min(500u, hcd->power_budget);
> > 
> > We probably shouldn't use the min() operation here, just set
> > rhdev->bus_mA to hcd->power_budget.  However, I'm not sure how the
> > various host controller drivers set the power_budget field; some of
> > them may set it to the total power divided by the number of ports
> > rather than the total power.  If they do, they will have to be fixed
> > when this change is made.
> 
> This precise instruction is a fairly clear indication that the
> rhdev->bus_mA value is a per-port limit and not a global hub limit.
> Otherwise, there wouldn't have been this maximum value of 500mA.
> 
> Am I missing something ?

Yes -- you are missing the fact that this line of code is wrong.  :-)
Change it to remove the min() function and you will see that 
rhdev->bus_mA is a global hub limit, just as hdev->bus_mA is for 
non-root hubs.

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