]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/usbehcipc.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / pc / usbehcipc.c
1 /*
2  * PC-specific code for
3  * USB Enhanced Host Controller Interface (EHCI) driver
4  * High speed USB 2.0.
5  */
6
7 #include        "u.h"
8 #include        "../port/lib.h"
9 #include        "mem.h"
10 #include        "dat.h"
11 #include        "fns.h"
12 #include        "io.h"
13 #include        "../port/error.h"
14 #include        "../port/usb.h"
15 #include        "usbehci.h"
16
17 static Ctlr* ctlrs[Nhcis];
18 static int maxehci = Nhcis;
19
20 static int
21 ehciecap(Ctlr *ctlr, int cap)
22 {
23         int i, off;
24
25         off = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask;
26         for(i=0; i<48; i++){
27                 if(off < 0x40 || (off & 3) != 0)
28                         break;
29                 if(pcicfgr8(ctlr->pcidev, off) == cap)
30                         return off;
31                 off = pcicfgr8(ctlr->pcidev, off+1);
32         }
33         return -1;
34 }
35
36 static void
37 getehci(Ctlr* ctlr)
38 {
39         int i, off;
40
41         off = ehciecap(ctlr, Clegacy);
42         if(off == -1)
43                 return;
44         if(pcicfgr8(ctlr->pcidev, off+CLbiossem) != 0){
45                 dprint("ehci %#p: bios active, taking over...\n", ctlr->capio);
46                 pcicfgw8(ctlr->pcidev, off+CLossem, 1);
47                 for(i = 0; i < 100; i++){
48                         if(pcicfgr8(ctlr->pcidev, off+CLbiossem) == 0)
49                                 break;
50                         delay(10);
51                 }
52                 if(i == 100)
53                         print("ehci %#p: bios timed out\n", ctlr->capio);
54         }
55         pcicfgw32(ctlr->pcidev, off+CLcontrol, 0);      /* no SMIs */
56 }
57
58 static void
59 ehcireset(Ctlr *ctlr)
60 {
61         Eopio *opio;
62         int i;
63
64         ilock(ctlr);
65         dprint("ehci %#p reset\n", ctlr->capio);
66         opio = ctlr->opio;
67
68         /*
69          * reclaim from bios
70          */
71         getehci(ctlr);
72
73         /*
74          * halt and route ports to companion controllers
75          * until we are setup
76          */
77         ehcirun(ctlr, 0);
78         opio->config = 0;
79         coherence();
80
81         /* clear high 32 bits of address signals if it's 64 bits capable.
82          * This is probably not needed but it does not hurt and others do it.
83          */
84         if((ctlr->capio->capparms & C64) != 0){
85                 dprint("ehci: 64 bits\n");
86                 opio->seg = 0;
87                 coherence();
88         }
89
90         if(ehcidebugcapio != ctlr->capio){
91                 opio->cmd |= Chcreset;  /* controller reset */
92                 coherence();
93                 for(i = 0; i < 100; i++){
94                         if((opio->cmd & Chcreset) == 0)
95                                 break;
96                         delay(1);
97                 }
98                 if(i == 100)
99                         print("ehci %#p controller reset timed out\n", ctlr->capio);
100         }
101         opio->cmd |= Citc1;             /* 1 intr. per µframe */
102         coherence();
103         switch(opio->cmd & Cflsmask){
104         case Cfls1024:
105                 ctlr->nframes = 1024;
106                 break;
107         case Cfls512:
108                 ctlr->nframes = 512;
109                 break;
110         case Cfls256:
111                 ctlr->nframes = 256;
112                 break;
113         default:
114                 panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
115         }
116         dprint("ehci: %d frames\n", ctlr->nframes);
117         iunlock(ctlr);
118 }
119
120 static void
121 setdebug(Hci*, int d)
122 {
123         ehcidebug = d;
124 }
125
126 static void
127 shutdown(Hci *hp)
128 {
129         int i;
130         Ctlr *ctlr;
131         Eopio *opio;
132
133         ctlr = hp->aux;
134         ilock(ctlr);
135         opio = ctlr->opio;
136         opio->cmd |= Chcreset;          /* controller reset */
137         coherence();
138         for(i = 0; i < 100; i++){
139                 if((opio->cmd & Chcreset) == 0)
140                         break;
141                 delay(1);
142         }
143         if(i >= 100)
144                 print("ehci %#p controller reset timed out\n", ctlr->capio);
145         delay(100);
146         ehcirun(ctlr, 0);
147         opio->frbase = 0;
148         iunlock(ctlr);
149 }
150
151 static void
152 scanpci(void)
153 {
154         static int already = 0;
155         int i;
156         uintptr io;
157         Ctlr *ctlr;
158         Pcidev *p;
159         Ecapio *capio;
160
161         if(already)
162                 return;
163         already = 1;
164         p = nil;
165         while ((p = pcimatch(p, 0, 0)) != nil) {
166                 /*
167                  * Find EHCI controllers (Programming Interface = 0x20).
168                  */
169                 if(p->ccrb != Pcibcserial || p->ccru != Pciscusb)
170                         continue;
171                 switch(p->ccrp){
172                 case 0x20:
173                         io = p->mem[0].bar & ~0x0f;
174                         break;
175                 default:
176                         continue;
177                 }
178                 if(io == 0)
179                         continue;
180
181                 print("usbehci: %#x %#x: port %#p size %#x irq %d\n",
182                         p->vid, p->did, io, p->mem[0].size, p->intl);
183
184                 ctlr = malloc(sizeof(Ctlr));
185                 if(ctlr == nil){
186                         print("usbehci: no memory\n");
187                         continue;
188                 }
189                 ctlr->pcidev = p;
190                 ctlr->base = io;
191                 capio = ctlr->capio = vmap(io, p->mem[0].size);
192                 ctlr->opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
193                 pcisetbme(p);
194                 pcisetpms(p, 0);
195                 for(i = 0; i < Nhcis; i++)
196                         if(ctlrs[i] == nil){
197                                 ctlrs[i] = ctlr;
198                                 break;
199                         }
200                 if(i >= Nhcis)
201                         print("ehci: bug: more than %d controllers\n", Nhcis);
202
203                 /*
204                  * currently, if we enable a second ehci controller,
205                  * we'll wedge solid after iunlock in init for the second one.
206                  */
207                 if (i >= maxehci) {
208                         iprint("usbehci: ignoring controllers after first %d, "
209                                 "at %#p\n", maxehci, io);
210                         ctlrs[i] = nil;
211                 }
212         }
213 }
214
215 static int
216 reset(Hci *hp)
217 {
218         int i;
219         char *s;
220         Ctlr *ctlr;
221         Ecapio *capio;
222         Pcidev *p;
223         static Lock resetlck;
224
225         s = getconf("*maxehci");
226         if (s != nil && s[0] >= '0' && s[0] <= '9')
227                 maxehci = atoi(s);
228         if(maxehci == 0 || getconf("*nousbehci"))
229                 return -1;
230         ilock(&resetlck);
231         scanpci();
232
233         /*
234          * Any adapter matches if no hp->port is supplied,
235          * otherwise the ports must match.
236          */
237         ctlr = nil;
238         for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
239                 ctlr = ctlrs[i];
240                 if(ctlr->active == 0)
241                 if(hp->port == 0 || hp->port == ctlr->base){
242                         ctlr->active = 1;
243                         break;
244                 }
245         }
246         iunlock(&resetlck);
247         if(i >= Nhcis || ctlrs[i] == nil)
248                 return -1;
249
250         p = ctlr->pcidev;
251         hp->aux = ctlr;
252         hp->port = ctlr->base;
253         hp->irq = p->intl;
254         hp->tbdf = p->tbdf;
255
256         capio = ctlr->capio;
257         hp->nports = capio->parms & Cnports;
258
259         ddprint("echi: %s, ncc %lud npcc %lud\n",
260                 capio->parms & 0x10000 ? "leds" : "no leds",
261                 (capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
262         ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
263                 capio->parms & 0x40 ? "explicit" : "automatic",
264                 capio->parms & 0x10 ? "" : "no ", hp->nports);
265
266         ehcireset(ctlr);
267         ehcimeminit(ctlr);
268
269         /*
270          * Linkage to the generic HCI driver.
271          */
272         ehcilinkage(hp);
273         hp->shutdown = shutdown;
274         hp->debug = setdebug;
275         intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
276
277         return 0;
278 }
279
280 void
281 usbehcilink(void)
282 {
283         addhcitype("ehci", reset);
284 }