aboutsummaryrefslogtreecommitdiff
path: root/lib/libusb/usb-xhci.c
diff options
context:
space:
mode:
authorNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2015-09-18 14:16:59 +0530
committerAlexey Kardashevskiy <aik@ozlabs.ru>2015-10-06 12:50:50 +1100
commit94168f451fd2327f813e5aa131b609ca161db352 (patch)
tree8b3d7f43781e9cf9faa10dde5db417031bc10071 /lib/libusb/usb-xhci.c
parent8d2f3ba63106c09ce797d7cbdc1e3039ccc99047 (diff)
downloadSLOF-94168f451fd2327f813e5aa131b609ca161db352.zip
SLOF-94168f451fd2327f813e5aa131b609ca161db352.tar.gz
SLOF-94168f451fd2327f813e5aa131b609ca161db352.tar.bz2
usb-xhci: bulk improve event handling loop
Since the controller was being used by single user, event poll loop works without verifying what event returned. Now with usb-keyboard addition where we will get keyboard events, this would not work. Transfer bulk would only look for response from the trb queued and ignore rest of the events. Moreover, while bulk transfer is going on, there are no keyboard events in booting use case. Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Diffstat (limited to 'lib/libusb/usb-xhci.c')
-rw-r--r--lib/libusb/usb-xhci.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/lib/libusb/usb-xhci.c b/lib/libusb/usb-xhci.c
index 73d3e52..6d6b8ad 100644
--- a/lib/libusb/usb-xhci.c
+++ b/lib/libusb/usb-xhci.c
@@ -225,11 +225,11 @@ static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd,
xhcd->slot_id = 0;
}
-static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
- uint32_t event_type)
+static uint64_t xhci_poll_event(struct xhci_hcd *xhcd,
+ uint32_t event_type)
{
struct xhci_event_trb *event;
- uint64_t val;
+ uint64_t val, retval = 0;
uint32_t flags, time;
int index;
@@ -244,7 +244,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
mb();
flags = le32_to_cpu(event->flags);
if (time < SLOF_GetTimer())
- return NULL;
+ return 0;
}
mb();
@@ -273,6 +273,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
break;
}
xhcd->ering.deq = (uint64_t) (event + 1);
+ retval = le64_to_cpu(event->addr);
event->addr = 0;
event->status = 0;
@@ -289,7 +290,11 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
dprintf("Update start %x deq %x index %d\n",
xhcd->ering.trbs_dma, val, index/sizeof(*event));
write_reg64(&xhcd->run_regs->irs[0].erdp, val);
- return event;
+
+ if (retval == 0)
+ return (uint64_t)event;
+ else
+ return retval;
}
static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1,
@@ -1119,6 +1124,11 @@ static inline void *xhci_get_trb(struct xhci_seg *seg)
return (void *)enq;
}
+static uint64_t xhci_get_trb_phys(struct xhci_seg *seg, uint64_t trb)
+{
+ return seg->trbs_dma + (trb - (uint64_t)seg->trbs);
+}
+
static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
void *data, int datalen)
{
@@ -1128,7 +1138,8 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
struct xhci_transfer_trb *trb;
struct xhci_db_regs *dbr;
int ret = true;
- uint32_t slot_id, epno;
+ uint32_t slot_id, epno, time;
+ uint64_t trb_phys, event_phys;
if (!pipe->dev || !pipe->dev->hcidev) {
dprintf(" NULL pointer\n");
@@ -1153,13 +1164,25 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
}
trb = xhci_get_trb(seg);
+ trb_phys = xhci_get_trb_phys(seg, (uint64_t)trb);
fill_normal_trb(trb, (void *)data, datalen);
epno = xhci_get_epno(pipe);
write_reg32(&dbr->db[slot_id], epno);
- if (!xhci_poll_event(xhcd, 0)) {
- dprintf("Bulk failed\n");
- ret = false;
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (1) {
+ event_phys = xhci_poll_event(xhcd, 0);
+ if (event_phys == trb_phys) {
+ break;
+ } else if (event_phys == 0) { /* polling timed out */
+ ret = false;
+ break;
+ }
+
+ /* transfer timed out */
+ if (time < SLOF_GetTimer())
+ return false;
}
trb->addr = 0;
trb->len = 0;