socsvn commit: r255269 - soc2013/bguan/head/sys/dev/xen/usbfront
bguan at FreeBSD.org
bguan at FreeBSD.org
Sun Jul 28 17:24:12 UTC 2013
Author: bguan
Date: Sun Jul 28 17:24:11 2013
New Revision: 255269
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=255269
Log:
debug method usbfront_connect() in usbfront
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 Sun Jul 28 16:56:31 2013 (r255268)
+++ soc2013/bguan/head/sys/dev/xen/usbfront/usbfront.c Sun Jul 28 17:24:11 2013 (r255269)
@@ -88,7 +88,14 @@
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);
+#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT)
/**
* Entry point to this code when a new device is created. Allocate the basic
@@ -168,6 +175,9 @@
printf("[gbdebug-pvusb]device_add_child() done!\n");
device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+ /* usbfront IO lock TODO?? */
+ mtx_init(&sc->lock, "usbfront i/o lock", NULL, MTX_DEF);
+
/* xen shared ring related stuff*/
err = xs_scanf(XST_NIL, backend_path, "num-ports", NULL, "%d", &num_ports);
if (err) {
@@ -234,8 +244,9 @@
{
printf("[gbdebug-pvusb]usbfront_detach\n");
- //struct xenhci_softc *sc = device_get_softc(dev);
+ struct xenhci_softc *sc = device_get_softc(dev);
+ mtx_destroy(&sc->lock);
DPRINTK("usbfront_remove: %s removed\n", xenbus_get_node(dev));
//TODO
@@ -245,6 +256,59 @@
return 0;
}
+
+static int
+usbfront_connect(device_t dev)
+{
+ struct xenhci_softc *sc = device_get_softc(dev);
+ //struct usbfront_info *info = dev->dev.driver_data;
+
+ usbif_conn_request_t *req;
+ int i, idx, err;
+ int notify;
+ //char name[TASK_COMM_LEN];
+ //struct usb_hcd *hcd;
+
+ //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;
+ //}
+
+ /* prepare ring for hotplug notification */
+ for (idx = 0, i = 0; i < USB_CONN_RING_SIZE; i++) {
+ req = RING_GET_REQUEST(&sc->conn_ring, idx);
+ req->id = idx;
+ idx++;
+ }
+ sc->conn_ring.req_prod_pvt = idx;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->conn_ring, notify);
+ if (notify)
+ notify_remote_via_irq(sc->irq);
+
+ return 0;
+}
+
+static void
+usbfront_disconnect(device_t dev)
+{
+ xenbus_set_state(dev, XenbusStateClosing);
+
+ DPRINTK("xusb_closing: %s removed\n", xenbus_get_node(dev));
+
+ xenbus_set_state(dev, XenbusStateClosed);
+}
+
/**
* Callback received when the backend's state changes.
*/
@@ -258,39 +322,204 @@
//DPRINTK("backend_state=%d\n", backend_state);
switch (backend_state) {
- case XenbusStateUnknown:
+ case XenbusStateInitialised:
case XenbusStateInitialising:
+ case XenbusStateConnected:
case XenbusStateReconfigured:
case XenbusStateReconfiguring:
+ case XenbusStateUnknown:
case XenbusStateClosed:
break;
case XenbusStateInitWait:
- case XenbusStateInitialised:
- //TODO
- //usbfront_initialize(sc);
- printf("[gbdebug-pvusb]usbfront_backend_changed: initialize(sc)\n");
+ printf("[gbdebug-pvusb]usbfront_backend_changed: XenbusStateInitWait\n");
+ if (xenbus_get_state(dev) != XenbusStateInitialising)
+ break;
+ //if (usbfront_connect(sc) != 0)
+ if (usbfront_connect(dev) != 0) {
+ printf("[gbdebug-pvusb]usbfront_connect(dev) error.\n");
+ break;
+ }
+ xenbus_set_state(dev, XenbusStateConnected); //???
+ printf("[gbdebug-pvusb]xenbus_set_state finished!\n");
break;
- case XenbusStateConnected:
- //TODO
- //usbfront_initialize(sc);
- //usbfront_connect(sc);
- printf("[gbdebug-pvusb]usbfront_backend_changed: initialize(sc);connect(sc)\n");
+ case XenbusStateClosing:
+ usbfront_disconnect(dev);
break;
- case XenbusStateClosing:
- //if (sc->users > 0) {
- // xenbus_dev_error(dev, -EBUSY, "Device in use; refusing to close");
- //} else {
- //TODO
- //usbfront_closing(dev);
- printf("[gbdebug-pvusb]usbfront_backend_changed: closing(dev)\n");
- //}
- break;
+ default:
+ xenbus_dev_fatal(dev, EINVAL, "get state %d at usb frontend",
+ backend_state);
+ break;
}
+ printf("[gbdebug-pvusb]usbfront_backend_changed finished!\n");
}
+/* Common code used when first setting up, and when resuming. */
+static int
+talk_to_backend(device_t dev, struct xenhci_softc *sc)
+{
+ const char *message;
+ struct xs_transaction xst;
+ const char *node = xenbus_get_node(dev);
+ int err;
+
+ printf("[gbdebug-pvusb]takl_to_backend()\n");
+ /* Create shared ring, alloc event channel. */
+ err = setup_rings(dev, sc);
+ if (err)
+ goto out;
+
+again:
+ err = xs_transaction_start(&xst);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_ring;
+ }
+
+ err = xs_printf(xst, node, "urb-ring-ref", "%u",
+ sc->urb_ring_ref);
+ if (err) {
+ message = "writing urb-ring-ref";
+ goto abort_transaction;
+ }
+
+ err = xs_printf(xst, node, "conn-ring-ref", "%u",
+ sc->conn_ring_ref);
+ if (err) {
+ message = "writing conn-ring-ref";
+ goto abort_transaction;
+ }
+
+ err = xs_printf(xst, node, "event-channel", "%u",
+ irq_to_evtchn_port(sc->irq));
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xs_transaction_end(xst, 0);
+ if (err) {
+ if (err == EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_ring;
+ }
+
+ return 0;
+
+abort_transaction:
+ xs_transaction_end(xst, 1);
+ xenbus_dev_fatal(dev, err, "%s", message);
+
+destroy_ring:
+ destroy_rings(sc);
+
+out:
+ return err;
+}
+
+static void
+destroy_rings(struct xenhci_softc *sc)
+{
+ if (sc->irq)
+ unbind_from_irqhandler(sc->irq);
+ sc->irq = 0;
+
+ if (sc->urb_ring_ref != GRANT_INVALID_REF) {
+ /* This API frees the associated ??TODO. */
+ gnttab_end_foreign_access(sc->urb_ring_ref,
+ (void *)sc->urb_ring.sring);
+ sc->urb_ring_ref = GRANT_INVALID_REF;
+ }
+ sc->urb_ring.sring = NULL;
+
+ if (sc->conn_ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(sc->conn_ring_ref,
+ (void *)sc->conn_ring.sring);
+ sc->conn_ring_ref = GRANT_INVALID_REF;
+ }
+ sc->conn_ring.sring = NULL;
+}
+
+/* Create shared ring, alloc event channel. */
+static int
+setup_rings(device_t dev, struct xenhci_softc *sc)
+{
+ usbif_urb_sring_t *urb_sring;
+ usbif_conn_sring_t *conn_sring;
+ int otherend_id = 0;
+ int err;
+
+ printf("[gbdebug-pvusb]setup_rings()\n");
+ sc->urb_ring_ref = GRANT_INVALID_REF;
+ sc->conn_ring_ref = GRANT_INVALID_REF;
+
+ //urb_sring = (usbif_urb_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
+ urb_sring = (usbif_urb_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (!urb_sring) {
+ xenbus_dev_fatal(dev, ENOMEM, "allocating urb ring");
+ return ENOMEM;
+ }
+ SHARED_RING_INIT(urb_sring);
+ FRONT_RING_INIT(&sc->urb_ring, urb_sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(urb_sring), &sc->urb_ring_ref);
+ if (err < 0) {
+ //free_page((unsigned long)urb_sring);//TODO
+ //sc->urb_ring.sring = NULL;
+ goto fail;
+ }
+ sc->urb_ring_ref = err;
+
+ //conn_sring = (usbif_conn_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
+ conn_sring = (usbif_conn_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (!conn_sring) {
+ xenbus_dev_fatal(dev, ENOMEM, "allocating conn ring");
+ return ENOMEM;
+ }
+ SHARED_RING_INIT(conn_sring);
+ FRONT_RING_INIT(&sc->conn_ring, conn_sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(conn_sring), &sc->conn_ring_ref);
+ if (err < 0) {
+ //free_page((unsigned long)conn_sring);//TODO
+ //sc->conn_ring.sring = NULL;
+ goto fail;
+ }
+ sc->conn_ring_ref = err;
+
+ otherend_id = xenbus_get_otherend_id(dev);
+ err = bind_listening_port_to_irqhandler(otherend_id, "xu", xu_intr,
+ sc, INTR_TYPE_BIO | INTR_MPSAFE, &sc->irq);
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err,
+ "bind_listening_port_to_irqhandler");
+ goto fail;
+ }
+ sc->irq = err;
+
+ return 0;
+fail:
+ destroy_rings(sc);
+ return err;
+}
+
+static void
+xenhci_notify_work(struct xenhci_softc *sc)
+{
+ sc->waiting_resp = 1;
+ wakeup(&sc->wait_taskqueue);
+}
+
+static void
+xu_intr(void *xsc)
+{
+ struct xenhci_softc *sc = xsc;
+ xenhci_notify_work(sc);
+}
+
/* ** Driver registration ** */
static device_method_t usbfront_methods[] = {
More information about the svn-soc-all
mailing list