qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams
@ 2013-02-01 10:51 Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 1/4] usb: fix endpoint descriptor ordering Gerd Hoffmann
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-02-01 10:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

Early patches to add support for usb3 streams to qemu.  Covered are
the subsystem core, xhci emulation and usb attached scsi emulation.

It's good enougth to trigger bugs in the linux xhci driver's stream
handling.

enjoy,
  Gerd

Gerd Hoffmann (4):
  usb: fix endpoint descriptor ordering
  [wip] core: usb3 streams
  [wip] xhci: usb3 streams
  [wip] uas: usb3 streams

 hw/usb.h                      |   10 +-
 hw/usb/core.c                 |   10 +-
 hw/usb/desc.c                 |    9 +-
 hw/usb/dev-bluetooth.c        |    2 +-
 hw/usb/dev-hid.c              |    2 +-
 hw/usb/dev-hub.c              |   10 +-
 hw/usb/dev-network.c          |    2 +-
 hw/usb/dev-smartcard-reader.c |    2 +-
 hw/usb/dev-uas.c              |  247 +++++++++++++++++++++++++++++++-------
 hw/usb/dev-wacom.c            |    4 +-
 hw/usb/hcd-ehci.c             |    7 +-
 hw/usb/hcd-musb.c             |    2 +-
 hw/usb/hcd-ohci.c             |    4 +-
 hw/usb/hcd-uhci.c             |    2 +-
 hw/usb/hcd-xhci.c             |  266 +++++++++++++++++++++++++++++++++--------
 trace-events                  |    6 +-
 16 files changed, 461 insertions(+), 124 deletions(-)

-- 
1.7.9.7

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 1/4] usb: fix endpoint descriptor ordering
  2013-02-01 10:51 [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams Gerd Hoffmann
@ 2013-02-01 10:51 ` Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 2/4] [wip] core: usb3 streams Gerd Hoffmann
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-02-01 10:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Fix the ordering of the endpoint descriptors for superspeed endpoints:
The superspeed companion must come first, possible additional
descriptors for the endpoint after that.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/desc.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index b7c3233..b389381 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -225,12 +225,9 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
         d->u.endpoint.bRefresh      = ep->bRefresh;
         d->u.endpoint.bSynchAddress = ep->bSynchAddress;
     }
-    if (ep->extra) {
-        memcpy(dest + bLength, ep->extra, extralen);
-    }
 
     if (superlen) {
-        USBDescriptor *d = (void *)(dest + bLength + extralen);
+        USBDescriptor *d = (void *)(dest + bLength);
 
         d->bLength                       = 0x06;
         d->bDescriptorType               = USB_DT_ENDPOINT_COMPANION;
@@ -243,6 +240,10 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags,
             usb_hi(ep->wBytesPerInterval);
     }
 
+    if (ep->extra) {
+        memcpy(dest + bLength + superlen, ep->extra, extralen);
+    }
+
     return bLength + extralen + superlen;
 }
 
-- 
1.7.9.7

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 2/4] [wip] core: usb3 streams
  2013-02-01 10:51 [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 1/4] usb: fix endpoint descriptor ordering Gerd Hoffmann
@ 2013-02-01 10:51 ` Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 3/4] [wip] xhci: " Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 4/4] [wip] uas: " Gerd Hoffmann
  3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-02-01 10:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

---
 hw/usb.h                      |   10 ++++++----
 hw/usb/core.c                 |   10 ++++++----
 hw/usb/dev-bluetooth.c        |    2 +-
 hw/usb/dev-hid.c              |    2 +-
 hw/usb/dev-hub.c              |   10 +++++-----
 hw/usb/dev-network.c          |    2 +-
 hw/usb/dev-smartcard-reader.c |    2 +-
 hw/usb/dev-wacom.c            |    4 ++--
 hw/usb/hcd-ehci.c             |    7 ++++---
 hw/usb/hcd-musb.c             |    2 +-
 hw/usb/hcd-ohci.c             |    4 ++--
 hw/usb/hcd-uhci.c             |    2 +-
 12 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/hw/usb.h b/hw/usb.h
index 0d09e02..382496c 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -361,6 +361,7 @@ struct USBPacket {
     int pid;
     uint64_t id;
     USBEndpoint *ep;
+    unsigned int stream;
     QEMUIOVector iov;
     uint64_t parameter; /* control transfers */
     bool short_not_ok;
@@ -383,8 +384,9 @@ struct USBCombinedPacket {
 void usb_packet_init(USBPacket *p);
 void usb_packet_set_state(USBPacket *p, USBPacketState state);
 void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
-                      bool short_not_ok, bool int_req);
+void usb_packet_setup(USBPacket *p, int pid,
+                      USBEndpoint *ep, unsigned int stream,
+                      uint64_t id, bool short_not_ok, bool int_req);
 void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
 int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
 void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
@@ -430,7 +432,7 @@ void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);
 void usb_device_reset(USBDevice *dev);
-void usb_wakeup(USBEndpoint *ep);
+void usb_wakeup(USBEndpoint *ep, unsigned int stream);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
 int set_usb_string(uint8_t *buf, const char *str);
 
