ref: ffa54947bc52cf9a09d3cee9780e6858792a8b9b
parent: f8f118423c894a028a99e02e7eec7e85f785d919
author: cinap_lenrek <[email protected]>
date: Sun Nov 25 11:24:10 EST 2012
usbehci: fix broken bios takeover bios takeover was broken. bad Ceecpmask (was 8, should be 0xFF) causing it to miss the legacy control ecap and properly take overship of the controller. also the order seems wrong, we have to takeover before we do anything with the controller. remove the pci config space 0xc0 = 0x2000 write. this the uhci legacy register. its not anywhere in the ehci spec.
--- a/sys/src/9/pc/usbehci.h
+++ b/sys/src/9/pc/usbehci.h
@@ -36,7 +36,7 @@
Cdbgportmask = 0xF,
C64 = 1, /* 64-bits, in Ecapio capparms. */
Ceecpshift = 8, /* extended capabilities ptr. in */
- Ceecpmask = 8, /* the Ecapio capparms reg. */
+ Ceecpmask = 0xFF, /* the Ecapio capparms reg. */
Clegacy = 1, /* legacy support cap. id */
CLbiossem = 2, /* legacy cap. bios sem. */
CLossem = 3, /* legacy cap. os sem */
--- a/sys/src/9/pc/usbehcipc.c
+++ b/sys/src/9/pc/usbehcipc.c
@@ -17,35 +17,42 @@
static Ctlr* ctlrs[Nhcis];
static int maxehci = Nhcis;
-/* Isn't this cap list search in a helper function? */
+static int
+ehciecap(Ctlr *ctlr, int cap)
+{
+ int i, off;
+
+ off = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask;
+ for(i=0; i<48; i++){
+ if(off < 0x40 || (off & 3) != 0)
+ break;
+ if(pcicfgr8(ctlr->pcidev, off) == cap)
+ return off;
+ off = pcicfgr8(ctlr->pcidev, off+1);
+ }
+ return -1;
+}
+
static void
getehci(Ctlr* ctlr)
{
- int i, ptr, cap, sem;
+ int i, off;
- ptr = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask;
- for(; ptr != 0; ptr = pcicfgr8(ctlr->pcidev, ptr+1)){
- if(ptr < 0x40 || (ptr & ~0xFC))
- break;
- cap = pcicfgr8(ctlr->pcidev, ptr);
- if(cap != Clegacy)
- continue;
- sem = pcicfgr8(ctlr->pcidev, ptr+CLbiossem);
- if(sem == 0)
- continue;
- pcicfgw8(ctlr->pcidev, ptr+CLossem, 1);
+ off = ehciecap(ctlr, Clegacy);
+ if(off == -1)
+ return;
+ if(pcicfgr8(ctlr->pcidev, off+CLbiossem) != 0){
+ dprint("ehci %#p: bios active, taking over...\n", ctlr->capio);
+ pcicfgw8(ctlr->pcidev, off+CLossem, 1);
for(i = 0; i < 100; i++){
- if(pcicfgr8(ctlr->pcidev, ptr+CLbiossem) == 0)
+ if(pcicfgr8(ctlr->pcidev, off+CLbiossem) == 0)
break;
delay(10);
}
if(i == 100)
- dprint("ehci %#p: bios timed out\n", ctlr->capio);
- pcicfgw32(ctlr->pcidev, ptr+CLcontrol, 0); /* no SMIs */
- ctlr->opio->config = 0;
- coherence();
- return;
+ print("ehci %#p: bios timed out\n", ctlr->capio);
}
+ pcicfgw32(ctlr->pcidev, off+CLcontrol, 0); /* no SMIs */
}
static void
@@ -59,16 +66,17 @@
opio = ctlr->opio;
/*
- * Turn off legacy mode. Some controllers won't
- * interrupt us as expected otherwise.
+ * reclaim from bios
*/
- ehcirun(ctlr, 0);
- pcicfgw16(ctlr->pcidev, 0xc0, 0x2000);
+ getehci(ctlr);
/*
- * reclaim from bios
+ * halt and route ports to companion controllers
+ * until we are setup
*/
- getehci(ctlr);
+ ehcirun(ctlr, 0);
+ opio->config = 0;
+ coherence();
/* clear high 32 bits of address signals if it's 64 bits capable.
* This is probably not needed but it does not hurt and others do it.