Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 27 Sep 2013 11:30:51 GMT
From:      bguan@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r257756 - soc2013/bguan/head/sys/dev/xen/usbfront
Message-ID:  <201309271130.r8RBUph5016468@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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), 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309271130.r8RBUph5016468>