@@ -489,7 +491,7 @@ struct USBBus {
 struct USBBusOps {
     int (*register_companion)(USBBus *bus, USBPort *ports[],
                               uint32_t portcount, uint32_t firstport);
-    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep);
+    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
 };
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 674fef8..15a150a 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -71,7 +71,7 @@ void usb_device_reset(USBDevice *dev)
     usb_device_handle_reset(dev);
 }
 
-void usb_wakeup(USBEndpoint *ep)
+void usb_wakeup(USBEndpoint *ep, unsigned int stream)
 {
     USBDevice *dev = ep->dev;
     USBBus *bus = usb_bus_from_device(dev);
@@ -80,7 +80,7 @@ void usb_wakeup(USBEndpoint *ep)
         dev->port->ops->wakeup(dev->port);
     }
     if (bus->ops->wakeup_endpoint) {
-        bus->ops->wakeup_endpoint(bus, ep);
+        bus->ops->wakeup_endpoint(bus, ep, stream);
     }
 }
 
@@ -545,14 +545,16 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
     p->state = state;
 }
 
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
-                      bool short_not_ok, bool int_req)
+void usb_packet_setup(USBPacket *p, int pid,
+                      USBEndpoint *ep, unsigned int stream,
+                      uint64_t id, bool short_not_ok, bool int_req)
 {
     assert(!usb_packet_is_inflight(p));
     assert(p->iov.iov != NULL);
     p->id = id;
     p->pid = pid;
     p->ep = ep;
+    p->stream = stream;
     p->status = USB_RET_SUCCESS;
     p->actual_length = 0;
     p->parameter = 0;
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index adbf9d4..0f8aa48 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -478,7 +478,7 @@ static void usb_bt_out_hci_packet_event(void *opaque,
     struct USBBtState *s = (struct USBBtState *) opaque;
 
     if (s->evt.len == 0) {
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
     usb_bt_fifo_enqueue(&s->evt, data, len);
 }
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 29b6481..9701048 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -423,7 +423,7 @@ static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    usb_wakeup(us->intr);
+    usb_wakeup(us->intr, 0);
 }
 
 static void usb_hid_handle_reset(USBDevice *dev)
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 79f2f46..504c98c 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -164,7 +164,7 @@ static void usb_hub_attach(USBPort *port1)
     } else {
         port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
     }
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_hub_detach(USBPort *port1)
@@ -173,7 +173,7 @@ static void usb_hub_detach(USBPort *port1)
     USBHubPort *port = &s->ports[port1->index];
 
     trace_usb_hub_detach(s->dev.addr, port1->index + 1);
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 
     /* Let upstream know the device on this port is gone */
     s->dev.port->ops->child_detach(s->dev.port, port1->dev);
@@ -184,7 +184,7 @@ static void usb_hub_detach(USBPort *port1)
         port->wPortStatus &= ~PORT_STAT_ENABLE;
         port->wPortChange |= PORT_STAT_C_ENABLE;
     }
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
@@ -202,7 +202,7 @@ static void usb_hub_wakeup(USBPort *port1)
 
     if (port->wPortStatus & PORT_STAT_SUSPEND) {
         port->wPortChange |= PORT_STAT_C_SUSPEND;
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
 }
 
@@ -364,7 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                     port->wPortChange |= PORT_STAT_C_RESET;
                     /* set enable bit */
                     port->wPortStatus |= PORT_STAT_ENABLE;
-                    usb_wakeup(s->intr);
+                    usb_wakeup(s->intr, 0);
                 }
                 break;
             case PORT_POWER:
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 9dede4c..68b16fc 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -855,7 +855,7 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length)
             g_malloc0(sizeof(struct rndis_response) + length);
 
     if (QTAILQ_EMPTY(&s->rndis_resp)) {
-        usb_wakeup(s->intr);
+        usb_wakeup(s->intr, 0);
     }
 
     QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 979a473..caebc1c 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -839,7 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void ccid_write_data_block_error(
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index ab9fa2e..3be5cde 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -138,7 +138,7 @@ static void usb_mouse_event(void *opaque,
     s->dz += dz1;
     s->buttons_state = buttons_state;
     s->changed = 1;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static void usb_wacom_event(void *opaque,
@@ -152,7 +152,7 @@ static void usb_wacom_event(void *opaque,
     s->dz += dz;
     s->buttons_state = buttons_state;
     s->changed = 1;
-    usb_wakeup(s->intr);
+    usb_wakeup(s->intr, 0);
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 7040659..5176251 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -874,7 +874,8 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
     return 0;
 }
 
-static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+                                 unsigned int stream)
 {
     EHCIState *s = container_of(bus, EHCIState, bus);
     uint32_t portsc = s->portsc[ep->dev->port->index];
@@ -1420,7 +1421,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
         }
 
         spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0);
-        usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd,
+        usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd,
                          (p->qtd.token & QTD_TOKEN_IOC) != 0);
         usb_packet_map(&p->packet, &p->sgl);
         p->async = EHCI_ASYNC_INITIALIZED;
