usbehci: import changes from sources (portreset, port handover handling), set interrupt threshold to 1 uframe
parent
c4535df0c4
commit
f0facb2ed8
|
@ -15,6 +15,7 @@
|
||||||
#include "usbehci.h"
|
#include "usbehci.h"
|
||||||
|
|
||||||
static Ctlr* ctlrs[Nhcis];
|
static Ctlr* ctlrs[Nhcis];
|
||||||
|
static int maxehci = Nhcis;
|
||||||
|
|
||||||
/* Isn't this cap list search in a helper function? */
|
/* Isn't this cap list search in a helper function? */
|
||||||
static void
|
static void
|
||||||
|
@ -89,9 +90,7 @@ ehcireset(Ctlr *ctlr)
|
||||||
if(i == 100)
|
if(i == 100)
|
||||||
print("ehci %#p controller reset timed out\n", ctlr->capio);
|
print("ehci %#p controller reset timed out\n", ctlr->capio);
|
||||||
}
|
}
|
||||||
|
opio->cmd |= Citc1; /* 1 intr. per µframe */
|
||||||
/* requesting more interrupts per µframe may miss interrupts */
|
|
||||||
opio->cmd |= Citc8; /* 1 intr. per ms */
|
|
||||||
coherence();
|
coherence();
|
||||||
switch(opio->cmd & Cflsmask){
|
switch(opio->cmd & Cflsmask){
|
||||||
case Cfls1024:
|
case Cfls1024:
|
||||||
|
@ -202,11 +201,10 @@ scanpci(void)
|
||||||
* currently, if we enable a second ehci controller,
|
* currently, if we enable a second ehci controller,
|
||||||
* we'll wedge solid after iunlock in init for the second one.
|
* we'll wedge solid after iunlock in init for the second one.
|
||||||
*/
|
*/
|
||||||
if (i > 0) {
|
if (i >= maxehci) {
|
||||||
// iprint("usbehci: ignoring controllers after the first, "
|
iprint("usbehci: ignoring controllers after first %d, "
|
||||||
// "at %#p\n", io);
|
"at %#p\n", maxehci, io);
|
||||||
// ctlrs[i] = nil;
|
ctlrs[i] = nil;
|
||||||
iprint("usbehci: multiple controllers present\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,12 +213,16 @@ static int
|
||||||
reset(Hci *hp)
|
reset(Hci *hp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
char *s;
|
||||||
Ctlr *ctlr;
|
Ctlr *ctlr;
|
||||||
Ecapio *capio;
|
Ecapio *capio;
|
||||||
Pcidev *p;
|
Pcidev *p;
|
||||||
static Lock resetlck;
|
static Lock resetlck;
|
||||||
|
|
||||||
if(getconf("*nousbehci"))
|
s = getconf("*maxehci");
|
||||||
|
if (s != nil && s[0] >= '0' && s[0] <= '9')
|
||||||
|
maxehci = atoi(s);
|
||||||
|
if(maxehci == 0 || getconf("*nousbehci"))
|
||||||
return -1;
|
return -1;
|
||||||
ilock(&resetlck);
|
ilock(&resetlck);
|
||||||
scanpci();
|
scanpci();
|
||||||
|
|
|
@ -514,7 +514,10 @@ static Qh*
|
||||||
qhlinkqh(Qh *qh, Qh *next)
|
qhlinkqh(Qh *qh, Qh *next)
|
||||||
{
|
{
|
||||||
qh->next = next;
|
qh->next = next;
|
||||||
qh->link = PADDR(next)|Lqh;
|
if(next == nil)
|
||||||
|
qh->link = Lterm;
|
||||||
|
else
|
||||||
|
qh->link = PADDR(next)|Lqh;
|
||||||
coherence();
|
coherence();
|
||||||
return qh;
|
return qh;
|
||||||
}
|
}
|
||||||
|
@ -1662,7 +1665,7 @@ portlend(Ctlr *ctlr, int port, char *ss)
|
||||||
static int
|
static int
|
||||||
portreset(Hci *hp, int port, int on)
|
portreset(Hci *hp, int port, int on)
|
||||||
{
|
{
|
||||||
ulong s;
|
ulong *portscp;
|
||||||
Eopio *opio;
|
Eopio *opio;
|
||||||
Ctlr *ctlr;
|
Ctlr *ctlr;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1678,31 +1681,35 @@ portreset(Hci *hp, int port, int on)
|
||||||
qunlock(&ctlr->portlck);
|
qunlock(&ctlr->portlck);
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
s = opio->portsc[port-1];
|
portscp = &opio->portsc[port-1];
|
||||||
dprint("ehci %#p port %d reset; sts %#lux\n", ctlr->capio, port, s);
|
dprint("ehci %#p port %d reset; sts %#lux\n", ctlr->capio, port, *portscp);
|
||||||
ilock(ctlr);
|
ilock(ctlr);
|
||||||
s &= ~(Psenable|Psreset);
|
/* Shalted must be zero, else Psreset will stay set */
|
||||||
opio->portsc[port-1] = s | Psreset; /* initiate reset */
|
if (opio->sts & Shalted)
|
||||||
|
iprint("ehci %#p: halted yet trying to reset port\n",
|
||||||
|
ctlr->capio);
|
||||||
|
*portscp = (*portscp & ~Psenable) | Psreset; /* initiate reset */
|
||||||
coherence();
|
coherence();
|
||||||
|
|
||||||
for(i = 0; i < 50; i++){ /* was 10 */
|
/*
|
||||||
|
* usb 2 spec: reset must finish within 20 ms.
|
||||||
|
* linux says spec says it can take 50 ms. for hubs.
|
||||||
|
*/
|
||||||
|
for(i = 0; *portscp & Psreset && i < 10; i++)
|
||||||
delay(10);
|
delay(10);
|
||||||
if((opio->portsc[port-1] & Psreset) == 0)
|
if (*portscp & Psreset)
|
||||||
break;
|
iprint("ehci %#p: port %d didn't reset within %d ms; sts %#lux\n",
|
||||||
}
|
ctlr->capio, port, i * 10, *portscp);
|
||||||
if (opio->portsc[port-1] & Psreset)
|
*portscp &= ~Psreset; /* force appearance of reset done */
|
||||||
iprint("ehci %#p: port %d didn't reset after %d ms; sts %#lux\n",
|
|
||||||
ctlr->capio, port, i * 10, opio->portsc[port-1]);
|
|
||||||
opio->portsc[port-1] &= ~Psreset; /* force appearance of reset done */
|
|
||||||
coherence();
|
coherence();
|
||||||
|
delay(10); /* ehci spec: enable within 2 ms. */
|
||||||
|
|
||||||
delay(10);
|
if((*portscp & Psenable) == 0)
|
||||||
if((opio->portsc[port-1] & Psenable) == 0)
|
|
||||||
portlend(ctlr, port, "full");
|
portlend(ctlr, port, "full");
|
||||||
|
|
||||||
iunlock(ctlr);
|
iunlock(ctlr);
|
||||||
dprint("ehci %#p after port %d reset; sts %#lux\n",
|
dprint("ehci %#p after port %d reset; sts %#lux\n",
|
||||||
ctlr->capio, port, opio->portsc[port-1]);
|
ctlr->capio, port, *portscp);
|
||||||
qunlock(&ctlr->portlck);
|
qunlock(&ctlr->portlck);
|
||||||
poperror();
|
poperror();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2407,15 +2414,18 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock)
|
||||||
ntds++;
|
ntds++;
|
||||||
/*
|
/*
|
||||||
* Use td tok, not io tok, because of setup packets.
|
* Use td tok, not io tok, because of setup packets.
|
||||||
* Also, if the Td was stalled or active (previous Td
|
* Also, we must save the next toggle value from the
|
||||||
* was a short packet), we must save the toggle as it is.
|
* last completed Td (in case of a short packet, or
|
||||||
|
* fewer than the requested number of packets in the
|
||||||
|
* Td being transferred).
|
||||||
*/
|
*/
|
||||||
if(td->csw & (Tdhalt|Tdactive)){
|
if(td->csw & (Tdhalt|Tdactive))
|
||||||
if(saved++ == 0) {
|
saved++;
|
||||||
|
else{
|
||||||
|
if(!saved){
|
||||||
io->toggle = td->csw & Tddata1;
|
io->toggle = td->csw & Tddata1;
|
||||||
coherence();
|
coherence();
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
tot += td->ndata;
|
tot += td->ndata;
|
||||||
if(c != nil && (td->csw & Tdtok) == Tdtokin && td->ndata > 0){
|
if(c != nil && (td->csw & Tdtok) == Tdtokin && td->ndata > 0){
|
||||||
memmove(c, td->data, td->ndata);
|
memmove(c, td->data, td->ndata);
|
||||||
|
@ -3199,6 +3209,7 @@ init(Hci *hp)
|
||||||
{
|
{
|
||||||
Ctlr *ctlr;
|
Ctlr *ctlr;
|
||||||
Eopio *opio;
|
Eopio *opio;
|
||||||
|
static int ctlrno;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
hp->highspeed = 1;
|
hp->highspeed = 1;
|
||||||
|
@ -3218,7 +3229,12 @@ init(Hci *hp)
|
||||||
opio->cmd |= Case;
|
opio->cmd |= Case;
|
||||||
coherence();
|
coherence();
|
||||||
ehcirun(ctlr, 1);
|
ehcirun(ctlr, 1);
|
||||||
opio->config = Callmine; /* reclaim all ports */
|
/*
|
||||||
|
* route all ports by default to only one ehci (the first).
|
||||||
|
* it's not obvious how multiple ehcis could work and on some
|
||||||
|
* machines, setting Callmine on all ehcis makes the machine seize up.
|
||||||
|
*/
|
||||||
|
opio->config = (ctlrno == 0 ? Callmine : 0);
|
||||||
coherence();
|
coherence();
|
||||||
|
|
||||||
for (i = 0; i < hp->nports; i++)
|
for (i = 0; i < hp->nports; i++)
|
||||||
|
@ -3226,6 +3242,7 @@ init(Hci *hp)
|
||||||
iunlock(ctlr);
|
iunlock(ctlr);
|
||||||
if(ehcidebug > 1)
|
if(ehcidebug > 1)
|
||||||
dump(hp);
|
dump(hp);
|
||||||
|
ctlrno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in New Issue