socsvn commit: r257756 - soc2013/bguan/head/sys/dev/xen/usbfront
bguan at FreeBSD.org
bguan at FreeBSD.org
Fri Sep 27 11:30:52 UTC 2013
Author: bguan
Date: Fri Sep 27 11:30:51 2013
New Revision: 257756
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=257756
Log:
create a thread to deal with USB request queue; get entry from the share ring; other little stuff work
Modified:
soc2013/bguan/head/sys/dev/xen/usbfront/usbfront.c
Modified: soc2013/bguan/head/sys/dev/xen/usbfront/usbfront.c
==============================================================================
--- soc2013/bguan/head/sys/dev/xen/usbfront/usbfront.c Fri Sep 27 10:47:22 2013 (r257755)
+++ soc2013/bguan/head/sys/dev/xen/usbfront/usbfront.c Fri Sep 27 11:30:51 2013 (r257756)
@@ -32,6 +32,7 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@@ -81,18 +82,21 @@
#include "xenbus_if.h"
+#define XENHCI_VENDORID_XEN 0x0001
-static int usbfront_probe(device_t dev);
-static int usbfront_attach(device_t dev);
-static int usbfront_detach(device_t dev);
-static int usbfront_suspend(device_t dev);
-static int usbfront_resume(device_t dev);
-static int talk_to_backend(device_t dev, struct xenhci_softc *sc);
-static int setup_rings(device_t dev, struct xenhci_softc *sc);
-static void destroy_rings(struct xenhci_softc *sc);
-static void xenhci_notify_work(struct xenhci_softc *sc);
-static void xu_intr(void *xsc);
-static int usbfront_connect(device_t dev);
+static int usbfront_probe(device_t dev);
+static int usbfront_attach(device_t dev);
+static int usbfront_detach(device_t dev);
+static int usbfront_suspend(device_t dev);
+static int usbfront_resume(device_t dev);
+static int talk_to_backend(device_t dev, struct xenhci_softc *sc);
+static int setup_rings(device_t dev, struct xenhci_softc *sc);
+static void destroy_rings(struct xenhci_softc *sc);
+static void xenhci_thread(void *arg);
+static void xenhci_notify_work(struct xenhci_softc *sc);
+static void xu_int(void *xsc);
+static int usbfront_connect(device_t dev);
+static void usbfront_free(struct xenhci_softc *sc);
#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT)
@@ -116,7 +120,7 @@
return (ENXIO);
}
-/*
+/**
* Setup supplies the backend dir, virtual device. We place an event
* channel and shared frame entries. We watch backend to wait if it's
* ok.
@@ -192,11 +196,20 @@
sc->xb_dev = dev;
sc->rh_numports = num_ports;
sc->sc_noport = num_ports;
- sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(dev));
+
+ switch (pci_get_vendor(dev)) {
+ case XENHCI_VENDORID_XEN:
+ sprintf(sc->sc_vendor, "Xen Device");
+ break;
+ default:
+ DPRINTK("host controller vendor: 0x%x\n", pci_get_vendor(dev));
+ sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(dev));
+ }
for (i = 0; i < USB_URB_RING_SIZE; i++) {
sc->shadow[i].req.id = i + 1;
- sc->shadow[i].urb = NULL;
+ //sc->shadow[i].urb = NULL;
+ sc->shadow[i].xfer = NULL;
}
sc->shadow[USB_URB_RING_SIZE-1].req.id = 0x0fff;
@@ -250,12 +263,21 @@
DPRINTK("usbfront_detach: %s removed\n", xenbus_get_node(dev));
//TODO
- //usbfront_free(sc);
+ usbfront_free(sc);
+
//mtx_destroy(&sc->xb_io_lock);
+
+ xenhci_uninit(sc);
return 0;
}
+static void
+usbfront_free(struct xenhci_softc *sc)
+{
+ destroy_rings(sc);
+}
+
static int
usbfront_connect(device_t dev)
@@ -271,18 +293,14 @@
//hcd = info_to_hcd(info);
//snprintf(name, TASK_COMM_LEN, "xenhcd.%d", sc->sc_bus.busnum);
-
err = talk_to_backend(dev, sc);
if (err)
return err;
- //sc->kthread = kthread_run(xenhcd_schedule, sc, name);
- //if (IS_ERR(sc->kthread)) {
- // err = PTR_ERR(sc->kthread);
- // sc->kthread = NULL;
- // xenbus_dev_fatal(dev, err, "Error creating thread");
- // return err;
- //}
+ //err = kproc_create(xenhci_thread, sc, NULL, 0, 0, name);
+ err = kproc_create(xenhci_thread, sc, NULL, 0, 0, "xenhcd");
+ if (err)
+ return err;
/* prepare ring for hotplug notification */
for (idx = 0, i = 0; i < USB_CONN_RING_SIZE; i++) {
@@ -372,7 +390,9 @@
}
}
-/* Common code used when first setting up, and when resuming. */
+/**
+ * Common code used when first setting up, and when resuming.
+ */
static int
talk_to_backend(device_t dev, struct xenhci_softc *sc)
{
@@ -459,7 +479,9 @@
sc->conn_ring.sring = NULL;
}
-/* Create shared ring, alloc event channel. */
+/**
+ * Create shared ring, alloc event channel.
+ */
static int
setup_rings(device_t dev, struct xenhci_softc *sc)
{
@@ -484,7 +506,6 @@
//sc->urb_ring.sring = NULL;
goto fail;
}
- sc->urb_ring_ref = err;
conn_sring = (usbif_conn_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
if (!conn_sring) {
@@ -500,17 +521,15 @@
//sc->conn_ring.sring = NULL;
goto fail;
}
- sc->conn_ring_ref = err;
err = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(dev),
- "xu", xu_intr, sc, INTR_TYPE_BIO | INTR_MPSAFE, &sc->irq);
+ "xu", xu_int, sc, INTR_TYPE_BIO | INTR_MPSAFE, &sc->irq);
if (err) {
xenbus_dev_fatal(dev, err,
"bind_listening_port_to_irqhandler");
goto fail;
}
- sc->irq = err;
return 0;
fail:
@@ -518,24 +537,228 @@
return err;
}
+////////////////////////////////////////////////
+static inline int get_id_from_freelist(struct xenhci_softc *sc)
+{
+ unsigned long free;
+ free = sc->shadow_free;
+ //BUG_ON(free >= USB_URB_RING_SIZE); //????
+ sc->shadow_free = sc->shadow[free].req.id;
+ sc->shadow[free].req.id = (unsigned int)0x0fff; /* debug */
+ return free;
+}
+
+static inline void add_id_to_freelist(struct xenhci_softc *sc,
+ unsigned long id)
+{
+ sc->shadow[id].req.id = sc->shadow_free;
+ //sc->shadow[id].urb = NULL;
+ sc->shadow[id].xfer = NULL;
+ sc->shadow_free = id;
+}
+
+static void xenhci_gnttab_done(struct usb_shadow *shadow)
+{
+ int nr_segs = 0;
+ int i;
+
+ nr_segs = shadow->req.nr_buffer_segs;
+
+ //???
+ //if (usb_pipeisoc(shadow->req.pipe))
+ nr_segs += shadow->req.u.isoc.nr_frame_desc_segs;
+
+ for (i = 0; i < nr_segs; i++)
+ gnttab_end_foreign_access(shadow->req.seg[i].gref, 0UL);
+
+ shadow->req.nr_buffer_segs = 0;
+ shadow->req.u.isoc.nr_frame_desc_segs = 0;
+}
+
+/*
+static void xenhci_giveback_urb(struct usbfront_info *info, struct urb *urb, int status)
+}
+*/
+
+
+/**
+ * Get response data from the backend
+ */
+static int
+xenhci_xfer_request_done(struct xenhci_softc *sc)
+{
+ usbif_urb_response_t *resp;
+ //struct urb *urb;
+ struct usb_xfer *xfer;
+
+ RING_IDX i, rp;
+ uint16_t id;
+ int more_req = 0;
+
+ mtx_lock(&sc->lock);
+ rp = sc->urb_ring.sring->rsp_prod;
+ //rmb();??? /* ensure we see queued responses up to "rp" */
+
+ for (i = sc->urb_ring.rsp_cons; i != rp; i++) {
+ resp = RING_GET_RESPONSE(&sc->urb_ring, i);
+ id = resp->id;
+
+ if (likely(usbif_pipesubmit(sc->shadow[id].req.pipe))) {
+ xenhci_gnttab_done(&sc->shadow[id]);
+ //urb = sc->shadow[id].urb;
+ xfer = sc->shadow[id].xfer;
+ //barrier();
+ //if (likely(urb)) {
+
+ //if (urb) {
+ if (xfer) {
+ //TODO
+ //xfer->
+
+ //urb->actual_length = resp->actual_length;
+ //urb->error_count = resp->error_count;
+ //urb->start_frame = resp->start_frame;
+
+ //barrier();
+ //xenhci_giveback_urb(sc, urb, resp->status); //???
+ }
+ }
+
+ add_id_to_freelist(sc, id);
+ }
+ sc->urb_ring.rsp_cons = i;
+
+ if (i != sc->urb_ring.req_prod_pvt)
+ RING_FINAL_CHECK_FOR_RESPONSES(&sc->urb_ring, more_req);
+ else
+ sc->urb_ring.sring->rsp_event = i + 1;
+
+ mtx_unlock(&sc->lock);
+
+ //cond_resched();
+
+ return more_req;
+}
+
+static int
+xenhci_conn_notify(struct xenhci_softc *sc)
+{
+ usbif_conn_response_t *res;
+ usbif_conn_request_t *req;
+ RING_IDX rc, rp;
+ uint16_t id;
+ uint8_t portnum, speed;
+ int more_req = 0;
+ int notify;
+ int port_changed = 0;
+ //unsigned long flags;
+
+ //spin_lock_irqsave(&sc->lock, flags);
+ mtx_lock(&sc->lock);
+
+ rc = sc->conn_ring.rsp_cons;
+ rp = sc->conn_ring.sring->rsp_prod;
+ rmb(); /* ensure we see queued responses up to "rp" */
+
+ while (rc != rp) {
+ res = RING_GET_RESPONSE(&sc->conn_ring, rc);
+ id = res->id;
+ portnum = res->portnum;
+ speed = res->speed;
+ sc->conn_ring.rsp_cons = ++rc;
+
+ //rhport_connect(sc, portnum, speed);
+ sc->ports[portnum-1].c_connection = 1;
+ if (sc->ports[portnum-1].c_connection)
+ port_changed = 1;
+
+ //barrier();
+
+ req = RING_GET_REQUEST(&sc->conn_ring, sc->conn_ring.req_prod_pvt);
+ req->id = id;
+ sc->conn_ring.req_prod_pvt++;
+ }
+
+ if (rc != sc->conn_ring.req_prod_pvt)
+ RING_FINAL_CHECK_FOR_RESPONSES(&sc->conn_ring, more_req);
+ else
+ sc->conn_ring.sring->rsp_event = rc + 1;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->conn_ring, notify);
+ if (notify)
+ notify_remote_via_irq(sc->irq);
+
+ //spin_unlock_irqrestore(&sc->lock, flags);
+ mtx_unlock(&sc->lock);
+
+ if (port_changed) {
+ //usb_hcd_poll_rh_status(sc_to_hcd(sc));
+ printf("[gbtest]usb_hcd_poll_rh_status(sc_to_hcd(sc))???????????\n");
+ }
+ //cond_resched();
+
+ return more_req;
+}
+
+/**
+ * A thread to deal with the USB req queue.
+ * Get the reply data from share ring.
+ */
+static void
+xenhci_thread(void *arg)
+{
+ struct xenhci_softc *sc = (struct xenhci_softc *) arg;
+
+ for (;;) {
+ while(sc->waiting_resp == 0) {};
+ sc->waiting_resp = 0;
+
+ if (xenhci_xfer_request_done(sc))
+ sc->waiting_resp = 1;
+
+ if (xenhci_conn_notify(sc))
+ sc->waiting_resp = 1;
+
+/* //mtx_lock(&xs.watch_events_lock);
+ //mtx_unlock(&xs.watch_events_lock);
+
+ //???
+ wait_event_interruptible(
+ info->wq,
+ info->waiting_resp || kthread_should_stop());
+ info->waiting_resp = 0;
+ smp_mb();
+
+ if (xenhci_urb_request_done(sc))
+ info->waiting_resp = 1;
+
+ if (xenhci_conn_notify(sc))
+ info->waiting_resp = 1;
+
+*/ //???
+ }
+}
+
static void
xenhci_notify_work(struct xenhci_softc *sc)
{
printf("[gbdebug-pvusb]xenhci_notify_work()\n");
sc->waiting_resp = 1;
- wakeup(&sc->wait_taskqueue);
+ wakeup(&sc->wait_taskqueue);//????
}
static void
-xu_intr(void *xsc)
+xu_int(void *xsc)
{
- printf("[gbdebug-pvusb]xu_intr()\n");
+ printf("[gbdebug-pvusb]xu_int()\n");
struct xenhci_softc *sc = xsc;
xenhci_notify_work(sc);
}
-/* ** Driver registration ** */
+/**
+ * ** Driver registration **
+ */
static device_method_t usbfront_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, usbfront_probe),
More information about the svn-soc-all
mailing list