@@ -1493,7 +1494,7 @@ static int ehci_process_itd(EHCIState *ehci,
             dev = ehci_find_device(ehci, devaddr);
             ep = usb_ep_get(dev, pid, endp);
             if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
-                usb_packet_setup(&ehci->ipacket, pid, ep, addr, false,
+                usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
                                  (itd->transact[i] & ITD_XACT_IOC) != 0);
                 usb_packet_map(&ehci->ipacket, &ehci->isgl);
                 usb_handle_packet(dev, &ehci->ipacket);
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 64e9e83..7968e17 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -625,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     /* A wild guess on the FADDR semantics... */
     dev = usb_find_device(&s->port, ep->faddr[idx]);
     uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
-    usb_packet_setup(&ep->packey[dir].p, pid, uep,
+    usb_packet_setup(&ep->packey[dir].p, pid, uep, 0,
                      (dev->addr << 16) | (uep->nr << 8) | pid, false, true);
     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
     ep->packey[dir].ep = ep;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index dd9967b..51241cd 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -830,7 +830,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
                        OHCI_BM(iso_td.flags, TD_DI) == 0;
         dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
         ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
-        usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req);
+        usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
         usb_handle_packet(dev, &ohci->usb_packet);
         if (ohci->usb_packet.status == USB_RET_ASYNC) {
@@ -1034,7 +1034,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
         }
         dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
         ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
-        usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r,
+        usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
                          OHCI_BM(td.flags, TD_DI) == 0);
         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
         usb_handle_packet(dev, &ohci->usb_packet);
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 60645aa..f8c4286 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -879,7 +879,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
 
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
-    usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
+    usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd,
                      (td->ctrl & TD_CTRL_IOC) != 0);
     qemu_sglist_add(&async->sgl, td->buffer, max_len);
     usb_packet_map(&async->packet, &async->sgl);
-- 
1.7.9.7

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 3/4] [wip] xhci: usb3 streams
  2013-02-01 10:51 [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 1/4] usb: fix endpoint descriptor ordering Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 2/4] [wip] core: usb3 streams Gerd Hoffmann
