Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / usb-uhci.c
1 // Code for handling UHCI USB controllers.
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "pci.h" // pci_bdf_to_bus
9 #include "config.h" // CONFIG_*
10 #include "ioport.h" // outw
11 #include "usb-uhci.h" // USBLEGSUP
12 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
13 #include "usb.h" // struct usb_s
14 #include "farptr.h" // GET_FLATPTR
15
16 struct usb_uhci_s {
17     struct usb_s usb;
18     u16 iobase;
19     struct uhci_qh *control_qh, *bulk_qh;
20     struct uhci_framelist *framelist;
21 };
22
23
24 /****************************************************************
25  * Root hub
26  ****************************************************************/
27
28 // Check if device attached to a given port
29 static int
30 uhci_hub_detect(struct usbhub_s *hub, u32 port)
31 {
32     struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
33     u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
34
35     u16 status = inw(ioport);
36     if (!(status & USBPORTSC_CCS))
37         // No device
38         return -1;
39
40     // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
41
42     // Begin reset on port
43     outw(USBPORTSC_PR, ioport);
44     msleep(USB_TIME_DRSTR);
45     return 0;
46 }
47
48 // Reset device on port
49 static int
50 uhci_hub_reset(struct usbhub_s *hub, u32 port)
51 {
52     struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
53     u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
54
55     // Finish reset on port
56     outw(0, ioport);
57     udelay(6); // 64 high-speed bit times
58     u16 status = inw(ioport);
59     if (!(status & USBPORTSC_CCS))
60         // No longer connected
61         return -1;
62     outw(USBPORTSC_PE, ioport);
63     return !!(status & USBPORTSC_LSDA);
64 }
65
66 // Disable port
67 static void
68 uhci_hub_disconnect(struct usbhub_s *hub, u32 port)
69 {
70     struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
71     u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
72     outw(0, ioport);
73 }
74
75 static struct usbhub_op_s uhci_HubOp = {
76     .detect = uhci_hub_detect,
77     .reset = uhci_hub_reset,
78     .disconnect = uhci_hub_disconnect,
79 };
80
81 // Find any devices connected to the root hub.
82 static int
83 check_uhci_ports(struct usb_uhci_s *cntl)
84 {
85     ASSERT32FLAT();
86     struct usbhub_s hub;
87     memset(&hub, 0, sizeof(hub));
88     hub.cntl = &cntl->usb;
89     hub.portcount = 2;
90     hub.op = &uhci_HubOp;
91     usb_enumerate(&hub);
92     return hub.devcount;
93 }
94
95
96 /****************************************************************
97  * Setup
98  ****************************************************************/
99
100 static void
101 reset_uhci(struct usb_uhci_s *cntl, u16 bdf)
102 {
103     // XXX - don't reset if not needed.
104
105     // Reset PIRQ and SMI
106     pci_config_writew(bdf, USBLEGSUP, USBLEGSUP_RWC);
107
108     // Reset the HC
109     outw(USBCMD_HCRESET, cntl->iobase + USBCMD);
110     udelay(5);
111
112     // Disable interrupts and commands (just to be safe).
113     outw(0, cntl->iobase + USBINTR);
114     outw(0, cntl->iobase + USBCMD);
115 }
116
117 static void
118 configure_uhci(void *data)
119 {
120     struct usb_uhci_s *cntl = data;
121
122     // Allocate ram for schedule storage
123     struct uhci_td *term_td = malloc_high(sizeof(*term_td));
124     struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
125     struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh));
126     struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
127     if (!term_td || !fl || !intr_qh || !term_qh) {
128         warn_noalloc();
129         goto fail;
130     }
131
132     // Work around for PIIX errata
133     memset(term_td, 0, sizeof(*term_td));
134     term_td->link = UHCI_PTR_TERM;
135     term_td->token = (uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT)
136                       | USB_PID_IN);
137     memset(term_qh, 0, sizeof(*term_qh));
138     term_qh->element = (u32)term_td;
139     term_qh->link = UHCI_PTR_TERM;
140
141     // Set schedule to point to primary intr queue head
142     memset(intr_qh, 0, sizeof(*intr_qh));
143     intr_qh->element = UHCI_PTR_TERM;
144     intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
145     int i;
146     for (i=0; i<ARRAY_SIZE(fl->links); i++)
147         fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
148     cntl->framelist = fl;
149     cntl->control_qh = cntl->bulk_qh = intr_qh;
150     barrier();
151
152     // Set the frame length to the default: 1 ms exactly
153     outb(USBSOF_DEFAULT, cntl->iobase + USBSOF);
154
155     // Store the frame list base address
156     outl((u32)fl->links, cntl->iobase + USBFLBASEADD);
157
158     // Set the current frame number
159     outw(0, cntl->iobase + USBFRNUM);
160
161     // Mark as configured and running with a 64-byte max packet.
162     outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD);
163
164     // Find devices
165     int count = check_uhci_ports(cntl);
166     free_pipe(cntl->usb.defaultpipe);
167     if (count)
168         // Success
169         return;
170
171     // No devices found - shutdown and free controller.
172     outw(0, cntl->iobase + USBCMD);
173 fail:
174     free(term_td);
175     free(fl);
176     free(intr_qh);
177     free(term_qh);
178     free(cntl);
179 }
180
181 void
182 uhci_init(struct pci_device *pci, int busid)
183 {
184     if (! CONFIG_USB_UHCI)
185         return;
186     u16 bdf = pci->bdf;
187     struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
188     if (!cntl) {
189         warn_noalloc();
190         return;
191     }
192     memset(cntl, 0, sizeof(*cntl));
193     cntl->usb.busid = busid;
194     cntl->usb.pci = pci;
195     cntl->usb.type = USB_TYPE_UHCI;
196     cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
197                     & PCI_BASE_ADDRESS_IO_MASK);
198
199     dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n"
200             , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
201             , pci_bdf_to_fn(bdf), cntl->iobase);
202
203     pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
204
205     reset_uhci(cntl, bdf);
206
207     run_thread(configure_uhci, cntl);
208 }
209
210
211 /****************************************************************
212  * End point communication
213  ****************************************************************/
214
215 static int
216 wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh)
217 {
218     // XXX - 500ms just a guess
219     u64 end = calc_future_tsc(500);
220     for (;;) {
221         if (qh->element & UHCI_PTR_TERM)
222             return 0;
223         if (check_tsc(end)) {
224             warn_timeout();
225             struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS);
226             dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n"
227                     , qh, td, td->status
228                     , inw(cntl->iobase + USBCMD)
229                     , inw(cntl->iobase + USBSTS));
230             return -1;
231         }
232         yield();
233     }
234 }
235
236 // Wait for next USB frame to start - for ensuring safe memory release.
237 static void
238 uhci_waittick(u16 iobase)
239 {
240     barrier();
241     u16 startframe = inw(iobase + USBFRNUM);
242     u64 end = calc_future_tsc(1000 * 5);
243     for (;;) {
244         if (inw(iobase + USBFRNUM) != startframe)
245             break;
246         if (check_tsc(end)) {
247             warn_timeout();
248             return;
249         }
250         yield();
251     }
252 }
253
254 struct uhci_pipe {
255     struct uhci_qh qh;
256     struct uhci_td *next_td;
257     struct usb_pipe pipe;
258     u16 iobase;
259     u8 toggle;
260 };
261
262 void
263 uhci_free_pipe(struct usb_pipe *p)
264 {
265     if (! CONFIG_USB_UHCI)
266         return;
267     dprintf(7, "uhci_free_pipe %p\n", p);
268     struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
269     struct usb_uhci_s *cntl = container_of(
270         pipe->pipe.cntl, struct usb_uhci_s, usb);
271
272     struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS);
273     for (;;) {
274         u32 link = pos->link;
275         if (link == UHCI_PTR_TERM) {
276             // Not found?!  Exit without freeing.
277             warn_internalerror();
278             return;
279         }
280         struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
281         if (next == &pipe->qh) {
282             pos->link = next->link;
283             if (cntl->control_qh == next)
284                 cntl->control_qh = pos;
285             if (cntl->bulk_qh == next)
286                 cntl->bulk_qh = pos;
287             uhci_waittick(cntl->iobase);
288             free(pipe);
289             return;
290         }
291         pos = next;
292     }
293 }
294
295 struct usb_pipe *
296 uhci_alloc_control_pipe(struct usb_pipe *dummy)
297 {
298     if (! CONFIG_USB_UHCI)
299         return NULL;
300     struct usb_uhci_s *cntl = container_of(
301         dummy->cntl, struct usb_uhci_s, usb);
302     dprintf(7, "uhci_alloc_control_pipe %p\n", &cntl->usb);
303
304     // Allocate a queue head.
305     struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
306     if (!pipe) {
307         warn_noalloc();
308         return NULL;
309     }
310     memset(pipe, 0, sizeof(*pipe));
311     memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
312     pipe->qh.element = UHCI_PTR_TERM;
313     pipe->iobase = cntl->iobase;
314
315     // Add queue head to controller list.
316     struct uhci_qh *control_qh = cntl->control_qh;
317     pipe->qh.link = control_qh->link;
318     barrier();
319     control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
320     if (cntl->bulk_qh == control_qh)
321         cntl->bulk_qh = &pipe->qh;
322     return &pipe->pipe;
323 }
324
325 int
326 uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
327              , void *data, int datasize)
328 {
329     ASSERT32FLAT();
330     if (! CONFIG_USB_UHCI)
331         return -1;
332     dprintf(5, "uhci_control %p\n", p);
333     struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
334     struct usb_uhci_s *cntl = container_of(
335         pipe->pipe.cntl, struct usb_uhci_s, usb);
336
337     int maxpacket = pipe->pipe.maxpacket;
338     int lowspeed = pipe->pipe.speed;
339     int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
340
341     // Setup transfer descriptors
342     int count = 2 + DIV_ROUND_UP(datasize, maxpacket);
343     struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count);
344     if (!tds) {
345         warn_noalloc();
346         return -1;
347     }
348
349     tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH;
350     tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
351                      | TD_CTRL_ACTIVE);
352     tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
353                     | USB_PID_SETUP);
354     tds[0].buffer = (void*)cmd;
355     int toggle = TD_TOKEN_TOGGLE;
356     int i;
357     for (i=1; i<count-1; i++) {
358         tds[i].link = (u32)&tds[i+1] | UHCI_PTR_DEPTH;
359         tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
360                          | TD_CTRL_ACTIVE);
361         int len = (i == count-2 ? (datasize - (i-1)*maxpacket) : maxpacket);
362         tds[i].token = (uhci_explen(len) | toggle
363                         | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
364                         | (dir ? USB_PID_IN : USB_PID_OUT));
365         tds[i].buffer = data + (i-1) * maxpacket;
366         toggle ^= TD_TOKEN_TOGGLE;
367     }
368     tds[i].link = UHCI_PTR_TERM;
369     tds[i].status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0)
370                      | TD_CTRL_ACTIVE);
371     tds[i].token = (uhci_explen(0) | TD_TOKEN_TOGGLE
372                     | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
373                     | (dir ? USB_PID_OUT : USB_PID_IN));
374     tds[i].buffer = 0;
375
376     // Transfer data
377     barrier();
378     pipe->qh.element = (u32)&tds[0];
379     int ret = wait_qh(cntl, &pipe->qh);
380     if (ret) {
381         pipe->qh.element = UHCI_PTR_TERM;
382         uhci_waittick(pipe->iobase);
383     }
384     free(tds);
385     return ret;
386 }
387
388 struct usb_pipe *
389 uhci_alloc_bulk_pipe(struct usb_pipe *dummy)
390 {
391     if (! CONFIG_USB_UHCI)
392         return NULL;
393     struct usb_uhci_s *cntl = container_of(
394         dummy->cntl, struct usb_uhci_s, usb);
395     dprintf(7, "uhci_alloc_bulk_pipe %p\n", &cntl->usb);
396
397     // Allocate a queue head.
398     struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
399     if (!pipe) {
400         warn_noalloc();
401         return NULL;
402     }
403     memset(pipe, 0, sizeof(*pipe));
404     memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
405     pipe->qh.element = UHCI_PTR_TERM;
406     pipe->iobase = cntl->iobase;
407
408     // Add queue head to controller list.
409     struct uhci_qh *bulk_qh = cntl->bulk_qh;
410     pipe->qh.link = bulk_qh->link;
411     barrier();
412     bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
413
414     return &pipe->pipe;
415 }
416
417 static int
418 wait_td(struct uhci_td *td)
419 {
420     u64 end = calc_future_tsc(5000); // XXX - lookup real time.
421     u32 status;
422     for (;;) {
423         status = td->status;
424         if (!(status & TD_CTRL_ACTIVE))
425             break;
426         if (check_tsc(end)) {
427             warn_timeout();
428             return -1;
429         }
430         yield();
431     }
432     if (status & TD_CTRL_ANY_ERROR) {
433         dprintf(1, "wait_td error - status=%x\n", status);
434         return -2;
435     }
436     return 0;
437 }
438
439 #define STACKTDS 4
440 #define TDALIGN 16
441
442 int
443 uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
444 {
445     if (! CONFIG_USB_UHCI)
446         return -1;
447     struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
448     dprintf(7, "uhci_send_bulk qh=%p dir=%d data=%p size=%d\n"
449             , &pipe->qh, dir, data, datasize);
450     int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
451     int lowspeed = GET_FLATPTR(pipe->pipe.speed);
452     int devaddr = (GET_FLATPTR(pipe->pipe.devaddr)
453                    | (GET_FLATPTR(pipe->pipe.ep) << 7));
454     int toggle = GET_FLATPTR(pipe->toggle) ? TD_TOKEN_TOGGLE : 0;
455
456     // Allocate 4 tds on stack (16byte aligned)
457     u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
458     struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN);
459     memset(tds, 0, sizeof(*tds) * STACKTDS);
460
461     // Enable tds
462     barrier();
463     SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
464
465     int tdpos = 0;
466     while (datasize) {
467         struct uhci_td *td = &tds[tdpos++ % STACKTDS];
468         int ret = wait_td(td);
469         if (ret)
470             goto fail;
471
472         int transfer = datasize;
473         if (transfer > maxpacket)
474             transfer = maxpacket;
475         struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
476                                                  , &tds[tdpos % STACKTDS]);
477         td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl);
478         td->token = (uhci_explen(transfer) | toggle
479                      | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
480                      | (dir ? USB_PID_IN : USB_PID_OUT));
481         td->buffer = data;
482         barrier();
483         td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
484                       | TD_CTRL_ACTIVE);
485         toggle ^= TD_TOKEN_TOGGLE;
486
487         data += transfer;
488         datasize -= transfer;
489     }
490     int i;
491     for (i=0; i<STACKTDS; i++) {
492         struct uhci_td *td = &tds[tdpos++ % STACKTDS];
493         int ret = wait_td(td);
494         if (ret)
495             goto fail;
496     }
497
498     SET_FLATPTR(pipe->toggle, !!toggle);
499     return 0;
500 fail:
501     dprintf(1, "uhci_send_bulk failed\n");
502     SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
503     uhci_waittick(GET_FLATPTR(pipe->iobase));
504     return -1;
505 }
506
507 struct usb_pipe *
508 uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
509 {
510     if (! CONFIG_USB_UHCI)
511         return NULL;
512     struct usb_uhci_s *cntl = container_of(
513         dummy->cntl, struct usb_uhci_s, usb);
514     dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
515
516     if (frameexp > 10)
517         frameexp = 10;
518     int maxpacket = dummy->maxpacket;
519     int lowspeed = dummy->speed;
520     int devaddr = dummy->devaddr | (dummy->ep << 7);
521     // Determine number of entries needed for 2 timer ticks.
522     int ms = 1<<frameexp;
523     int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
524     count = ALIGN(count, 2);
525     struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
526     struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
527     void *data = malloc_low(maxpacket * count);
528     if (!pipe || !tds || !data) {
529         warn_noalloc();
530         goto fail;
531     }
532     memset(pipe, 0, sizeof(*pipe));
533     memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
534     pipe->qh.element = (u32)tds;
535     pipe->next_td = &tds[0];
536     pipe->iobase = cntl->iobase;
537
538     int toggle = 0;
539     int i;
540     for (i=0; i<count; i++) {
541         tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
542         tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
543                          | TD_CTRL_ACTIVE);
544         tds[i].token = (uhci_explen(maxpacket) | toggle
545                         | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
546                         | USB_PID_IN);
547         tds[i].buffer = data + maxpacket * i;
548         toggle ^= TD_TOKEN_TOGGLE;
549     }
550
551     // Add to interrupt schedule.
552     struct uhci_framelist *fl = cntl->framelist;
553     if (frameexp == 0) {
554         // Add to existing interrupt entry.
555         struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
556         pipe->qh.link = intr_qh->link;
557         barrier();
558         intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
559         if (cntl->control_qh == intr_qh)
560             cntl->control_qh = &pipe->qh;
561         if (cntl->bulk_qh == intr_qh)
562             cntl->bulk_qh = &pipe->qh;
563     } else {
564         int startpos = 1<<(frameexp-1);
565         pipe->qh.link = fl->links[startpos];
566         barrier();
567         for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
568             fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
569     }
570
571     return &pipe->pipe;
572 fail:
573     free(pipe);
574     free(tds);
575     free(data);
576     return NULL;
577 }
578
579 int
580 uhci_poll_intr(struct usb_pipe *p, void *data)
581 {
582     ASSERT16();
583     if (! CONFIG_USB_UHCI)
584         return -1;
585
586     struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
587     struct uhci_td *td = GET_FLATPTR(pipe->next_td);
588     u32 status = GET_FLATPTR(td->status);
589     u32 token = GET_FLATPTR(td->token);
590     if (status & TD_CTRL_ACTIVE)
591         // No intrs found.
592         return -1;
593     // XXX - check for errors.
594
595     // Copy data.
596     void *tddata = GET_FLATPTR(td->buffer);
597     memcpy_far(GET_SEG(SS), data
598                , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
599                , uhci_expected_length(token));
600
601     // Reenable this td.
602     struct uhci_td *next = (void*)(GET_FLATPTR(td->link) & ~UHCI_PTR_BITS);
603     SET_FLATPTR(pipe->next_td, next);
604     barrier();
605     SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
606                              | TD_CTRL_ACTIVE));
607
608     return 0;
609 }