Date: Sun, 28 Jul 2013 17:24:11 GMT From: bguan@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r255269 - soc2013/bguan/head/sys/dev/xen/usbfront Message-ID: <201307281724.r6SHOBQ6088349@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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[] = {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307281724.r6SHOBQ6088349>