@ 2013-02-01 10:51 ` Gerd Hoffmann
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 4/4] [wip] uas: " Gerd Hoffmann
  3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-02-01 10:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/hcd-xhci.c |  266 +++++++++++++++++++++++++++++++++++++++++++----------
 trace-events      |    6 +-
 2 files changed, 220 insertions(+), 52 deletions(-)

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 5fb0c48..ce17e2a 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -34,8 +34,8 @@
 #else
 #define DPRINTF(...) do {} while (0)
 #endif
-#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
-                             __func__, __LINE__); abort(); } while (0)
+#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \
+                                 __func__, __LINE__, _msg); abort(); } while (0)
 
 #define MAXPORTS_2 15
 #define MAXPORTS_3 15
@@ -301,6 +301,8 @@ typedef enum TRBCCode {
 #define SLOT_CONTEXT_ENTRIES_SHIFT 27
 
 typedef struct XHCIState XHCIState;
+typedef struct XHCIStreamContext XHCIStreamContext;
+typedef struct XHCIEPContext XHCIEPContext;
 
 #define get_field(data, field)                  \
     (((data) >> field##_SHIFT) & field##_MASK)
@@ -351,6 +353,7 @@ typedef struct XHCITransfer {
     unsigned int iso_pkts;
     unsigned int slotid;
     unsigned int epid;
+    unsigned int streamid;
     bool in_xfer;
     bool iso_xfer;
 
@@ -367,7 +370,14 @@ typedef struct XHCITransfer {
     uint64_t mfindex_kick;
 } XHCITransfer;
 
-typedef struct XHCIEPContext {
+struct XHCIStreamContext {
+    dma_addr_t pctx;
+    unsigned int sct;
+    XHCIRing ring;
+    XHCIStreamContext *sstreams;
+};
+
+struct XHCIEPContext {
     XHCIState *xhci;
     unsigned int slotid;
     unsigned int epid;
@@ -382,11 +392,17 @@ typedef struct XHCIEPContext {
     unsigned int max_psize;
     uint32_t state;
 
+    /* streams */
+    unsigned int max_pstreams;
+    bool         lsa;
+    unsigned int nr_pstreams;
+    XHCIStreamContext *pstreams;
+
     /* iso xfer scheduling */
     unsigned int interval;
     int64_t mfindex_last;
     QEMUTimer *kick_timer;
-} XHCIEPContext;
+};
 
 typedef struct XHCISlot {
     bool enabled;
@@ -482,7 +498,7 @@ enum xhci_flags {
 };
 
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
-                         unsigned int epid);
+                         unsigned int epid, unsigned int streamid);
 static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
                                 unsigned int epid);
 static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
@@ -1068,18 +1084,112 @@ static void xhci_stop(XHCIState *xhci)
     xhci->crcr_low &= ~CRCR_CRR;
 }
 
+static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count,
+                                                     dma_addr_t base)
+{
+    XHCIStreamContext *stctx;
+    unsigned int i;
+
+    stctx = g_new0(XHCIStreamContext, count);
+    for (i = 0; i < count; i++) {
+        stctx[i].pctx = base + i * 16;
+        stctx[i].sct = -1;
+    }
+    return stctx;
+}
+
+static void xhci_reset_streams(XHCIEPContext *epctx)
+{
+    unsigned int i;
+
+    for (i = 0; i < epctx->nr_pstreams; i++) {
+        epctx->pstreams[i].sct = -1;
+        g_free(epctx->pstreams[i].sstreams);
+    }
+}
+
+static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
+{
+    assert(epctx->pstreams == NULL);
+    epctx->nr_pstreams = 2 << epctx->max_pstreams;
+    epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
+}
+
+static void xhci_free_streams(XHCIEPContext *epctx)
+{
+    int i;
+
+    assert(epctx->pstreams != NULL);
+
+    if (!epctx->lsa) {
+        for (i = 0; i < epctx->nr_pstreams; i++) {
+            g_free(epctx->pstreams[i].sstreams);
+        }
+    }
+    g_free(epctx->pstreams);
+    epctx->pstreams = NULL;
+    epctx->nr_pstreams = 0;
+}
+
+static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx,
+                                           unsigned int streamid)
+{
+    XHCIStreamContext *sctx;
+    dma_addr_t base;
+    uint32_t ctx[2];
+
+    assert(streamid != 0);
+    if (epctx->lsa) {
+        if (streamid >= epctx->nr_pstreams) {
+            return NULL;
+        }
+        sctx = epctx->pstreams + streamid;
+    } else {
+        FIXME("secondary streams not implemented yet");
+    }
+
+    if (sctx->sct == -1) {
+        xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx));
+        fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__,
+                streamid, sctx->pctx, ctx[0], ctx[1]);
+        sctx->sct = (ctx[0] >> 1) & 0x07;
+        if (sctx->sct != 1) {
+            FIXME("must return error");
+        }
+        base = xhci_addr64(ctx[0] & ~0xf, ctx[1]);
+        xhci_ring_init(epctx->xhci, &sctx->ring, base);
+    }
+    return sctx;
+}
+
 static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
-                              uint32_t state)
+                              XHCIStreamContext *sctx, uint32_t state)
 {
     uint32_t ctx[5];
+    uint32_t ctx2[2];
 
+    fprintf(stderr, "%s: epid %d, state %d\n",
+            __func__, epctx->epid, state);
     xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
     ctx[0] &= ~EP_STATE_MASK;
     ctx[0] |= state;
-    ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
-    ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
-    DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
-            epctx->pctx, state, ctx[3], ctx[2]);
+
+    /* update ring dequeue ptr */
+    if (epctx->nr_pstreams) {
+        if (sctx != NULL) {
+            xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+            ctx2[0] &= 0xe;
+            ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs;
+            ctx2[1] = (sctx->ring.dequeue >> 16) >> 16;
+            xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2));
+        }
+    } else {
+        ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
+        ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
+        DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
+                epctx->pctx, state, ctx[3], ctx[2]);
+    }
+
     xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
     epctx->state = state;
 }
@@ -1087,7 +1197,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
 static void xhci_ep_kick_timer(void *opaque)
 {
     XHCIEPContext *epctx = opaque;
-    xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid);
+    xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0);
 }
 
 static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
@@ -1117,16 +1227,22 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
     slot->eps[epid-1] = epctx;
 
     dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
-    xhci_ring_init(xhci, &epctx->ring, dequeue);
-    epctx->ring.ccs = ctx[2] & 1;
 
     epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
     DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
     epctx->pctx = pctx;
     epctx->max_psize = ctx[1]>>16;
     epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+    epctx->max_pstreams = (ctx[0] >> 10) & 0xf;
+    epctx->lsa = (ctx[0] >> 15) & 1;
     DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
             epid/2, epid%2, epctx->max_psize);
+    if (epctx->max_pstreams) {
+        xhci_alloc_streams(epctx, dequeue);
+    } else {
+        xhci_ring_init(xhci, &epctx->ring, dequeue);
+        epctx->ring.ccs = ctx[2] & 1;
+    }
     for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
         usb_packet_init(&epctx->transfers[i].packet);
     }
@@ -1227,7 +1343,11 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-    xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+    if (epctx->nr_pstreams) {
+        xhci_free_streams(epctx);
+    }
+
+    xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
 
     qemu_free_timer(epctx->kick_timer);
     g_free(epctx);
@@ -1264,7 +1384,11 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+    if (epctx->nr_pstreams) {
+        xhci_reset_streams(epctx);
+    }
 
     return CC_SUCCESS;
 }
@@ -1315,16 +1439,22 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
         return CC_USB_TRANSACTION_ERROR;
     }
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED);
+
+    if (epctx->nr_pstreams) {
+        xhci_reset_streams(epctx);
+    }
 
     return CC_SUCCESS;
 }
 
 static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
-                                    unsigned int epid, uint64_t pdequeue)
+                                    unsigned int epid, unsigned int streamid,
+                                    uint64_t pdequeue)
 {
     XHCISlot *slot;
     XHCIEPContext *epctx;
+    XHCIStreamContext *sctx;
     dma_addr_t dequeue;
 
     assert(slotid >= 1 && slotid <= xhci->numslots);
@@ -1334,7 +1464,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
         return CC_TRB_ERROR;
     }
 
-    trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue);
+    trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue);
     dequeue = xhci_mask64(pdequeue);
 
     slot = &xhci->slots[slotid-1];
@@ -1346,16 +1476,23 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
 
     epctx = slot->eps[epid-1];
 
-
     if (epctx->state != EP_STOPPED) {
         fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
         return CC_CONTEXT_STATE_ERROR;
     }
 
-    xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
-    epctx->ring.ccs = dequeue & 1;
+    if (epctx->nr_pstreams) {
+        sctx = xhci_find_stream(epctx, streamid);
+        assert(sctx != NULL);
+        xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf);
+        sctx->ring.ccs = dequeue & 1;
+    } else {
+        sctx = NULL;
+        xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+        epctx->ring.ccs = dequeue & 1;
+    }
 
-    xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+    xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED);
 
     return CC_SUCCESS;
 }
@@ -1484,12 +1621,19 @@ static void xhci_stall_ep(XHCITransfer *xfer)
     XHCIState *xhci = xfer->xhci;
     XHCISlot *slot = &xhci->slots[xfer->slotid-1];
     XHCIEPContext *epctx = slot->eps[xfer->epid-1];
-
-    epctx->ring.dequeue = xfer->trbs[0].addr;
-    epctx->ring.ccs = xfer->trbs[0].ccs;
-    xhci_set_ep_state(xhci, epctx, EP_HALTED);
-    DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
-    DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue);
+    XHCIStreamContext *sctx = xfer->streamid ?
+        xhci_find_stream(epctx, xfer->streamid) : NULL;
+
+    if (epctx->nr_pstreams) {
+        assert(sctx != NULL);
+        sctx->ring.dequeue = xfer->trbs[0].addr;
+        sctx->ring.ccs = xfer->trbs[0].ccs;
+        xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED);
+    } else {
+        epctx->ring.dequeue = xfer->trbs[0].addr;
+        epctx->ring.ccs = xfer->trbs[0].ccs;
+        xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED);
+    }
 }
 
 static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
@@ -1518,8 +1662,8 @@ static int xhci_setup_packet(XHCITransfer *xfer)
     }
 
     xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
-    usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false,
-                     xfer->int_req);
+    usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
+                     xfer->trbs[0].addr, false, xfer->int_req);
     usb_packet_map(&xfer->packet, &xfer->sgl);
     DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
             xfer->packet.pid, dev->addr, ep->nr);
@@ -1572,7 +1716,7 @@ static int xhci_complete_packet(XHCITransfer *xfer)
     default:
         fprintf(stderr, "%s: FIXME: status = %d\n", __func__,
                 xfer->packet.status);
-        FIXME();
+        FIXME("unhandled USB_RET_*");
     }
     return 0;
 }
@@ -1585,7 +1729,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
     trb_setup = &xfer->trbs[0];
     trb_status = &xfer->trbs[xfer->trb_count-1];
 
-    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
 
     /* at most one Event Data TRB allowed after STATUS */
     if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
@@ -1627,7 +1771,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
 
     xhci_complete_packet(xfer);
     if (!xfer->running_async && !xfer->running_retry) {
-        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0);
     }
     return 0;
 }
@@ -1710,26 +1854,29 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
 
     xhci_complete_packet(xfer);
     if (!xfer->running_async && !xfer->running_retry) {
-        xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+        xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid);
     }
     return 0;
 }
 
 static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
 {
-    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid);
+    trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid);
     return xhci_submit(xhci, xfer, epctx);
 }
 
-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+                         unsigned int epid, unsigned int streamid)
 {
+    XHCIStreamContext *stctx;
     XHCIEPContext *epctx;
+    XHCIRing *ring;
     USBEndpoint *ep = NULL;
     uint64_t mfindex;
     int length;
     int i;
 
-    trace_usb_xhci_ep_kick(slotid, epid);
+    trace_usb_xhci_ep_kick(slotid, epid, streamid);
     assert(slotid >= 1 && slotid <= xhci->numslots);
     assert(epid >= 1 && epid <= 31);
 
@@ -1782,14 +1929,27 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
         return;
     }
 
-    xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+    if (epctx->nr_pstreams) {
+        stctx = xhci_find_stream(epctx, streamid);
+        if (stctx == NULL) {
+            return;
+        }
+        ring = &stctx->ring;
+        xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING);
+    } else {
+        ring = &epctx->ring;
+        streamid = 0;
+        xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING);
+    }
+    assert(ring->base != 0);
 
     while (1) {
         XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
         if (xfer->running_async || xfer->running_retry) {
             break;
         }
-        length = xhci_ring_chain_length(xhci, &epctx->ring);
+        length = xhci_ring_chain_length(xhci, ring);
         if (length < 0) {
             break;
         } else if (length == 0) {
@@ -1808,11 +1968,12 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
         xfer->trb_count = length;
 
         for (i = 0; i < length; i++) {
-            assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+            assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
         }
         xfer->xhci = xhci;
         xfer->epid = epid;
         xfer->slotid = slotid;
+        xfer->streamid = streamid;
 
         if (epid == 1) {
             if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
@@ -1977,7 +2138,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
         DPRINTF("xhci: device address is %d\n", slot->devaddr);
         usb_device_reset(dev);
         usb_packet_setup(&p, USB_TOKEN_OUT,
-                         usb_ep_get(dev, USB_TOKEN_OUT, 0),
+                         usb_ep_get(dev, USB_TOKEN_OUT, 0), 0,
                          0, false, false);
         usb_device_handle_control(dev, &p,
                                   DeviceOutRequest | USB_REQ_SET_ADDRESS,
@@ -2357,11 +2518,14 @@ static void xhci_process_commands(XHCIState *xhci)
             }
             break;
         case CR_SET_TR_DEQUEUE:
+            fprintf(stderr, "%s: CR_SET_TR_DEQUEUE\n", __func__);
             slotid = xhci_get_slot(xhci, &event, &trb);
             if (slotid) {
                 unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
                     & TRB_CR_EPID_MASK;
-                event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+                unsigned int streamid = (trb.status >> 16) & 0xffff;
+                event.ccode = xhci_set_ep_dequeue(xhci, slotid,
+                                                  epid, streamid,
                                                   trb.parameter);
             }
             break;
@@ -2554,9 +2718,9 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
         break;
     case 0x10: /* HCCPARAMS */
         if (sizeof(dma_addr_t) == 4) {
-            ret = 0x00081000;
+            ret = 0x00087000;
         } else {
-            ret = 0x00081001;
+            ret = 0x00087001;
         }
         break;
     case 0x14: /* DBOFF */
@@ -2880,6 +3044,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
                                 uint64_t val, unsigned size)
 {
     XHCIState *xhci = ptr;
+    unsigned int epid, streamid;
 
     trace_usb_xhci_doorbell_write(reg, val);
 
@@ -2898,13 +3063,15 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
                     (uint32_t)val);
         }
     } else {
+        epid = val & 0xff;
+        streamid = (val >> 16) & 0xffff;
         if (reg > xhci->numslots) {
             fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg);
-        } else if (val > 31) {
+        } else if (epid > 31) {
             fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n",
                     (int)reg, (uint32_t)val);
         } else {
-            xhci_kick_ep(xhci, reg, val);
+            xhci_kick_ep(xhci, reg, epid, streamid);
         }
     }
 }
@@ -2988,7 +3155,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet)
         return;
     }
     xhci_complete_packet(xfer);
-    xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+    xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid);
 }
 
 static void xhci_child_detach(USBPort *uport, USBDevice *child)
@@ -3033,7 +3200,8 @@ static int xhci_find_epid(USBEndpoint *ep)
     }
 }
 
-static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
+static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
+                                 unsigned int stream)
 {
     XHCIState *xhci = container_of(bus, XHCIState, bus);
     int slotid;
@@ -3044,7 +3212,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep)
         DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
         return;
     }
-    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep));
+    xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
 }
 
 static USBBusOps xhci_bus_ops = {
diff --git a/trace-events b/trace-events
index 57666dd..a275fa8 100644
--- a/trace-events
+++ b/trace-events
@@ -370,11 +370,11 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
 usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
 usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
 usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64
-usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
+usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64
+usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d"
 usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
 usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
-usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d"
+usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d"
 usb_xhci_xfer_async(void *xfer) "%p"
 usb_xhci_xfer_nak(void *xfer) "%p"
 usb_xhci_xfer_retry(void *xfer) "%p"
-- 
1.7.9.7

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [Qemu-devel] [PATCH 4/4] [wip] uas: usb3 streams
  2013-02-01 10:51 [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2013-02-01 10:51 ` [Qemu-devel] [PATCH 3/4] [wip] xhci: " Gerd Hoffmann
