X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fusb-uhci.c;h=a78dbcaf63e679ac55d1c8f3fc11fd93454ec6b0;hb=refs%2Fheads%2Fcoreboot;hp=40f83bb9a850d57b1662fd2d1ab6d6ba136e2fed;hpb=a5f2b91060ee43c9acd0162227b85153cbbae1c6;p=seabios.git diff --git a/src/usb-uhci.c b/src/usb-uhci.c index 40f83bb..a78dbca 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -179,14 +179,19 @@ fail: } void -uhci_init(u16 bdf, int busid) +uhci_init(struct pci_device *pci, int busid) { if (! CONFIG_USB_UHCI) return; + u16 bdf = pci->bdf; struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl)); + if (!cntl) { + warn_noalloc(); + return; + } memset(cntl, 0, sizeof(*cntl)); cntl->usb.busid = busid; - cntl->usb.bdf = bdf; + cntl->usb.pci = pci; cntl->usb.type = USB_TYPE_UHCI; cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4) & PCI_BASE_ADDRESS_IO_MASK); @@ -207,26 +212,13 @@ uhci_init(u16 bdf, int busid) * End point communication ****************************************************************/ -static int -wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh) -{ - // XXX - 500ms just a guess - u64 end = calc_future_tsc(500); - for (;;) { - if (qh->element & UHCI_PTR_TERM) - return 0; - if (check_tsc(end)) { - warn_timeout(); - struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS); - dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n" - , qh, td, td->status - , inw(cntl->iobase + USBCMD) - , inw(cntl->iobase + USBSTS)); - return -1; - } - yield(); - } -} +struct uhci_pipe { + struct uhci_qh qh; + struct uhci_td *next_td; + struct usb_pipe pipe; + u16 iobase; + u8 toggle; +}; // Wait for next USB frame to start - for ensuring safe memory release. static void @@ -246,13 +238,29 @@ uhci_waittick(u16 iobase) } } -struct uhci_pipe { - struct uhci_qh qh; - struct uhci_td *next_td; - struct usb_pipe pipe; - u16 iobase; - u8 toggle; -}; +static int +wait_pipe(struct uhci_pipe *pipe, int timeout) +{ + u64 end = calc_future_tsc(timeout); + for (;;) { + u32 el_link = GET_FLATPTR(pipe->qh.element); + if (el_link & UHCI_PTR_TERM) + return 0; + if (check_tsc(end)) { + warn_timeout(); + u16 iobase = GET_FLATPTR(pipe->iobase); + struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS); + dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n" + , pipe, (void*)el_link, GET_FLATPTR(td->status) + , inw(iobase + USBCMD) + , inw(iobase + USBSTS)); + SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); + uhci_waittick(iobase); + return -1; + } + yield(); + } +} void uhci_free_pipe(struct usb_pipe *p) @@ -326,8 +334,6 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize return -1; dprintf(5, "uhci_control %p\n", p); struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); - struct usb_uhci_s *cntl = container_of( - pipe->pipe.cntl, struct usb_uhci_s, usb); int maxpacket = pipe->pipe.maxpacket; int lowspeed = pipe->pipe.speed; @@ -371,11 +377,7 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize // Transfer data barrier(); pipe->qh.element = (u32)&tds[0]; - int ret = wait_qh(cntl, &pipe->qh); - if (ret) { - pipe->qh.element = UHCI_PTR_TERM; - uhci_waittick(pipe->iobase); - } + int ret = wait_pipe(pipe, 500); free(tds); return ret; } @@ -482,16 +484,8 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) data += transfer; datasize -= transfer; } - int i; - for (i=0; itoggle, !!toggle); - return 0; + return wait_pipe(pipe, 5000); fail: dprintf(1, "uhci_send_bulk failed\n"); SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);