grub-devel
[Top][All Lists]
Advanced

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

Re: EHCI driver


From: Christer Weinigel
Subject: Re: EHCI driver
Date: Wed, 30 May 2012 11:28:00 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20120430 Thunderbird/12.0.1

On 2012-05-30 00:46, Aleš Nesrsta wrote:

>> the EHCI driver in GRUB has some known problems with low-speed transfers
>> and split transactions [1].  On older machines this is not a big problem
>> since it's possible to connect low speed devices such a USB keyboard
>> directly to a port and use the UHCI driver instead.  But modern Intel
>> chipsets do not have a UHCI companion controller any more, they only
>> have a EHCI controller with a normal USB 2.0 rate matching hub
>> permanently connected to the EHCI port inside the chipset.


> In fact there could be probably only two reasons of the problem:

> - my mistake in split transfer configuration (I checked it but who
> knows...)
> - GRUB "simulation" of interrupt transfer via bulk transfers is not
> working when it is used via EHCI split transfers

>

> From my point of view it is little bit more probable the second reason.
> In this case the solution could be real implementation of interrupt
> transfers in GRUB - at least for EHCI. It may be possible even though
> GRUB is not supporting CPU interrupts but currently I have no idea/time
> to think about.


Right.  I put a USB bus analyzer on the bus and it turns out that when a
queue head  where the Endpoint Speed field is set to 01b (indicating a
_low speed_ split transaction) is put on the asynchronous schedule, what
actually comes out on the wire is a split packet saying that it is a
_full speed_ bulk transfer. So the hub sees a full speed transfer for a
low speed port (or doesn't get any intelligible response) and returns a
stall condition.

This is all according to the standards I guess since bulk transfers are
not allowed for low speed.  GRUB is wrong in asking for such a transfer
and the behavior when it does is undefined.  It's a bit surprising
though, Intel engineers must have made an extra effort to disallow low
speed bulk transfers in the EHCI controller instead of just doing what
the user asks the controller to do.

I've done a quick hack to test this, basically changed grub_ehci_find_qh
like this:

if (transfer->dev->speed == GRUB_USB_SPEED_LOW
    && transfer->type != GRUB_USB_TRANSACTION_TYPE_CONTROL)
{
    // special case to link the QH to e->qh_virt[0]
    // which is the periodic schedule
    // also set the s-mask and c-mask for interrupt transfers
}
else
{
    // the normal code to link the QH to e->qh_virt[1]
    // which is the asynchronous schedule
}

This of course crashes after a while since the queues get mixed up but
it does allow me to talk to a USB keyboard connected to a USB 2.0 hub,
and the split packets seen on the wire now correctly say that they are
interrupt transfers to a low speed device.  So it looks like GRUBs
misuse of bulk transfers instead of proper interrupt transfers is the
root cause.

> If the reason is only my mistake in EHCI code then the solution is very
> simple - find the bug and correct it... :-)

I did find one fairly obvious bug, the High-Bandwidth Pipe Multiplier
(Mult) field of endpoint characteristics have the wrong defines:

  GRUB_EHCI_MULT_ONE = (0 << 30),
  GRUB_EHCI_MULT_TWO = (0 << 30),
  GRUB_EHCI_MULT_THREE = (0 << 30),

They should be 1, 2 and 3 instead.  The EHCI specification says "A zero
in this field yields undefined results."  But it doesn't seem to make
any difference though.

> If You have time and related knowledges or You know somebody like that,
> You are welcome to help us - at least to find the reason of the problem
> or check the EHCI split transfer code or invent implemention of
> interrupt transfers in EHCI GRUB driver etc...


Done. :-)

Now I just have to fix up the queue management so that it properly keeps
track of QHs for two queues instead of one. And figure out if there are
any other problems.

  /Christer



reply via email to

[Prev in Thread] Current Thread [Next in Thread]