@ 2013-02-01 10:51 ` Gerd Hoffmann
  3 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2013-02-01 10:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/usb/dev-uas.c |  247 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 205 insertions(+), 42 deletions(-)

diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index d904d1a..1ac5117 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -99,6 +99,9 @@ typedef struct {
 
 /* --------------------------------------------------------------------- */
 
+#define UAS_STREAM_BM_ATTR  4
+#define UAS_MAX_STREAMS     (1 << UAS_STREAM_BM_ATTR)
+
 typedef struct UASDevice UASDevice;
 typedef struct UASRequest UASRequest;
 typedef struct UASStatus UASStatus;
@@ -106,12 +109,18 @@ typedef struct UASStatus UASStatus;
 struct UASDevice {
     USBDevice                 dev;
     SCSIBus                   bus;
-    UASRequest                *datain;
-    UASRequest                *dataout;
-    USBPacket                 *status;
     QEMUBH                    *status_bh;
     QTAILQ_HEAD(, UASStatus)  results;
     QTAILQ_HEAD(, UASRequest) requests;
+
+    /* usb 2.0 only */
+    USBPacket                 *status2;
+    UASRequest                *datain2;
+    UASRequest                *dataout2;
+
+    /* usb 3.0 only */
+    USBPacket                 *data3[UAS_MAX_STREAMS];
+    USBPacket                 *status3[UAS_MAX_STREAMS];
 };
 
 struct UASRequest {
@@ -132,6 +141,7 @@ struct UASRequest {
 };
 
 struct UASStatus {
+    uint32_t                  stream;
     uas_ui                    status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
@@ -144,6 +154,7 @@ enum {
     STR_PRODUCT,
     STR_SERIALNUMBER,
     STR_CONFIG_HIGH,
+    STR_CONFIG_SUPER,
 };
 
 static const USBDescStrings desc_strings = {
@@ -151,6 +162,7 @@ static const USBDescStrings desc_strings = {
     [STR_PRODUCT]      = "USB Attached SCSI HBA",
     [STR_SERIALNUMBER] = "27842",
     [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
+    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
 };
 
 static const USBDescIface desc_iface_high = {
@@ -204,6 +216,64 @@ static const USBDescIface desc_iface_high = {
     }
 };
 
+static const USBDescIface desc_iface_super = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 4,
+    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
+    .bInterfaceSubClass            = 0x06, /* SCSI */
+    .bInterfaceProtocol            = 0x62, /* UAS  */
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_COMMAND,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_IN | UAS_PIPE_ID_STATUS,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_STATUS,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_DATA_IN,
+                0x00,  /*  u8  bReserved */
+            },
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 1024,
+            .bMaxBurst             = 15,
+            .bmAttributes_super    = UAS_STREAM_BM_ATTR,
+            .extra = (uint8_t[]) {
+                0x04,  /*  u8  bLength */
+                0x24,  /*  u8  bDescriptorType */
+                UAS_PIPE_ID_DATA_OUT,
+                0x00,  /*  u8  bReserved */
+            },
+        },
+    }
+};
+
 static const USBDescDevice desc_device_high = {
     .bcdUSB                        = 0x0200,
     .bMaxPacketSize0               = 64,
@@ -220,6 +290,22 @@ static const USBDescDevice desc_device_high = {
     },
 };
 
+static const USBDescDevice desc_device_super = {
+    .bcdUSB                        = 0x0300,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .iConfiguration        = STR_CONFIG_SUPER,
+            .bmAttributes          = 0xc0,
+            .nif = 1,
+            .ifs = &desc_iface_super,
+        },
+    },
+};
+
 static const USBDesc desc = {
     .id = {
         .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
@@ -229,45 +315,68 @@ static const USBDesc desc = {
         .iProduct          = STR_PRODUCT,
         .iSerialNumber     = STR_SERIALNUMBER,
     },
-    .high = &desc_device_high,
-    .str  = desc_strings,
+    .high  = &desc_device_high,
+    .super = &desc_device_super,
+    .str   = desc_strings,
 };
 
 /* --------------------------------------------------------------------- */
 
-static UASStatus *usb_uas_alloc_status(uint8_t id, uint16_t tag)
+static bool uas_using_streams(UASDevice *uas)
+{
+    return uas->dev.speed == USB_SPEED_SUPER;
+}
+
+/* --------------------------------------------------------------------- */
+
+static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
 {
     UASStatus *st = g_new0(UASStatus, 1);
 
     st->status.hdr.id = id;
     st->status.hdr.tag = cpu_to_be16(tag);
     st->length = sizeof(uas_ui_header);
+    if (uas_using_streams(uas)) {
+        st->stream = tag;
+    }
     return st;
 }
 
 static void usb_uas_send_status_bh(void *opaque)
 {
     UASDevice *uas = opaque;
-    UASStatus *st = QTAILQ_FIRST(&uas->results);
-    USBPacket *p = uas->status;
+    UASStatus *st;
+    USBPacket *p;
 
-    assert(p != NULL);
-    assert(st != NULL);
+    while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
+        if (uas_using_streams(uas)) {
+            p = uas->status3[st->stream];
+            uas->status3[st->stream] = NULL;
+        } else {
+            p = uas->status2;
+            uas->status2 = NULL;
+        }
+        if (p == NULL) {
+            break;
+        }
 
-    uas->status = NULL;
-    usb_packet_copy(p, &st->status, st->length);
-    QTAILQ_REMOVE(&uas->results, st, next);
-    g_free(st);
+        usb_packet_copy(p, &st->status, st->length);
+        QTAILQ_REMOVE(&uas->results, st, next);
+        g_free(st);
 
-    p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
-    usb_packet_complete(&uas->dev, p);
+        p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
+        usb_packet_complete(&uas->dev, p);
+    }
 }
 
 static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
 {
+    USBPacket *p = uas_using_streams(uas) ?
+        uas->status3[st->stream] : uas->status2;
+
     st->length += length;
     QTAILQ_INSERT_TAIL(&uas->results, st, next);
-    if (uas->status) {
+    if (p) {
         /*
          * Just schedule bh make sure any in-flight data transaction
          * is finished before completing (sending) the status packet.
@@ -276,14 +385,14 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
     } else {
         USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
                                      UAS_PIPE_ID_STATUS);
-        usb_wakeup(ep);
+        usb_wakeup(ep, st->stream);
     }
 }
 
 static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
                                    uint8_t code, uint16_t add_info)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_RESPONSE, tag);
+    UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
 
     trace_usb_uas_response(uas->dev.addr, tag, code);
     st->status.response.response_code = code;
@@ -293,7 +402,7 @@ static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
 
 static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_SENSE, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
     int len, slen = 0;
 
     trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
@@ -310,7 +419,8 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
 
 static void usb_uas_queue_read_ready(UASRequest *req)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_READ_READY, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
+                                         req->tag);
 
     trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
     usb_uas_queue_status(req->uas, st, 0);
@@ -318,7 +428,8 @@ static void usb_uas_queue_read_ready(UASRequest *req)
 
 static void usb_uas_queue_write_ready(UASRequest *req)
 {
-    UASStatus *st = usb_uas_alloc_status(UAS_UI_WRITE_READY, req->tag);
+    UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
+                                         req->tag);
 
     trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
     usb_uas_queue_status(req->uas, st, 0);
@@ -381,18 +492,22 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
 {
     UASRequest *req;
 
+    if (uas_using_streams(uas)) {
+        return;
+    }
+
     QTAILQ_FOREACH(req, &uas->requests, next) {
         if (req->active || req->complete) {
             continue;
         }
-        if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain == NULL) {
-            uas->datain = req;
+        if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
+            uas->datain2 = req;
             usb_uas_queue_read_ready(req);
             req->active = true;
             return;
         }
-        if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout == NULL) {
-            uas->dataout = req;
+        if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
+            uas->dataout2 = req;
             usb_uas_queue_write_ready(req);
             req->active = true;
             return;
@@ -417,11 +532,11 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
     UASRequest *req = priv;
     UASDevice *uas = req->uas;
 
-    if (req == uas->datain) {
-        uas->datain = NULL;
+    if (req == uas->datain2) {
+        uas->datain2 = NULL;
     }
-    if (req == uas->dataout) {
-        uas->dataout = NULL;
+    if (req == uas->dataout2) {
+        uas->dataout2 = NULL;
     }
     QTAILQ_REMOVE(&uas->requests, req, next);
     g_free(req);
@@ -522,12 +637,25 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
 {
     UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
     UASRequest *req, *nreq;
+    int i;
 
-    if (uas->status == p) {
-        uas->status = NULL;
+    if (uas->status2 == p) {
+        uas->status2 = NULL;
         qemu_bh_cancel(uas->status_bh);
         return;
     }
+    if (uas_using_streams(uas)) {
+        for (i = 0; i < UAS_MAX_STREAMS; i++) {
+            if (uas->status3[i] == p) {
+                uas->status3[i] = NULL;
+                return;
+            }
+            if (uas->data3[i] == p) {
+                uas->data3[i] = NULL;
+                return;
+            }
+        }
+    }
     QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
         if (req->data == p) {
             req->data = NULL;
@@ -555,9 +683,18 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
                           usb_uas_get_lun(req->lun),
                           req->lun >> 32, req->lun & 0xffffffff);
     QTAILQ_INSERT_TAIL(&uas->requests, req, next);
+    if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
+        req->data = uas->data3[req->tag];
+        req->data_async = true;
+        uas->data3[req->tag] = NULL;
+    }
+
     req->req = scsi_req_new(req->dev, req->tag,
                             usb_uas_get_lun(req->lun),
                             ui->command.cdb, req);
+#if 1
+    scsi_req_print(req->req);
+#endif
     len = scsi_req_enqueue(req->req);
     if (len) {
         req->data_size = len;
@@ -669,12 +806,26 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         }
         break;
     case UAS_PIPE_ID_STATUS:
-        st = QTAILQ_FIRST(&uas->results);
-        if (st == NULL) {
-            assert(uas->status == NULL);
-            uas->status = p;
-            p->status = USB_RET_ASYNC;
-            break;
+        if (p->stream) {
+            QTAILQ_FOREACH(st, &uas->results, next) {
+                if (st->stream == p->stream) {
+                    break;
+                }
+            }
+            if (st == NULL) {
+                assert(uas->status3[p->stream] == NULL);
+                uas->status3[p->stream] = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            }
+        } else {
+            st = QTAILQ_FIRST(&uas->results);
+            if (st == NULL) {
+                assert(uas->status2 == NULL);
+                uas->status2 = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            }
         }
         usb_packet_copy(p, &st->status, st->length);
         QTAILQ_REMOVE(&uas->results, st, next);
@@ -682,11 +833,23 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         break;
     case UAS_PIPE_ID_DATA_IN:
     case UAS_PIPE_ID_DATA_OUT:
-        req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout;
+        if (p->stream) {
+            req = usb_uas_find_request(uas, p->stream);
+        } else {
+            req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
+                ? uas->datain2 : uas->dataout2;
+        }
         if (req == NULL) {
-            fprintf(stderr, "%s: no inflight request\n", __func__);
-            p->status = USB_RET_STALL;
-            break;
+            if (p->stream) {
+                assert(uas->data3[p->stream] == NULL);
+                uas->data3[p->stream] = p;
+                p->status = USB_RET_ASYNC;
+                break;
+            } else {
+                fprintf(stderr, "%s: no inflight request\n", __func__);
+                p->status = USB_RET_STALL;
+                break;
+            }
         }
         scsi_req_ref(req->req);
         req->data = p;
-- 
1.7.9.7

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-02-01 10:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-01 10:51 [Qemu-devel] [PATCH 0/4] sneak preview: usb3 streams Gerd Hoffmann
2013-02-01 10:51 ` [Qemu-devel] [PATCH 1/4] usb: fix endpoint descriptor ordering Gerd Hoffmann
2013-02-01 10:51 ` [Qemu-devel] [PATCH 2/4] [wip] core: usb3 streams Gerd Hoffmann
2013-02-01 10:51 ` [Qemu-devel] [PATCH 3/4] [wip] xhci: " Gerd Hoffmann
2013-02-01 10:51 ` [Qemu-devel] [PATCH 4/4] [wip] uas: " Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).