[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] PVUSB: Fixes and updates
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1254901320 -3600 # Node ID 498ac445a2a9bb3e8e01f1bca46fc22e49ad23cb # Parent 7d57b5843b6587d2f220db0e43cb20b85de9baf7 PVUSB: Fixes and updates - xenbus state flow changed. Whole of the flow is changed to be like netback/netfront. Reconfiguring/Reconfiguring are removed. - New RING for hotplug notification added. - USBIF_MAX_SEGMENTS_PER_REQUEST value is changed (10) to (16). According to this change, RING_SIZE is decreased from 32 to 16. This affects the performance. My flash drive's read throughput was dropped from 29MB/s to 18MB/s in the linux environment. However, Windows guest send urb with 64kB buffer(64KB = 4kB * 16). This is required. - New port-setting interface xenbus_watch_path2 is added to usbback, port-setting interface is moved from sysfs to xenstore. Now, the port-rule is directly written to xenstore entry. Example. # xenstore-write /local/domain/0/backend/vusb/1/0/port/1 "2-1" (adding physical bus 2-1 to vusb-1-0 port 1) - urb dequeue function completed. usbfront send unlink-request to usbback, and can cancel the urb that is submitted in the backend. - New USB Spec version (USB1.1/USB2.0) selection support. usbfront can act as both USB1.1 and USB2.0 virtual host controller according to the xenstore entry key "usb-ver". - experimental bus_suspend/bus_resume added to usbfront. - various cleanups, bugfix, refactoring and codestyle-fix. Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx> --- drivers/xen/usbback/interface.c | 135 ++++++--- drivers/xen/usbback/usbback.c | 227 ++++++++++------ drivers/xen/usbback/usbback.h | 89 +++--- drivers/xen/usbback/usbstub.c | 498 +++++++++++++----------------------- drivers/xen/usbback/xenbus.c | 257 +++++++++++------- drivers/xen/usbfront/usbfront-dbg.c | 5 drivers/xen/usbfront/usbfront-hcd.c | 130 ++------- drivers/xen/usbfront/usbfront-hub.c | 131 +++------ drivers/xen/usbfront/usbfront-q.c | 279 ++++++++++++++------ drivers/xen/usbfront/usbfront.h | 97 +++---- drivers/xen/usbfront/xenbus.c | 289 ++++++++++++-------- include/xen/interface/io/usbif.h | 46 ++- 12 files changed, 1174 insertions(+), 1009 deletions(-) diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/interface.c --- a/drivers/xen/usbback/interface.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbback/interface.c Wed Oct 07 08:42:00 2009 +0100 @@ -48,7 +48,7 @@ static LIST_HEAD(usbif_list); static LIST_HEAD(usbif_list); static DEFINE_SPINLOCK(usbif_list_lock); -usbif_t *find_usbif(int dom_id, int dev_id) +usbif_t *find_usbif(domid_t domid, unsigned int handle) { usbif_t *usbif; int found = 0; @@ -56,8 +56,8 @@ usbif_t *find_usbif(int dom_id, int dev_ spin_lock_irqsave(&usbif_list_lock, flags); list_for_each_entry(usbif, &usbif_list, usbif_list) { - if (usbif->domid == dom_id - && usbif->handle == dev_id) { + if (usbif->domid == domid + && usbif->handle == handle) { found = 1; break; } @@ -82,16 +82,16 @@ usbif_t *usbif_alloc(domid_t domid, unsi usbif->domid = domid; usbif->handle = handle; - spin_lock_init(&usbif->ring_lock); + spin_lock_init(&usbif->urb_ring_lock); + spin_lock_init(&usbif->conn_ring_lock); atomic_set(&usbif->refcnt, 0); init_waitqueue_head(&usbif->wq); init_waitqueue_head(&usbif->waiting_to_free); - spin_lock_init(&usbif->plug_lock); - INIT_LIST_HEAD(&usbif->plugged_devices); + spin_lock_init(&usbif->stub_lock); + INIT_LIST_HEAD(&usbif->stub_list); spin_lock_init(&usbif->addr_lock); - for (i = 0; i < USB_DEV_ADDR_SIZE; i++) { + for (i = 0; i < USB_DEV_ADDR_SIZE; i++) usbif->addr_table[i] = NULL; - } spin_lock_irqsave(&usbif_list_lock, flags); list_add(&usbif->usbif_list, &usbif_list); @@ -100,70 +100,109 @@ usbif_t *usbif_alloc(domid_t domid, unsi return usbif; } -static int map_frontend_page(usbif_t *usbif, unsigned long shared_page) +static int map_frontend_pages(usbif_t *usbif, + grant_ref_t urb_ring_ref, + grant_ref_t conn_ring_ref) { struct gnttab_map_grant_ref op; - gnttab_set_map_op(&op, (unsigned long)usbif->ring_area->addr, - GNTMAP_host_map, shared_page, usbif->domid); + gnttab_set_map_op(&op, (unsigned long)usbif->urb_ring_area->addr, + GNTMAP_host_map, urb_ring_ref, usbif->domid); if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) BUG(); if (op.status) { - printk(KERN_ERR "grant table operation failure\n"); + printk(KERN_ERR "grant table failure mapping urb_ring_ref\n"); return op.status; } - usbif->shmem_ref = shared_page; - usbif->shmem_handle = op.handle; + usbif->urb_shmem_ref = urb_ring_ref; + usbif->urb_shmem_handle = op.handle; + + gnttab_set_map_op(&op, (unsigned long)usbif->conn_ring_area->addr, + GNTMAP_host_map, conn_ring_ref, usbif->domid); + + if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) + BUG(); + + if (op.status) { + struct gnttab_unmap_grant_ref unop; + gnttab_set_unmap_op(&unop, + (unsigned long) usbif->urb_ring_area->addr, + GNTMAP_host_map, usbif->urb_shmem_handle); + VOID(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, + 1)); + printk(KERN_ERR "grant table failure mapping conn_ring_ref\n"); + return op.status; + } + + usbif->conn_shmem_ref = conn_ring_ref; + usbif->conn_shmem_handle = op.handle; return 0; } -static void unmap_frontend_page(usbif_t *usbif) +static void unmap_frontend_pages(usbif_t *usbif) { struct gnttab_unmap_grant_ref op; - gnttab_set_unmap_op(&op, (unsigned long)usbif->ring_area->addr, - GNTMAP_host_map, usbif->shmem_handle); + gnttab_set_unmap_op(&op, (unsigned long)usbif->urb_ring_area->addr, + GNTMAP_host_map, usbif->urb_shmem_handle); if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) BUG(); -} - -int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn) -{ - int err; - usbif_sring_t *sring; + + gnttab_set_unmap_op(&op, (unsigned long)usbif->conn_ring_area->addr, + GNTMAP_host_map, usbif->conn_shmem_handle); + + if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) + BUG(); +} + +int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref, + unsigned long conn_ring_ref, unsigned int evtchn) +{ + int err = -ENOMEM; + + usbif_urb_sring_t *urb_sring; + usbif_conn_sring_t *conn_sring; if (usbif->irq) return 0; - if ((usbif->ring_area = alloc_vm_area(PAGE_SIZE)) == NULL) - return -ENOMEM; - - err = map_frontend_page(usbif, shared_page); - if (err) { - free_vm_area(usbif->ring_area); + if ((usbif->urb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL) return err; - } - - sring = (usbif_sring_t *) usbif->ring_area->addr; - BACK_RING_INIT(&usbif->ring, sring, PAGE_SIZE); + if ((usbif->conn_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL) + goto fail_alloc; + + err = map_frontend_pages(usbif, urb_ring_ref, conn_ring_ref); + if (err) + goto fail_map; err = bind_interdomain_evtchn_to_irqhandler( - usbif->domid, evtchn, usbbk_be_int, 0, "usbif-backend", usbif); + usbif->domid, evtchn, usbbk_be_int, 0, + "usbif-backend", usbif); if (err < 0) - { - unmap_frontend_page(usbif); - free_vm_area(usbif->ring_area); - usbif->ring.sring = NULL; - return err; - } + goto fail_evtchn; usbif->irq = err; + urb_sring = (usbif_urb_sring_t *) usbif->urb_ring_area->addr; + BACK_RING_INIT(&usbif->urb_ring, urb_sring, PAGE_SIZE); + + conn_sring = (usbif_conn_sring_t *) usbif->conn_ring_area->addr; + BACK_RING_INIT(&usbif->conn_ring, conn_sring, PAGE_SIZE); + return 0; + +fail_evtchn: + unmap_frontend_pages(usbif); +fail_map: + free_vm_area(usbif->conn_ring_area); +fail_alloc: + free_vm_area(usbif->urb_ring_area); + + return err; } void usbif_disconnect(usbif_t *usbif) @@ -176,12 +215,12 @@ void usbif_disconnect(usbif_t *usbif) usbif->xenusbd = NULL; } - spin_lock_irqsave(&usbif->plug_lock, flags); - list_for_each_entry_safe(stub, tmp, &usbif->plugged_devices, plugged_list) { + spin_lock_irqsave(&usbif->stub_lock, flags); + list_for_each_entry_safe(stub, tmp, &usbif->stub_list, dev_list) { usbbk_unlink_urbs(stub); detach_device_without_lock(usbif, stub); } - spin_unlock_irqrestore(&usbif->plug_lock, flags); + spin_unlock_irqrestore(&usbif->stub_lock, flags); wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0); @@ -190,10 +229,12 @@ void usbif_disconnect(usbif_t *usbif) usbif->irq = 0; } - if (usbif->ring.sring) { - unmap_frontend_page(usbif); - free_vm_area(usbif->ring_area); - usbif->ring.sring = NULL; + if (usbif->urb_ring.sring) { + unmap_frontend_pages(usbif); + free_vm_area(usbif->urb_ring_area); + free_vm_area(usbif->conn_ring_area); + usbif->urb_ring.sring = NULL; + usbif->conn_ring.sring = NULL; } } diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbback.c --- a/drivers/xen/usbback/usbback.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbback/usbback.c Wed Oct 07 08:42:00 2009 +0100 @@ -107,7 +107,7 @@ static inline unsigned long vaddr(pendin #define pending_handle(_req, _seg) \ (pending_grant_handles[vaddr_pagenr(_req, _seg)]) -static pending_req_t* alloc_req(void) +static pending_req_t *alloc_req(void) { pending_req_t *req = NULL; unsigned long flags; @@ -222,7 +222,7 @@ static void copy_pages_to_buff(void *buf } } -static int usbbk_alloc_urb(usbif_request_t *req, pending_req_t *pending_req) +static int usbbk_alloc_urb(usbif_urb_request_t *req, pending_req_t *pending_req) { int ret; @@ -298,21 +298,21 @@ static void usbbk_do_response(pending_re int32_t actual_length, int32_t error_count, uint16_t start_frame) { usbif_t *usbif = pending_req->usbif; - usbif_response_t *ring_res; + usbif_urb_response_t *res; unsigned long flags; int notify; - spin_lock_irqsave(&usbif->ring_lock, flags); - ring_res = RING_GET_RESPONSE(&usbif->ring, usbif->ring.rsp_prod_pvt); - ring_res->id = pending_req->id; - ring_res->status = status; - ring_res->actual_length = actual_length; - ring_res->error_count = error_count; - ring_res->start_frame = start_frame; - usbif->ring.rsp_prod_pvt++; - barrier(); - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->ring, notify); - spin_unlock_irqrestore(&usbif->ring_lock, flags); + spin_lock_irqsave(&usbif->urb_ring_lock, flags); + res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); + res->id = pending_req->id; + res->status = status; + res->actual_length = actual_length; + res->error_count = error_count; + res->start_frame = start_frame; + usbif->urb_ring.rsp_prod_pvt++; + barrier(); + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); + spin_unlock_irqrestore(&usbif->urb_ring_lock, flags); if (notify) notify_remote_via_irq(usbif->irq); @@ -346,7 +346,7 @@ static void usbbk_urb_complete(struct ur } static int usbbk_gnttab_map(usbif_t *usbif, - usbif_request_t *req, pending_req_t *pending_req) + usbif_urb_request_t *req, pending_req_t *pending_req) { int i, ret; unsigned int nr_segs; @@ -434,7 +434,7 @@ fail: return ret; } -static void usbbk_init_urb(usbif_request_t *req, pending_req_t *pending_req) +static void usbbk_init_urb(usbif_urb_request_t *req, pending_req_t *pending_req) { unsigned int pipe; struct usb_device *udev = pending_req->stub->udev; @@ -671,14 +671,14 @@ struct usbstub *find_attached_device(usb int found = 0; unsigned long flags; - spin_lock_irqsave(&usbif->plug_lock, flags); - list_for_each_entry(stub, &usbif->plugged_devices, plugged_list) { - if (stub->id->portnum == portnum) { + spin_lock_irqsave(&usbif->stub_lock, flags); + list_for_each_entry(stub, &usbif->stub_list, dev_list) { + if (stub->portid->portnum == portnum) { found = 1; break; } } - spin_unlock_irqrestore(&usbif->plug_lock, flags); + spin_unlock_irqrestore(&usbif->stub_lock, flags); if (found) return stub; @@ -686,7 +686,47 @@ struct usbstub *find_attached_device(usb return NULL; } -static int check_and_submit_special_ctrlreq(usbif_t *usbif, usbif_request_t *req, pending_req_t *pending_req) +static void process_unlink_req(usbif_t *usbif, + usbif_urb_request_t *req, pending_req_t *pending_req) +{ + pending_req_t *unlink_req = NULL; + int devnum; + int ret = 0; + unsigned long flags; + + devnum = usb_pipedevice(req->pipe); + if (unlikely(devnum == 0)) { + pending_req->stub = find_attached_device(usbif, usbif_pipeportnum(req->pipe)); + if (unlikely(!pending_req->stub)) { + ret = -ENODEV; + goto fail_response; + } + } else { + if (unlikely(!usbif->addr_table[devnum])) { + ret = -ENODEV; + goto fail_response; + } + pending_req->stub = usbif->addr_table[devnum]; + } + + spin_lock_irqsave(&pending_req->stub->submitting_lock, flags); + list_for_each_entry(unlink_req, &pending_req->stub->submitting_list, urb_list) { + if (unlink_req->id == req->u.unlink.unlink_id) { + ret = usb_unlink_urb(unlink_req->urb); + break; + } + } + spin_unlock_irqrestore(&pending_req->stub->submitting_lock, flags); + +fail_response: + usbbk_do_response(pending_req, ret, 0, 0, 0); + usbif_put(usbif); + free_req(pending_req); + return; +} + +static int check_and_submit_special_ctrlreq(usbif_t *usbif, + usbif_urb_request_t *req, pending_req_t *pending_req) { int devnum; struct usbstub *stub = NULL; @@ -824,7 +864,7 @@ fail_response: } static void dispatch_request_to_pending_reqs(usbif_t *usbif, - usbif_request_t *req, + usbif_urb_request_t *req, pending_req_t *pending_req) { int ret; @@ -834,17 +874,13 @@ static void dispatch_request_to_pending_ barrier(); - /* - * TODO: - * receive unlink request and cancel the urb in backend - */ -#if 0 - if (unlikely(usb_pipeunlink(req->pipe))) { - - } -#endif - usbif_get(usbif); + + /* unlink request */ + if (unlikely(usbif_pipeunlink(req->pipe))) { + process_unlink_req(usbif, req, pending_req); + return; + } if (usb_pipecontrol(req->pipe)) { if (check_and_submit_special_ctrlreq(usbif, req, pending_req)) @@ -927,18 +963,18 @@ fail_response: static int usbbk_start_submit_urb(usbif_t *usbif) { - usbif_back_ring_t *usb_ring = &usbif->ring; - usbif_request_t *ring_req; + usbif_urb_back_ring_t *urb_ring = &usbif->urb_ring; + usbif_urb_request_t *req; pending_req_t *pending_req; RING_IDX rc, rp; int more_to_do = 0; - rc = usb_ring->req_cons; - rp = usb_ring->sring->req_prod; + rc = urb_ring->req_cons; + rp = urb_ring->sring->req_prod; rmb(); while (rc != rp) { - if (RING_REQUEST_CONS_OVERFLOW(usb_ring, rc)) { + if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) { printk(KERN_WARNING "RING_REQUEST_CONS_OVERFLOW\n"); break; } @@ -949,73 +985,100 @@ static int usbbk_start_submit_urb(usbif_ break; } - ring_req = RING_GET_REQUEST(usb_ring, rc); - usb_ring->req_cons = ++rc; - - dispatch_request_to_pending_reqs(usbif, ring_req, + req = RING_GET_REQUEST(urb_ring, rc); + urb_ring->req_cons = ++rc; + + dispatch_request_to_pending_reqs(usbif, req, pending_req); } - RING_FINAL_CHECK_FOR_REQUESTS(&usbif->ring, more_to_do); + RING_FINAL_CHECK_FOR_REQUESTS(&usbif->urb_ring, more_to_do); cond_resched(); return more_to_do; } +void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed) +{ + usbif_conn_back_ring_t *ring = &usbif->conn_ring; + usbif_conn_request_t *req; + usbif_conn_response_t *res; + unsigned long flags; + u16 id; + int notify; + + spin_lock_irqsave(&usbif->conn_ring_lock, flags); + + req = RING_GET_REQUEST(ring, ring->req_cons);; + id = req->id; + ring->req_cons++; + ring->sring->req_event = ring->req_cons + 1; + + res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); + res->id = id; + res->portnum = portnum; + res->speed = speed; + ring->rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); + + spin_unlock_irqrestore(&usbif->conn_ring_lock, flags); + + if (notify) + notify_remote_via_irq(usbif->irq); +} + int usbbk_schedule(void *arg) { - usbif_t *usbif = (usbif_t *)arg; - - usbif_get(usbif); - - while(!kthread_should_stop()) { - wait_event_interruptible( - usbif->wq, - usbif->waiting_reqs || kthread_should_stop()); - wait_event_interruptible( - pending_free_wq, - !list_empty(&pending_free) || kthread_should_stop()); - usbif->waiting_reqs = 0; - smp_mb(); - - if (usbbk_start_submit_urb(usbif)) - usbif->waiting_reqs = 1; - } - - usbif->xenusbd = NULL; - usbif_put(usbif); - - return 0; + usbif_t *usbif = (usbif_t *) arg; + + usbif_get(usbif); + + while (!kthread_should_stop()) { + wait_event_interruptible( + usbif->wq, + usbif->waiting_reqs || kthread_should_stop()); + wait_event_interruptible( + pending_free_wq, + !list_empty(&pending_free) || kthread_should_stop()); + usbif->waiting_reqs = 0; + smp_mb(); + + if (usbbk_start_submit_urb(usbif)) + usbif->waiting_reqs = 1; + } + + usbif->xenusbd = NULL; + usbif_put(usbif); + + return 0; } /* - * attach the grabbed device to usbif. + * attach usbstub device to usbif. */ -void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub) -{ - unsigned long flags; - - spin_lock_irqsave(&usbif->plug_lock, flags); - list_add(&stub->plugged_list, &usbif->plugged_devices); - spin_unlock_irqrestore(&usbif->plug_lock, flags); - stub->plugged = 1; +void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub) +{ + unsigned long flags; + + spin_lock_irqsave(&usbif->stub_lock, flags); + list_add(&stub->dev_list, &usbif->stub_list); + spin_unlock_irqrestore(&usbif->stub_lock, flags); stub->usbif = usbif; } /* - * detach the grabbed device from usbif. + * detach usbstub device from usbif. */ -void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub) +void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub) { unsigned long flags; if (stub->addr) usbbk_set_address(usbif, stub, stub->addr, 0); - spin_lock_irqsave(&usbif->plug_lock, flags); - list_del(&stub->plugged_list); - spin_unlock_irqrestore(&usbif->plug_lock, flags); - stub->plugged = 0; + spin_lock_irqsave(&usbif->stub_lock, flags); + list_del(&stub->dev_list); + spin_unlock_irqrestore(&usbif->stub_lock, flags); stub->usbif = NULL; } @@ -1023,8 +1086,7 @@ void detach_device_without_lock(usbif_t { if (stub->addr) usbbk_set_address(usbif, stub, stub->addr, 0); - list_del(&stub->plugged_list); - stub->plugged = 0; + list_del(&stub->dev_list); stub->usbif = NULL; } @@ -1054,9 +1116,8 @@ static int __init usbback_init(void) memset(pending_reqs, 0, sizeof(pending_reqs)); INIT_LIST_HEAD(&pending_free); - for (i = 0; i < usbif_reqs; i++) { + for (i = 0; i < usbif_reqs; i++) list_add_tail(&pending_reqs[i].free_list, &pending_free); - } usbback_xenbus_init(); diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbback.h --- a/drivers/xen/usbback/usbback.h Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbback/usbback.h Wed Oct 07 08:42:00 2009 +0100 @@ -59,6 +59,7 @@ #include <xen/gnttab.h> #include <xen/driver_util.h> #include <xen/interface/xen.h> +#include <xen/xenbus.h> #include <xen/interface/io/usbif.h> struct usbstub; @@ -66,89 +67,103 @@ struct usbstub; #define USB_DEV_ADDR_SIZE 128 typedef struct usbif_st { - domid_t domid; - unsigned int handle; + domid_t domid; + unsigned int handle; + int num_ports; + enum usb_spec_version usb_ver; + struct xenbus_device *xbdev; struct list_head usbif_list; unsigned int irq; - usbif_back_ring_t ring; - struct vm_struct *ring_area; + usbif_urb_back_ring_t urb_ring; + usbif_conn_back_ring_t conn_ring; + struct vm_struct *urb_ring_area; + struct vm_struct *conn_ring_area; - spinlock_t ring_lock; + spinlock_t urb_ring_lock; + spinlock_t conn_ring_lock; atomic_t refcnt; - grant_handle_t shmem_handle; - grant_ref_t shmem_ref; + + grant_handle_t urb_shmem_handle; + grant_ref_t urb_shmem_ref; + grant_handle_t conn_shmem_handle; + grant_ref_t conn_shmem_ref; + + struct xenbus_watch backend_watch; /* device address lookup table */ + struct usbstub *addr_table[USB_DEV_ADDR_SIZE]; spinlock_t addr_lock; - struct usbstub *addr_table[USB_DEV_ADDR_SIZE]; - /* plugged device list */ - unsigned plaggable:1; - spinlock_t plug_lock; - struct list_head plugged_devices; + /* connected device list */ + struct list_head stub_list; + spinlock_t stub_lock; /* request schedule */ struct task_struct *xenusbd; unsigned int waiting_reqs; wait_queue_head_t waiting_to_free; wait_queue_head_t wq; - } usbif_t; -struct usbstub_id -{ +struct vusb_port_id { struct list_head id_list; - char bus_id[BUS_ID_SIZE]; - int dom_id; - int dev_id; + char phys_bus[BUS_ID_SIZE]; + domid_t domid; + unsigned int handle; int portnum; + unsigned is_connected:1; }; -struct usbstub -{ - struct usbstub_id *id; +struct usbstub { + struct kref kref; + struct list_head dev_list; + + struct vusb_port_id *portid; struct usb_device *udev; - struct usb_interface *interface; usbif_t *usbif; - - struct list_head grabbed_list; - - unsigned plugged:1; - struct list_head plugged_list; - int addr; + struct list_head submitting_list; spinlock_t submitting_lock; - struct list_head submitting_list; }; usbif_t *usbif_alloc(domid_t domid, unsigned int handle); void usbif_disconnect(usbif_t *usbif); void usbif_free(usbif_t *usbif); -int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn); +int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref, + unsigned long conn_ring_ref, unsigned int evtchn); #define usbif_get(_b) (atomic_inc(&(_b)->refcnt)) #define usbif_put(_b) \ do { \ if (atomic_dec_and_test(&(_b)->refcnt)) \ - wake_up(&(_b)->waiting_to_free); \ + wake_up(&(_b)->waiting_to_free); \ } while (0) +usbif_t *find_usbif(domid_t domid, unsigned int handle); void usbback_xenbus_init(void); void usbback_xenbus_exit(void); - +struct vusb_port_id *find_portid_by_busid(const char *busid); +struct vusb_port_id *find_portid(const domid_t domid, + const unsigned int handle, + const int portnum); +int portid_add(const char *busid, + const domid_t domid, + const unsigned int handle, + const int portnum); +int portid_remove(const domid_t domid, + const unsigned int handle, + const int portnum); irqreturn_t usbbk_be_int(int irq, void *dev_id, struct pt_regs *regs); int usbbk_schedule(void *arg); struct usbstub *find_attached_device(usbif_t *usbif, int port); -struct usbstub *find_grabbed_device(int dom_id, int dev_id, int port); -usbif_t *find_usbif(int dom_id, int dev_id); -void usbback_reconfigure(usbif_t *usbif); -void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub); -void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub); +void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub); +void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub); +void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed); void detach_device_without_lock(usbif_t *usbif, struct usbstub *stub); void usbbk_unlink_urbs(struct usbstub *stub); diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbstub.c --- a/drivers/xen/usbback/usbstub.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbback/usbstub.c Wed Oct 07 08:42:00 2009 +0100 @@ -45,36 +45,106 @@ #include "usbback.h" -static LIST_HEAD(usbstub_ids); -static DEFINE_SPINLOCK(usbstub_ids_lock); -static LIST_HEAD(grabbed_devices); -static DEFINE_SPINLOCK(grabbed_devices_lock); - -struct usbstub *find_grabbed_device(int dom_id, int dev_id, int portnum) -{ - struct usbstub *stub; +static LIST_HEAD(port_list); +static DEFINE_SPINLOCK(port_list_lock); + +struct vusb_port_id *find_portid_by_busid(const char *busid) +{ + struct vusb_port_id *portid; int found = 0; unsigned long flags; - spin_lock_irqsave(&grabbed_devices_lock, flags); - list_for_each_entry(stub, &grabbed_devices, grabbed_list) { - if (stub->id->dom_id == dom_id - && stub->id->dev_id == dev_id - && stub->id->portnum == portnum) { + spin_lock_irqsave(&port_list_lock, flags); + list_for_each_entry(portid, &port_list, id_list) { + if (!(strncmp(portid->phys_bus, busid, BUS_ID_SIZE))) { found = 1; break; } } - spin_unlock_irqrestore(&grabbed_devices_lock, flags); + spin_unlock_irqrestore(&port_list_lock, flags); if (found) - return stub; + return portid; return NULL; } -static struct usbstub *usbstub_alloc(struct usb_interface *interface, - struct usbstub_id *stub_id) +struct vusb_port_id *find_portid(const domid_t domid, + const unsigned int handle, + const int portnum) +{ + struct vusb_port_id *portid; + int found = 0; + unsigned long flags; + + spin_lock_irqsave(&port_list_lock, flags); + list_for_each_entry(portid, &port_list, id_list) { + if ((portid->domid == domid) + && (portid->handle == handle) + && (portid->portnum == portnum)) { + found = 1; + break; + } + } + spin_unlock_irqrestore(&port_list_lock, flags); + + if (found) + return portid; + + return NULL; +} + +int portid_add(const char *busid, + const domid_t domid, + const unsigned int handle, + const int portnum) +{ + struct vusb_port_id *portid; + unsigned long flags; + + portid = kzalloc(sizeof(*portid), GFP_KERNEL); + if (!portid) + return -ENOMEM; + + portid->domid = domid; + portid->handle = handle; + portid->portnum = portnum; + + strncpy(portid->phys_bus, busid, BUS_ID_SIZE); + + spin_lock_irqsave(&port_list_lock, flags); + list_add(&portid->id_list, &port_list); + spin_unlock_irqrestore(&port_list_lock, flags); + + return 0; +} + +int portid_remove(const domid_t domid, + const unsigned int handle, + const int portnum) +{ + struct vusb_port_id *portid, *tmp; + int err = -ENOENT; + unsigned long flags; + + spin_lock_irqsave(&port_list_lock, flags); + list_for_each_entry_safe(portid, tmp, &port_list, id_list) { + if (portid->domid == domid + && portid->handle == handle + && portid->portnum == portnum) { + list_del(&portid->id_list); + kfree(portid); + + err = 0; + } + } + spin_unlock_irqrestore(&port_list_lock, flags); + + return err; +} + +static struct usbstub *usbstub_alloc(struct usb_device *udev, + struct vusb_port_id *portid) { struct usbstub *stub; @@ -83,314 +153,135 @@ static struct usbstub *usbstub_alloc(str printk(KERN_ERR "no memory for alloc usbstub\n"); return NULL; } - - stub->udev = usb_get_dev(interface_to_usbdev(interface)); - stub->interface = interface; - stub->id = stub_id; + kref_init(&stub->kref); + stub->udev = usb_get_dev(udev); + stub->portid = portid; spin_lock_init(&stub->submitting_lock); INIT_LIST_HEAD(&stub->submitting_list); return stub; } -static int usbstub_free(struct usbstub *stub) -{ - if (!stub) - return -EINVAL; +static void usbstub_release(struct kref *kref) +{ + struct usbstub *stub; + + stub = container_of(kref, struct usbstub, kref); usb_put_dev(stub->udev); - stub->interface = NULL; stub->udev = NULL; - stub->id = NULL; + stub->portid = NULL; kfree(stub); - - return 0; -} - -static int usbstub_match_one(struct usb_interface *interface, - struct usbstub_id *stub_id) -{ - char *udev_busid = interface->dev.parent->bus_id; - - if (!(strncmp(stub_id->bus_id, udev_busid, BUS_ID_SIZE))) { - return 1; - } - - return 0; -} - -static struct usbstub_id *usbstub_match(struct usb_interface *interface) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usbstub_id *stub_id; - unsigned long flags; - int found = 0; +} + +static inline void usbstub_get(struct usbstub *stub) +{ + kref_get(&stub->kref); +} + +static inline void usbstub_put(struct usbstub *stub) +{ + kref_put(&stub->kref, usbstub_release); +} + +static int usbstub_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char *busid = intf->dev.parent->bus_id; + struct vusb_port_id *portid = NULL; + struct usbstub *stub = NULL; + usbif_t *usbif = NULL; + int retval = -ENODEV; /* hub currently not supported, so skip. */ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return NULL; - - spin_lock_irqsave(&usbstub_ids_lock, flags); - list_for_each_entry(stub_id, &usbstub_ids, id_list) { - if (usbstub_match_one(interface, stub_id)) { - found = 1; + goto out; + + portid = find_portid_by_busid(busid); + if (!portid) + goto out; + + usbif = find_usbif(portid->domid, portid->handle); + if (!usbif) + goto out; + + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + break; + case USB_SPEED_HIGH: + if (usbif->usb_ver >= USB_VER_USB20) break; - } - } - spin_unlock_irqrestore(&usbstub_ids_lock, flags); - - if (found) - return stub_id; - - return NULL; -} - -static void add_to_grabbed_devices(struct usbstub *stub) -{ - unsigned long flags; - - spin_lock_irqsave(&grabbed_devices_lock, flags); - list_add(&stub->grabbed_list, &grabbed_devices); - spin_unlock_irqrestore(&grabbed_devices_lock, flags); -} - -static void remove_from_grabbed_devices(struct usbstub *stub) -{ - unsigned long flags; - - spin_lock_irqsave(&grabbed_devices_lock, flags); - list_del(&stub->grabbed_list); - spin_unlock_irqrestore(&grabbed_devices_lock, flags); -} - -static int usbstub_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usbstub_id *stub_id = NULL; - struct usbstub *stub = NULL; - usbif_t *usbif = NULL; - int retval = 0; - - if ((stub_id = usbstub_match(interface))) { - stub = usbstub_alloc(interface, stub_id); + /* fall through */ + default: + goto out; + } + + stub = find_attached_device(usbif, portid->portnum); + if (!stub) { + /* new connection */ + stub = usbstub_alloc(udev, portid); if (!stub) return -ENOMEM; - - usb_set_intfdata(interface, stub); - add_to_grabbed_devices(stub); - usbif = find_usbif(stub_id->dom_id, stub_id->dev_id); - if (usbif) { - usbbk_plug_device(usbif, stub); - usbback_reconfigure(usbif); - } - - } else - retval = -ENODEV; - + usbbk_attach_device(usbif, stub); + usbbk_hotplug_notify(usbif, portid->portnum, udev->speed); + } else { + /* maybe already called and connected by other intf */ + if (strncmp(stub->portid->phys_bus, busid, BUS_ID_SIZE)) + goto out; /* invalid call */ + } + + usbstub_get(stub); + usb_set_intfdata(intf, stub); + retval = 0; + +out: return retval; } -static void usbstub_disconnect(struct usb_interface *interface) +static void usbstub_disconnect(struct usb_interface *intf) { struct usbstub *stub - = (struct usbstub *) usb_get_intfdata(interface); - - usb_set_intfdata(interface, NULL); + = (struct usbstub *) usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); if (!stub) return; if (stub->usbif) { - usbback_reconfigure(stub->usbif); - usbbk_unplug_device(stub->usbif, stub); - } - + usbbk_hotplug_notify(stub->usbif, stub->portid->portnum, 0); + usbbk_detach_device(stub->usbif, stub); + } usbbk_unlink_urbs(stub); - - remove_from_grabbed_devices(stub); - - usbstub_free(stub); - - return; -} - -static inline int str_to_vport(const char *buf, - char *phys_bus, - int *dom_id, - int *dev_id, - int *port) -{ - char *p; - int len; - int err; - - /* no physical bus */ - if (!(p = strchr(buf, ':'))) - return -EINVAL; - - len = p - buf; - - /* bad physical bus */ - if (len + 1 > BUS_ID_SIZE) - return -EINVAL; - - strlcpy(phys_bus, buf, len + 1); - err = sscanf(p + 1, "%d:%d:%d", dom_id, dev_id, port); - if (err == 3) - return 0; - else - return -EINVAL; -} - -static int usbstub_id_add(const char *bus_id, - const int dom_id, - const int dev_id, - const int portnum) -{ - struct usbstub_id *stub_id; - unsigned long flags; - - stub_id = kzalloc(sizeof(*stub_id), GFP_KERNEL); - if (!stub_id) - return -ENOMEM; - - stub_id->dom_id = dom_id; - stub_id->dev_id = dev_id; - stub_id->portnum = portnum; - - strncpy(stub_id->bus_id, bus_id, BUS_ID_SIZE); - - spin_lock_irqsave(&usbstub_ids_lock, flags); - list_add(&stub_id->id_list, &usbstub_ids); - spin_unlock_irqrestore(&usbstub_ids_lock, flags); - - return 0; -} - -static int usbstub_id_remove(const char *phys_bus, - const int dom_id, - const int dev_id, - const int portnum) -{ - struct usbstub_id *stub_id, *tmp; - int err = -ENOENT; - unsigned long flags; - - spin_lock_irqsave(&usbstub_ids_lock, flags); - list_for_each_entry_safe(stub_id, tmp, &usbstub_ids, id_list) { - if (stub_id->dom_id == dom_id - && stub_id->dev_id == dev_id - && stub_id->portnum == portnum) { - list_del(&stub_id->id_list); - kfree(stub_id); - - err = 0; - } - } - spin_unlock_irqrestore(&usbstub_ids_lock, flags); - - return err; -} - -static ssize_t usbstub_vport_add(struct device_driver *driver, - const char *buf, size_t count) -{ - int err = 0; - - char bus_id[BUS_ID_SIZE]; - int dom_id; - int dev_id; - int portnum; - - err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum); - if (err) - goto out; - - err = usbstub_id_add(&bus_id[0], dom_id, dev_id, portnum); - -out: - if (!err) - err = count; - return err; -} - -DRIVER_ATTR(new_vport, S_IWUSR, NULL, usbstub_vport_add); - -static ssize_t usbstub_vport_remove(struct device_driver *driver, - const char *buf, size_t count) -{ - int err = 0; - - char bus_id[BUS_ID_SIZE]; - int dom_id; - int dev_id; - int portnum; - - err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum); - if (err) - goto out; - - err = usbstub_id_remove(&bus_id[0], dom_id, dev_id, portnum); - -out: - if (!err) - err = count; - return err; -} - -DRIVER_ATTR(remove_vport, S_IWUSR, NULL, usbstub_vport_remove); - -static ssize_t usbstub_vport_show(struct device_driver *driver, + usbstub_put(stub); +} + +static ssize_t usbstub_show_portids(struct device_driver *driver, char *buf) { - struct usbstub_id *stub_id; + struct vusb_port_id *portid; size_t count = 0; unsigned long flags; - spin_lock_irqsave(&usbstub_ids_lock, flags); - list_for_each_entry(stub_id, &usbstub_ids, id_list) { + spin_lock_irqsave(&port_list_lock, flags); + list_for_each_entry(portid, &port_list, id_list) { if (count >= PAGE_SIZE) break; count += scnprintf((char *)buf + count, PAGE_SIZE - count, "%s:%d:%d:%d\n", - &stub_id->bus_id[0], - stub_id->dom_id, - stub_id->dev_id, - stub_id->portnum); - } - spin_unlock_irqrestore(&usbstub_ids_lock, flags); + &portid->phys_bus[0], + portid->domid, + portid->handle, + portid->portnum); + } + spin_unlock_irqrestore(&port_list_lock, flags); return count; } -DRIVER_ATTR(vports, S_IRUSR, usbstub_vport_show, NULL); - -static ssize_t usbstub_devices_show(struct device_driver *driver, - char *buf) -{ - struct usbstub *stub; - size_t count = 0; - unsigned long flags; - - spin_lock_irqsave(&grabbed_devices_lock, flags); - list_for_each_entry(stub, &grabbed_devices, grabbed_list) { - if (count >= PAGE_SIZE) - break; - - count += scnprintf((char *)buf + count, PAGE_SIZE - count, - "%u-%s:%u.%u\n", - stub->udev->bus->busnum, - stub->udev->devpath, - stub->udev->config->desc.bConfigurationValue, - stub->interface->cur_altsetting->desc.bInterfaceNumber); - - } - spin_unlock_irqrestore(&grabbed_devices_lock, flags); - - return count; -} - -DRIVER_ATTR(grabbed_devices, S_IRUSR, usbstub_devices_show, NULL); +DRIVER_ATTR(port_ids, S_IRUSR, usbstub_show_portids, NULL); /* table of devices that matches any usbdevice */ static struct usb_device_id usbstub_table[] = { @@ -404,44 +295,31 @@ static struct usb_driver usbback_usb_dri .probe = usbstub_probe, .disconnect = usbstub_disconnect, .id_table = usbstub_table, + .no_dynamic_id = 1, }; int __init usbstub_init(void) { - int err; + int err; err = usb_register(&usbback_usb_driver); - if (err < 0) - goto out; - if (!err) - err = driver_create_file(&usbback_usb_driver.driver, - &driver_attr_new_vport); - if (!err) - err = driver_create_file(&usbback_usb_driver.driver, - &driver_attr_remove_vport); - if (!err) - err = driver_create_file(&usbback_usb_driver.driver, - &driver_attr_vports); - if (!err) - err = driver_create_file(&usbback_usb_driver.driver, - &driver_attr_grabbed_devices); + if (err < 0) { + printk(KERN_ERR "usbback: usb_register failed (error %d)\n", err); + goto out; + } + + err = driver_create_file(&usbback_usb_driver.driver, + &driver_attr_port_ids); if (err) - usbstub_exit(); + usb_deregister(&usbback_usb_driver); out: return err; } -void usbstub_exit(void) +void __exit usbstub_exit(void) { driver_remove_file(&usbback_usb_driver.driver, - &driver_attr_new_vport); - driver_remove_file(&usbback_usb_driver.driver, - &driver_attr_remove_vport); - driver_remove_file(&usbback_usb_driver.driver, - &driver_attr_vports); - driver_remove_file(&usbback_usb_driver.driver, - &driver_attr_grabbed_devices); - + &driver_attr_port_ids); usb_deregister(&usbback_usb_driver); } diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/xenbus.c --- a/drivers/xen/usbback/xenbus.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbback/xenbus.c Wed Oct 07 08:42:00 2009 +0100 @@ -43,29 +43,118 @@ * DEALINGS IN THE SOFTWARE. */ -#include <xen/xenbus.h> #include "usbback.h" static int start_xenusbd(usbif_t *usbif) { - int err = 0; - char name[TASK_COMM_LEN]; - - snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, usbif->handle); - usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name); - if (IS_ERR(usbif->xenusbd)) { - err = PTR_ERR(usbif->xenusbd); - usbif->xenusbd = NULL; - xenbus_dev_error(usbif->xbdev, err, "start xenusbd"); - } - return err; + int err = 0; + char name[TASK_COMM_LEN]; + + snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, + usbif->handle); + usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name); + if (IS_ERR(usbif->xenusbd)) { + err = PTR_ERR(usbif->xenusbd); + usbif->xenusbd = NULL; + xenbus_dev_error(usbif->xbdev, err, "start xenusbd"); + } + + return err; +} + +static void backend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + struct xenbus_transaction xbt; + int err; + int i; + char node[8]; + char *busid; + struct vusb_port_id *portid = NULL; + + usbif_t *usbif = container_of(watch, usbif_t, backend_watch); + struct xenbus_device *dev = usbif->xbdev; + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + xenbus_dev_fatal(dev, err, "starting transaction"); + return; + } + + for (i = 1; i <= usbif->num_ports; i++) { + sprintf(node, "port/%d", i); + busid = xenbus_read(xbt, dev->nodename, node, NULL); + if (IS_ERR(busid)) { + err = PTR_ERR(busid); + xenbus_dev_fatal(dev, err, "reading port/%d", i); + goto abort; + } + + /* + * remove portid, if the port is not connected, + */ + if (strlen(busid) == 0) { + portid = find_portid(usbif->domid, usbif->handle, i); + if (portid) { + if (portid->is_connected) + xenbus_dev_fatal(dev, err, + "can't remove port/%d, unbind first", i); + else + portid_remove(usbif->domid, usbif->handle, i); + } + continue; /* never configured, ignore */ + } + + /* + * add portid, + * if the port is not configured and not used from other usbif. + */ + portid = find_portid(usbif->domid, usbif->handle, i); + if (portid) { + if ((strncmp(portid->phys_bus, busid, BUS_ID_SIZE))) + xenbus_dev_fatal(dev, err, + "can't add port/%d, remove first", i); + else + continue; /* already configured, ignore */ + } else { + if (find_portid_by_busid(busid)) + xenbus_dev_fatal(dev, err, + "can't add port/%d, busid already used", i); + else + portid_add(busid, usbif->domid, usbif->handle, i); + } + } + + err = xenbus_transaction_end(xbt, 0); + if (err == -EAGAIN) + goto again; + if (err) + xenbus_dev_fatal(dev, err, "completing transaction"); + + return; + +abort: + xenbus_transaction_end(xbt, 1); + + return; } static int usbback_remove(struct xenbus_device *dev) { usbif_t *usbif = dev->dev.driver_data; + int i; + + if (usbif->backend_watch.node) { + unregister_xenbus_watch(&usbif->backend_watch); + kfree(usbif->backend_watch.node); + usbif->backend_watch.node = NULL; + } if (usbif) { + /* remove all ports */ + for (i = 1; i <= usbif->num_ports; i++) + portid_remove(usbif->domid, usbif->handle, i); usbif_disconnect(usbif); usbif_free(usbif);; } @@ -79,12 +168,14 @@ static int usbback_probe(struct xenbus_d { usbif_t *usbif; unsigned int handle; + int num_ports; + int usb_ver; int err; if (usb_disabled()) return -ENODEV; - handle = simple_strtoul(strrchr(dev->otherend,'/')+1, NULL, 0); + handle = simple_strtoul(strrchr(dev->otherend, '/') + 1, NULL, 0); usbif = usbif_alloc(dev->otherend_id, handle); if (!usbif) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface"); @@ -93,6 +184,34 @@ static int usbback_probe(struct xenbus_d usbif->xbdev = dev; dev->dev.driver_data = usbif; + err = xenbus_scanf(XBT_NIL, dev->nodename, + "num-ports", "%d", &num_ports); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading num-ports"); + goto fail; + } + if (num_ports < 1 || num_ports > USB_MAXCHILDREN) { + xenbus_dev_fatal(dev, err, "invalid num-ports"); + goto fail; + } + usbif->num_ports = num_ports; + + err = xenbus_scanf(XBT_NIL, dev->nodename, + "usb-ver", "%d", &usb_ver); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading usb-ver"); + goto fail; + } + switch (usb_ver) { + case USB_VER_USB11: + case USB_VER_USB20: + usbif->usb_ver = usb_ver; + break; + default: + xenbus_dev_fatal(dev, err, "invalid usb-ver"); + goto fail; + } + err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; @@ -104,15 +223,17 @@ fail: return err; } -static int connect_ring(usbif_t *usbif) +static int connect_rings(usbif_t *usbif) { struct xenbus_device *dev = usbif->xbdev; - unsigned long ring_ref; + unsigned long urb_ring_ref; + unsigned long conn_ring_ref; unsigned int evtchn; int err; err = xenbus_gather(XBT_NIL, dev->otherend, - "ring-ref", "%lu", &ring_ref, + "urb-ring-ref", "%lu", &urb_ring_ref, + "conn-ring-ref", "%lu", &conn_ring_ref, "event-channel", "%u", &evtchn, NULL); if (err) { xenbus_dev_fatal(dev, err, @@ -121,81 +242,32 @@ static int connect_ring(usbif_t *usbif) return err; } - printk("usbback: ring-ref %ld, event-channel %d\n", - ring_ref, evtchn); - - err = usbif_map(usbif, ring_ref, evtchn); + printk("usbback: urb-ring-ref %ld, conn-ring-ref %ld, event-channel %d\n", + urb_ring_ref, conn_ring_ref, evtchn); + + err = usbif_map(usbif, urb_ring_ref, conn_ring_ref, evtchn); if (err) { - xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u", - ring_ref, evtchn); + xenbus_dev_fatal(dev, err, + "mapping urb-ring-ref %lu conn-ring-ref %lu port %u", + urb_ring_ref, conn_ring_ref, evtchn); return err; } return 0; } -void usbback_do_hotplug(usbif_t *usbif) -{ - struct xenbus_transaction xbt; - struct xenbus_device *dev = usbif->xbdev; - struct usbstub *stub = NULL; - int err; - char port_str[8]; - int i; - int num_ports; - int state; - -again: - err = xenbus_transaction_start(&xbt); - if (err) { - xenbus_dev_fatal(dev, err, "starting transaction"); - return; - } - - err = xenbus_scanf(xbt, dev->nodename, - "num-ports", "%d", &num_ports); - - for (i = 1; i <= num_ports; i++) { - stub = find_attached_device(usbif, i); - if (stub) - state = stub->udev->speed; - else - state = 0; - sprintf(port_str, "port-%d", i); - err = xenbus_printf(xbt, dev->nodename, port_str, "%d", state); - if (err) { - xenbus_dev_fatal(dev, err, "writing port-%d state", i); - goto abort; - } - } - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) - goto again; - if (err) - xenbus_dev_fatal(dev, err, "completing transaction"); - - return; - -abort: - xenbus_transaction_end(xbt, 1); -} - -void usbback_reconfigure(usbif_t *usbif) -{ - struct xenbus_device *dev = usbif->xbdev; - - if (dev->state == XenbusStateConnected) - xenbus_switch_state(dev, XenbusStateReconfiguring); -} - -void frontend_changed(struct xenbus_device *dev, +static void frontend_changed(struct xenbus_device *dev, enum xenbus_state frontend_state) { usbif_t *usbif = dev->dev.driver_data; int err; switch (frontend_state) { + case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: + break; + case XenbusStateInitialising: if (dev->state == XenbusStateClosed) { printk("%s: %s: prepare for reconnect\n", @@ -204,17 +276,18 @@ void frontend_changed(struct xenbus_devi } break; - case XenbusStateInitialised: - err = connect_ring(usbif); - if (err) - break; - start_xenusbd(usbif); - usbback_do_hotplug(usbif); - xenbus_switch_state(dev, XenbusStateConnected); - break; - case XenbusStateConnected: if (dev->state == XenbusStateConnected) + break; + err = connect_rings(usbif); + if (err) + break; + err = start_xenusbd(usbif); + if (err) + break; + err = xenbus_watch_path2(dev, dev->nodename, "port", + &usbif->backend_watch, backend_changed); + if (err) break; xenbus_switch_state(dev, XenbusStateConnected); break; @@ -226,13 +299,9 @@ void frontend_changed(struct xenbus_devi case XenbusStateClosed: xenbus_switch_state(dev, XenbusStateClosed); - break; - - case XenbusStateReconfiguring: - usbback_do_hotplug(usbif); - xenbus_switch_state(dev, XenbusStateReconfigured); - break; - + if (xenbus_dev_is_online(dev)) + break; + /* fall through if not online */ case XenbusStateUnknown: device_unregister(&dev->dev); break; diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-dbg.c --- a/drivers/xen/usbfront/usbfront-dbg.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/usbfront-dbg.c Wed Oct 07 08:42:00 2009 +0100 @@ -60,7 +60,7 @@ static ssize_t show_statistics(struct cl spin_lock_irqsave(&info->lock, flags); - temp = scnprintf (next, size, + temp = scnprintf(next, size, "bus %s, device %s\n" "%s\n" "xenhcd, hcd state %d\n", @@ -74,7 +74,8 @@ static ssize_t show_statistics(struct cl #ifdef XENHCD_STATS temp = scnprintf(next, size, "complete %ld unlink %ld ring_full %ld\n", - info->stats.complete, info->stats.unlink, info->stats.ring_full); + info->stats.complete, info->stats.unlink, + info->stats.ring_full); size -= temp; next += temp; #endif diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-hcd.c --- a/drivers/xen/usbfront/usbfront-hcd.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/usbfront-hcd.c Wed Oct 07 08:42:00 2009 +0100 @@ -54,7 +54,7 @@ static void xenhcd_watchdog(unsigned lon unsigned long flags; spin_lock_irqsave(&info->lock, flags); - if (HC_IS_RUNNING(info_to_hcd(info)->state)) { + if (likely(HC_IS_RUNNING(info_to_hcd(info)->state))) { timer_action_done(info, TIMER_RING_WATCHDOG); xenhcd_giveback_unlinked_urbs(info); xenhcd_kick_pending_urbs(info); @@ -70,9 +70,10 @@ static int xenhcd_setup(struct usb_hcd * struct usbfront_info *info = hcd_to_info(hcd); spin_lock_init(&info->lock); - INIT_LIST_HEAD(&info->pending_urbs); - INIT_LIST_HEAD(&info->inprogress_urbs); - INIT_LIST_HEAD(&info->unlinked_urbs); + INIT_LIST_HEAD(&info->pending_submit_list); + INIT_LIST_HEAD(&info->pending_unlink_list); + INIT_LIST_HEAD(&info->in_progress_list); + INIT_LIST_HEAD(&info->giveback_waiting_list); init_timer(&info->watchdog); info->watchdog.function = xenhcd_watchdog; info->watchdog.data = (unsigned long) info; @@ -101,68 +102,12 @@ static void xenhcd_stop(struct usb_hcd * del_timer_sync(&info->watchdog); remove_debug_file(info); spin_lock_irq(&info->lock); - /* - * TODO: port power off, cancel all urbs. - */ - - if (HC_IS_RUNNING(hcd->state)) - hcd->state = HC_STATE_HALT; + /* cancel all urbs */ + hcd->state = HC_STATE_HALT; + xenhcd_cancel_all_enqueued_urbs(info); + xenhcd_giveback_unlinked_urbs(info); spin_unlock_irq(&info->lock); } - -/* - * TODO: incomplete suspend/resume functions! - */ -#if 0 -#ifdef CONFIG_PM -/* - * suspend running HC - */ -static int xenhcd_suspend(struct usb_hcd *hcd, pm_message_t message) -{ - struct usbfront_info *info = hcd_to_info(hcd); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&info->lock, flags); - if (hcd->state != HC_STATE_SUSPENDED) { - ret = -EINVAL; - goto done; - } - - /* - * TODO: - * canceling all transfer, clear all hc queue, - * stop kthread, - */ - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -done: - spin_unlock_irqrestore(&info->lock, flags); - - return ret; -} - -/* - * resume HC - */ -static int xenhcd_resume(struct usb_hcd *hcd) -{ - struct usbfront_info *info = hcd_to_info(hcd); - int ret = -EINVAL; - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* - * TODO: - * re-init HC. - * resume all roothub ports. - */ - - return ret; -} -#endif -#endif /* * called as .urb_enqueue() @@ -197,11 +142,6 @@ done: /* * called as .urb_dequeue() - * - * just mark the urb as unlinked - * if the urb is in pending_urbs, move to unlinked_urbs - * TODO: - * canceling the urb transfer in backend */ static int xenhcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) @@ -234,46 +174,54 @@ static int xenhcd_get_frame(struct usb_h return 0; } -/* - * TODO: - * suspend/resume whole hcd and roothub - */ static const char hcd_name[] = "xen_hcd"; -struct hc_driver usbfront_hc_driver = { +struct hc_driver xen_usb20_hc_driver = { .description = hcd_name, - .product_desc = DRIVER_DESC, + .product_desc = "Xen USB2.0 Virtual Host Controller", .hcd_priv_size = sizeof(struct usbfront_info), .flags = HCD_USB2, - /* - * basic HC lifecycle operations - */ + /* basic HC lifecycle operations */ .reset = xenhcd_setup, .start = xenhcd_run, .stop = xenhcd_stop, -#if 0 -#ifdef CONFIG_PM - .suspend = xenhcd_suspend, - .resume = xenhcd_resume, -#endif -#endif - /* - * managing urb I/O - */ + + /* managing urb I/O */ .urb_enqueue = xenhcd_urb_enqueue, .urb_dequeue = xenhcd_urb_dequeue, .get_frame_number = xenhcd_get_frame, - /* - * root hub operations - */ + /* root hub operations */ .hub_status_data = xenhcd_hub_status_data, .hub_control = xenhcd_hub_control, -#if 0 #ifdef CONFIG_PM .bus_suspend = xenhcd_bus_suspend, .bus_resume = xenhcd_bus_resume, #endif +}; + +struct hc_driver xen_usb11_hc_driver = { + .description = hcd_name, + .product_desc = "Xen USB1.1 Virtual Host Controller", + .hcd_priv_size = sizeof(struct usbfront_info), + .flags = HCD_USB11, + + /* basic HC lifecycle operations */ + .reset = xenhcd_setup, + .start = xenhcd_run, + .stop = xenhcd_stop, + + /* managing urb I/O */ + .urb_enqueue = xenhcd_urb_enqueue, + .urb_dequeue = xenhcd_urb_dequeue, + .get_frame_number = xenhcd_get_frame, + + /* root hub operations */ + .hub_status_data = xenhcd_hub_status_data, + .hub_control = xenhcd_hub_control, +#ifdef CONFIG_PM + .bus_suspend = xenhcd_bus_suspend, + .bus_resume = xenhcd_bus_resume, #endif }; diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-hub.c --- a/drivers/xen/usbfront/usbfront-hub.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/usbfront-hub.c Wed Oct 07 08:42:00 2009 +0100 @@ -50,15 +50,16 @@ void set_connect_state(struct usbfront_i { int port; - port = portnum -1; + port = portnum - 1; if (info->ports[port].status & USB_PORT_STAT_POWER) { switch (info->devices[port].speed) { case USB_SPEED_UNKNOWN: - info->ports[port].status &= ~(USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | - USB_PORT_STAT_HIGH_SPEED | - USB_PORT_STAT_SUSPEND); + info->ports[port].status &= + ~(USB_PORT_STAT_CONNECTION | + USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED | + USB_PORT_STAT_HIGH_SPEED | + USB_PORT_STAT_SUSPEND); break; case USB_SPEED_LOW: info->ports[port].status |= USB_PORT_STAT_CONNECTION; @@ -85,6 +86,9 @@ void rhport_connect(struct usbfront_info int portnum, enum usb_device_speed speed) { int port; + + if (portnum < 1 || portnum > info->rh_numports) + return; /* invalid port number */ port = portnum - 1; if (info->devices[port].speed != speed) { @@ -105,30 +109,6 @@ void rhport_connect(struct usbfront_info set_connect_state(info, portnum); } -} - -void rhport_disconnect(struct usbfront_info *info, int portnum) -{ - rhport_connect(info, portnum, USB_SPEED_UNKNOWN); -} - -void xenhcd_rhport_state_change(struct usbfront_info *info, - int portnum, enum usb_device_speed speed) -{ - int changed = 0; - unsigned long flags; - - if (portnum < 1 || portnum > info->rh_numports) - return; /* invalid port number */ - - spin_lock_irqsave(&info->lock, flags); - rhport_connect(info, portnum, speed); - if (info->ports[portnum-1].c_connection) - changed = 1; - spin_unlock_irqrestore(&info->lock, flags); - - if (changed) - usb_hcd_poll_rh_status(info_to_hcd(info)); } /* @@ -214,7 +194,7 @@ void rhport_reset(struct usbfront_info * { int port; - port = portnum -1; + port = portnum - 1; info->ports[port].status &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); @@ -227,56 +207,50 @@ void rhport_reset(struct usbfront_info * info->ports[port].timeout = jiffies + msecs_to_jiffies(10); } -#if 0 #ifdef CONFIG_PM static int xenhcd_bus_suspend(struct usb_hcd *hcd) { struct usbfront_info *info = hcd_to_info(hcd); + int ret = 0; int i, ports; ports = info->rh_numports; spin_lock_irq(&info->lock); - - if (HC_IS_RUNNING(hcd->state)) { - /* - * TODO: - * clean queue, - * stop all transfers, - * ... - */ - hcd->state = HC_STATE_QUIESCING; - } - - /* suspend any active ports*/ - for (i = 1; i <= ports; i++) { - rhport_suspend(info, i); - } + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &info->flags)) + ret = -ESHUTDOWN; + else if (!info->dead) { + /* suspend any active ports*/ + for (i = 1; i <= ports; i++) + rhport_suspend(info, i); + } + spin_unlock_irq(&info->lock); del_timer_sync(&info->watchdog); + return ret; +} + +static int xenhcd_bus_resume(struct usb_hcd *hcd) +{ + struct usbfront_info *info = hcd_to_info(hcd); + int ret = 0; + int i, ports; + + ports = info->rh_numports; + + spin_lock_irq(&info->lock); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &info->flags)) + ret = -ESHUTDOWN; + else if (!info->dead) { + /* resume any suspended ports*/ + for (i = 1; i <= ports; i++) + rhport_resume(info, i); + } spin_unlock_irq(&info->lock); - return 0; -} - -static int xenhcd_bus_resume(struct usb_hcd *hcd) -{ - struct usbfront_info *info = hcd_to_info(hcd); - int i, ports; - - ports = info->rh_numports; - - spin_lock_irq(&info->lock); - /* resume any suspended ports*/ - for (i = 1; i <= ports; i++) { - rhport_resume(info, i); - } - hcd->state = HC_STATE_RUNNING; - spin_unlock_irq(&info->lock); - return 0; -} -#endif + return ret; +} #endif static void xenhcd_hub_descriptor(struct usbfront_info *info, @@ -295,8 +269,8 @@ static void xenhcd_hub_descriptor(struct desc->bDescLength = 7 + 2 * temp; /* bitmaps for DeviceRemovable and PortPwrCtrlMask */ - memset (&desc->bitmap[0], 0, temp); - memset (&desc->bitmap[temp], 0xff, temp); + memset(&desc->bitmap[0], 0, temp); + memset(&desc->bitmap[temp], 0xff, temp); /* per-port over current reporting and no power switching */ temp = 0x000a; @@ -380,11 +354,6 @@ static int xenhcd_hub_control(struct usb int i; int changed = 0; -#ifdef USBFRONT_DEBUG - WPRINTK("xenusb_hub_control(typeReq %x wValue %x wIndex %x)\n", - typeReq, wValue, wIndex); -#endif - spin_lock_irqsave(&info->lock, flags); switch (typeReq) { case ClearHubFeature: @@ -394,7 +363,7 @@ static int xenhcd_hub_control(struct usb if (!wIndex || wIndex > ports) goto error; - switch(wValue) { + switch (wValue) { case USB_PORT_FEAT_SUSPEND: rhport_resume(info, wIndex); break; @@ -414,7 +383,7 @@ static int xenhcd_hub_control(struct usb break; case GetHubDescriptor: xenhcd_hub_descriptor(info, - (struct usb_hub_descriptor*) buf); + (struct usb_hub_descriptor *) buf); break; case GetHubStatus: /* always local power supply good and no over-current exists. */ @@ -444,7 +413,7 @@ static int xenhcd_hub_control(struct usb info->devices[wIndex].status = USB_STATE_DEFAULT; } - switch(info->devices[wIndex].speed) { + switch (info->devices[wIndex].speed) { case USB_SPEED_LOW: info->ports[wIndex].status |= USB_PORT_STAT_LOW_SPEED; break; @@ -466,7 +435,7 @@ static int xenhcd_hub_control(struct usb if (!wIndex || wIndex > ports) goto error; - switch(wValue) { + switch (wValue) { case USB_PORT_FEAT_POWER: rhport_power_on(info, wIndex); break; @@ -477,9 +446,8 @@ static int xenhcd_hub_control(struct usb rhport_suspend(info, wIndex); break; default: - if ((info->ports[wIndex-1].status & USB_PORT_STAT_POWER) != 0) { + if ((info->ports[wIndex-1].status & USB_PORT_STAT_POWER) != 0) info->ports[wIndex-1].status |= (1 << wValue); - } } break; @@ -491,9 +459,8 @@ error: /* check status for each port */ for (i = 0; i < ports; i++) { - if (info->ports[i].status & PORT_C_MASK) { + if (info->ports[i].status & PORT_C_MASK) changed = 1; - } } if (changed) usb_hcd_poll_rh_status(hcd); diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-q.c --- a/drivers/xen/usbfront/usbfront-q.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/usbfront-q.c Wed Oct 07 08:42:00 2009 +0100 @@ -50,13 +50,13 @@ static struct urb_priv *alloc_urb_priv(s struct urb_priv *urbp; urbp = kmem_cache_zalloc(xenhcd_urbp_cachep, GFP_ATOMIC); - if (!urbp) { + if (!urbp) return NULL; - } urbp->urb = urb; urb->hcpriv = urbp; urbp->req_id = ~0; + urbp->unlink_req_id = ~0; INIT_LIST_HEAD(&urbp->list); return urbp; @@ -73,7 +73,7 @@ static inline int get_id_from_freelist( { unsigned long free; free = info->shadow_free; - BUG_ON(free > USB_RING_SIZE); + BUG_ON(free >= USB_URB_RING_SIZE); info->shadow_free = info->shadow[free].req.id; info->shadow[free].req.id = (unsigned int)0x0fff; /* debug */ return free; @@ -90,7 +90,7 @@ static inline int count_pages(void *addr static inline int count_pages(void *addr, int length) { unsigned long start = (unsigned long) addr >> PAGE_SHIFT; - unsigned long end = (unsigned long) (addr + length + PAGE_SIZE -1) >> PAGE_SHIFT; + unsigned long end = (unsigned long) (addr + length + PAGE_SIZE - 1) >> PAGE_SHIFT; return end - start; } @@ -108,7 +108,7 @@ static inline void xenhcd_gnttab_map(str len = length; - for(i = 0;i < nr_pages;i++){ + for (i = 0; i < nr_pages; i++) { BUG_ON(!len); page = virt_to_page(addr); @@ -116,7 +116,7 @@ static inline void xenhcd_gnttab_map(str offset = offset_in_page(addr); bytes = PAGE_SIZE - offset; - if(bytes > len) + if (bytes > len) bytes = len; ref = gnttab_claim_grant_reference(gref_head); @@ -132,7 +132,7 @@ static inline void xenhcd_gnttab_map(str } static int map_urb_for_request(struct usbfront_info *info, struct urb *urb, - usbif_request_t *req) + usbif_urb_request_t *req) { grant_ref_t gref_head; int nr_buff_pages = 0; @@ -175,14 +175,12 @@ static int map_urb_for_request(struct us req->u.isoc.start_frame = urb->start_frame; req->u.isoc.number_of_packets = urb->number_of_packets; req->u.isoc.nr_frame_desc_segs = nr_isodesc_pages; - /* - * urb->number_of_packets must be > 0 - */ + /* urb->number_of_packets must be > 0 */ if (unlikely(urb->number_of_packets <= 0)) BUG(); xenhcd_gnttab_map(info, &urb->iso_frame_desc[0], - sizeof(struct usb_iso_packet_descriptor) * urb->number_of_packets, - &gref_head, &req->seg[nr_buff_pages], nr_isodesc_pages, 0); + sizeof(struct usb_iso_packet_descriptor) * urb->number_of_packets, + &gref_head, &req->seg[nr_buff_pages], nr_isodesc_pages, 0); gnttab_free_grant_references(gref_head); break; case PIPE_INTERRUPT: @@ -213,9 +211,12 @@ static void xenhcd_gnttab_done(struct us for (i = 0; i < nr_segs; i++) gnttab_end_foreign_access(shadow->req.seg[i].gref, 0UL); -} - -static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb) + + shadow->req.nr_buffer_segs = 0; + shadow->req.u.isoc.nr_frame_desc_segs = 0; +} + +static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb, int status) __releases(info->lock) __acquires(info->lock) { @@ -228,6 +229,9 @@ __acquires(info->lock) case -ENOENT: COUNT(info->stats.unlink); break; + case -EINPROGRESS: + urb->status = status; + /* falling through */ default: COUNT(info->stats.complete); } @@ -238,28 +242,35 @@ __acquires(info->lock) static inline int xenhcd_do_request(struct usbfront_info *info, struct urb_priv *urbp) { - usbif_request_t *ring_req; + usbif_urb_request_t *req; struct urb *urb = urbp->urb; uint16_t id; int notify; int ret = 0; - ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); + req = RING_GET_REQUEST(&info->urb_ring, info->urb_ring.req_prod_pvt); id = get_id_from_freelist(info); - ring_req->id = id; - - ret = map_urb_for_request(info, urb, ring_req); - if (ret < 0) { - add_id_to_freelist(info, id); - return ret; - } - - info->ring.req_prod_pvt++; + req->id = id; + + if (unlikely(urbp->unlinked)) { + req->u.unlink.unlink_id = urbp->req_id; + req->pipe = usbif_setunlink_pipe(usbif_setportnum_pipe( + urb->pipe, urb->dev->portnum)); + urbp->unlink_req_id = id; + } else { + ret = map_urb_for_request(info, urb, req); + if (ret < 0) { + add_id_to_freelist(info, id); + return ret; + } + urbp->req_id = id; + } + + info->urb_ring.req_prod_pvt++; info->shadow[id].urb = urb; - info->shadow[id].req = *ring_req; - urbp->req_id = id; - - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); + info->shadow[id].req = *req; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify); if (notify) notify_remote_via_irq(info->irq); @@ -271,19 +282,19 @@ static void xenhcd_kick_pending_urbs(str struct urb_priv *urbp; int ret; - while (!list_empty(&info->pending_urbs)) { - if (RING_FULL(&info->ring)) { + while (!list_empty(&info->pending_submit_list)) { + if (RING_FULL(&info->urb_ring)) { COUNT(info->stats.ring_full); timer_action(info, TIMER_RING_WATCHDOG); goto done; } - urbp = list_entry(info->pending_urbs.next, struct urb_priv, list); + urbp = list_entry(info->pending_submit_list.next, struct urb_priv, list); ret = xenhcd_do_request(info, urbp); if (ret == 0) - list_move_tail(&urbp->list, &info->inprogress_urbs); + list_move_tail(&urbp->list, &info->in_progress_list); else - xenhcd_giveback_urb(info, urbp->urb); + xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN); } timer_action_done(info, TIMER_SCAN_PENDING_URBS); @@ -291,12 +302,41 @@ done: return; } +/* + * caller must lock info->lock + */ +static void xenhcd_cancel_all_enqueued_urbs(struct usbfront_info *info) +{ + struct urb_priv *urbp, *tmp; + + list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) { + if (!urbp->unlinked) { + xenhcd_gnttab_done(&info->shadow[urbp->req_id]); + barrier(); + if (urbp->urb->status == -EINPROGRESS) /* not dequeued */ + xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN); + else /* dequeued */ + xenhcd_giveback_urb(info, urbp->urb, urbp->urb->status); + } + info->shadow[urbp->req_id].urb = NULL; + } + + list_for_each_entry_safe(urbp, tmp, &info->pending_submit_list, list) { + xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN); + } + + return; +} + +/* + * caller must lock info->lock + */ static void xenhcd_giveback_unlinked_urbs(struct usbfront_info *info) { struct urb_priv *urbp, *tmp; - list_for_each_entry_safe(urbp, tmp, &info->unlinked_urbs, list) { - xenhcd_giveback_urb(info, urbp->urb); + list_for_each_entry_safe(urbp, tmp, &info->giveback_waiting_list, list) { + xenhcd_giveback_urb(info, urbp->urb, urbp->urb->status); } } @@ -304,22 +344,22 @@ static int xenhcd_submit_urb(struct usbf { int ret = 0; - if (RING_FULL(&info->ring)) { - list_add_tail(&urbp->list, &info->pending_urbs); + if (RING_FULL(&info->urb_ring)) { + list_add_tail(&urbp->list, &info->pending_submit_list); COUNT(info->stats.ring_full); timer_action(info, TIMER_RING_WATCHDOG); goto done; } - if (!list_empty(&info->pending_urbs)) { - list_add_tail(&urbp->list, &info->pending_urbs); + if (!list_empty(&info->pending_submit_list)) { + list_add_tail(&urbp->list, &info->pending_submit_list); timer_action(info, TIMER_SCAN_PENDING_URBS); goto done; } ret = xenhcd_do_request(info, urbp); if (ret == 0) - list_add_tail(&urbp->list, &info->inprogress_urbs); + list_add_tail(&urbp->list, &info->in_progress_list); done: return ret; @@ -327,26 +367,47 @@ done: static int xenhcd_unlink_urb(struct usbfront_info *info, struct urb_priv *urbp) { + int ret = 0; + + /* already unlinked? */ if (urbp->unlinked) return -EBUSY; + urbp->unlinked = 1; - /* if the urb is in pending_urbs */ + /* the urb is still in pending_submit queue */ if (urbp->req_id == ~0) { - list_move_tail(&urbp->list, &info->unlinked_urbs); + list_move_tail(&urbp->list, &info->giveback_waiting_list); timer_action(info, TIMER_SCAN_PENDING_URBS); - } - - /* TODO: send cancel request to backend */ - - return 0; -} - -static int xenhcd_end_submit_urb(struct usbfront_info *info) -{ - usbif_response_t *ring_res; + goto done; + } + + /* send unlink request to backend */ + if (RING_FULL(&info->urb_ring)) { + list_move_tail(&urbp->list, &info->pending_unlink_list); + COUNT(info->stats.ring_full); + timer_action(info, TIMER_RING_WATCHDOG); + goto done; + } + + if (!list_empty(&info->pending_unlink_list)) { + list_move_tail(&urbp->list, &info->pending_unlink_list); + timer_action(info, TIMER_SCAN_PENDING_URBS); + goto done; + } + + ret = xenhcd_do_request(info, urbp); + if (ret == 0) + list_move_tail(&urbp->list, &info->in_progress_list); + +done: + return ret; +} + +static int xenhcd_urb_request_done(struct usbfront_info *info) +{ + usbif_urb_response_t *res; struct urb *urb; - struct urb_priv *urbp; RING_IDX i, rp; uint16_t id; @@ -354,35 +415,92 @@ static int xenhcd_end_submit_urb(struct unsigned long flags; spin_lock_irqsave(&info->lock, flags); - rp = info->ring.sring->rsp_prod; + + rp = info->urb_ring.sring->rsp_prod; rmb(); /* ensure we see queued responses up to "rp" */ - for (i = info->ring.rsp_cons; i != rp; i++) { - ring_res = RING_GET_RESPONSE(&info->ring, i); - id = ring_res->id; - xenhcd_gnttab_done(&info->shadow[id]); - urb = info->shadow[id].urb; + for (i = info->urb_ring.rsp_cons; i != rp; i++) { + res = RING_GET_RESPONSE(&info->urb_ring, i); + id = res->id; + + if (likely(usbif_pipesubmit(info->shadow[id].req.pipe))) { + xenhcd_gnttab_done(&info->shadow[id]); + urb = info->shadow[id].urb; + barrier(); + if (likely(urb)) { + urb->actual_length = res->actual_length; + urb->error_count = res->error_count; + urb->start_frame = res->start_frame; + barrier(); + xenhcd_giveback_urb(info, urb, res->status); + } + } + + add_id_to_freelist(info, id); + } + info->urb_ring.rsp_cons = i; + + if (i != info->urb_ring.req_prod_pvt) + RING_FINAL_CHECK_FOR_RESPONSES(&info->urb_ring, more_to_do); + else + info->urb_ring.sring->rsp_event = i + 1; + + spin_unlock_irqrestore(&info->lock, flags); + + cond_resched(); + + return more_to_do; +} + +static int xenhcd_conn_notify(struct usbfront_info *info) +{ + usbif_conn_response_t *res; + usbif_conn_request_t *req; + RING_IDX rc, rp; + uint16_t id; + uint8_t portnum, speed; + int more_to_do = 0; + int notify; + int port_changed = 0; + unsigned long flags; + + spin_lock_irqsave(&info->lock, flags); + + rc = info->conn_ring.rsp_cons; + rp = info->conn_ring.sring->rsp_prod; + rmb(); /* ensure we see queued responses up to "rp" */ + + while (rc != rp) { + res = RING_GET_RESPONSE(&info->conn_ring, rc); + id = res->id; + portnum = res->portnum; + speed = res->speed; + info->conn_ring.rsp_cons = ++rc; + + rhport_connect(info, portnum, speed); + if (info->ports[portnum-1].c_connection) + port_changed = 1; + barrier(); - add_id_to_freelist(info, id); - - urbp = (struct urb_priv *)urb->hcpriv; - if (likely(!urbp->unlinked)) { - urb->status = ring_res->status; - urb->actual_length = ring_res->actual_length; - urb->error_count = ring_res->error_count; - urb->start_frame = ring_res->start_frame; - } - barrier(); - xenhcd_giveback_urb(info, urb); - } - info->ring.rsp_cons = i; - - if (i != info->ring.req_prod_pvt) - RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); + + req = RING_GET_REQUEST(&info->conn_ring, info->conn_ring.req_prod_pvt); + req->id = id; + info->conn_ring.req_prod_pvt++; + } + + if (rc != info->conn_ring.req_prod_pvt) + RING_FINAL_CHECK_FOR_RESPONSES(&info->conn_ring, more_to_do); else - info->ring.sring->rsp_event = i + 1; + info->conn_ring.sring->rsp_event = rc + 1; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify); + if (notify) + notify_remote_via_irq(info->irq); spin_unlock_irqrestore(&info->lock, flags); + + if (port_changed) + usb_hcd_poll_rh_status(info_to_hcd(info)); cond_resched(); @@ -400,7 +518,10 @@ int xenhcd_schedule(void *arg) info->waiting_resp = 0; smp_mb(); - if (xenhcd_end_submit_urb(info)) + if (xenhcd_urb_request_done(info)) + info->waiting_resp = 1; + + if (xenhcd_conn_notify(info)) info->waiting_resp = 1; } diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront.h --- a/drivers/xen/usbfront/usbfront.h Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/usbfront.h Wed Oct 07 08:42:00 2009 +0100 @@ -66,8 +66,6 @@ #include "../../usb/core/hcd.h" #include "../../usb/core/hub.h" -#define DRIVER_DESC "Xen USB2.0 Virtual Host Controller driver (usbfront)" - static inline struct usbfront_info *hcd_to_info(struct usb_hcd *hcd) { return (struct usbfront_info *) (hcd->hcd_priv); @@ -75,17 +73,16 @@ static inline struct usbfront_info *hcd_ static inline struct usb_hcd *info_to_hcd(struct usbfront_info *info) { - return container_of ((void *) info, struct usb_hcd, hcd_priv); -} - -/* - * Private per-URB data - */ + return container_of((void *) info, struct usb_hcd, hcd_priv); +} + +/* Private per-URB data */ struct urb_priv { struct list_head list; struct urb *urb; - int req_id; /* RING_REQUEST id */ - unsigned unlinked:1; /* dequeued urb just marked */ + int req_id; /* RING_REQUEST id for submitting */ + int unlink_req_id; /* RING_REQUEST id for unlinking */ + unsigned unlinked:1; /* dequeued marker */ }; /* virtual roothub port status */ @@ -105,7 +102,7 @@ struct vdevice_status { /* RING request shadow */ struct usb_shadow { - usbif_request_t req; + usbif_urb_request_t req; struct urb *urb; }; @@ -117,62 +114,46 @@ struct xenhcd_stats { }; struct usbfront_info { - /* - * Virtual Host Controller has 3 queues. - * - * pending_urbs: - * If xenhcd_urb_enqueue() called in RING_FULL state, - * the enqueued urbs are added to this queue, and waits - * to be sent to the backend. - * - * inprogress_urbs: - * After xenhcd_urb_enqueue() called and RING_REQUEST sent, - * the urbs are added to this queue and waits for RING_RESPONSE. - * - * unlinked_urbs: - * When xenhcd_urb_dequeue() called, if the dequeued urb is - * listed in pending_urbs, that urb is moved to this queue - * and waits to be given back to the USB core. - */ - struct list_head pending_urbs; - struct list_head inprogress_urbs; - struct list_head unlinked_urbs; + /* Virtual Host Controller has 4 urb queues */ + struct list_head pending_submit_list; + struct list_head pending_unlink_list; + struct list_head in_progress_list; + struct list_head giveback_waiting_list; + spinlock_t lock; - /* - * timer function that kick pending_urbs and unlink_urbs. - */ + /* timer that kick pending and giveback waiting urbs */ + struct timer_list watchdog; unsigned long actions; - struct timer_list watchdog; - - /* - * Virtual roothub: - * Emulates the hub ports and the attached devices status. - * USB_MAXCHILDREN is defined (16) in include/linux/usb.h - */ + + /* virtual root hub */ int rh_numports; struct rhport_status ports[USB_MAXCHILDREN]; struct vdevice_status devices[USB_MAXCHILDREN]; + /* Xen related staff */ + struct xenbus_device *xbdev; + int urb_ring_ref; + int conn_ring_ref; + usbif_urb_front_ring_t urb_ring; + usbif_conn_front_ring_t conn_ring; + + unsigned int irq; /* event channel */ + struct usb_shadow shadow[USB_URB_RING_SIZE]; + unsigned long shadow_free; + + /* RING_RESPONSE thread */ + struct task_struct *kthread; + wait_queue_head_t wq; + unsigned int waiting_resp; + + /* xmit statistics */ #ifdef XENHCD_STATS struct xenhcd_stats stats; #define COUNT(x) do { (x)++; } while (0) #else #define COUNT(x) do {} while (0) #endif - - /* Xen related staff */ - struct xenbus_device *xbdev; - int ring_ref; - usbif_front_ring_t ring; - unsigned int irq; - struct usb_shadow shadow[USB_RING_SIZE]; - unsigned long shadow_free; - - /* RING_RESPONSE thread */ - struct task_struct *kthread; - wait_queue_head_t wq; - unsigned int waiting_resp; }; #define XENHCD_RING_JIFFIES (HZ/200) @@ -199,7 +180,7 @@ timer_action(struct usbfront_info *info, if (!test_and_set_bit(action, &info->actions)) { unsigned long t; - switch(action) { + switch (action) { case TIMER_RING_WATCHDOG: t = XENHCD_RING_JIFFIES; break; @@ -211,6 +192,12 @@ timer_action(struct usbfront_info *info, } } +extern struct kmem_cache *xenhcd_urbp_cachep; +extern struct hc_driver xen_usb20_hc_driver; +extern struct hc_driver xen_usb11_hc_driver; irqreturn_t xenhcd_int(int irq, void *dev_id, struct pt_regs *ptregs); +void xenhcd_rhport_state_change(struct usbfront_info *info, + int port, enum usb_device_speed speed); +int xenhcd_schedule(void *arg); #endif /* __XEN_USBFRONT_H__ */ diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/xenbus.c --- a/drivers/xen/usbfront/xenbus.c Wed Oct 07 07:33:40 2009 +0100 +++ b/drivers/xen/usbfront/xenbus.c Wed Oct 07 08:42:00 2009 +0100 @@ -45,50 +45,70 @@ #include "usbfront.h" -extern struct hc_driver usbfront_hc_driver; -extern struct kmem_cache *xenhcd_urbp_cachep; -extern void xenhcd_rhport_state_change(struct usbfront_info *info, - int port, enum usb_device_speed speed); -extern int xenhcd_schedule(void *arg); - #define GRANT_INVALID_REF 0 -static void usbif_free(struct usbfront_info *info) -{ - if (info->ring_ref != GRANT_INVALID_REF) { - gnttab_end_foreign_access(info->ring_ref, - (unsigned long)info->ring.sring); - info->ring_ref = GRANT_INVALID_REF; - info->ring.sring = NULL; - } +static void destroy_rings(struct usbfront_info *info) +{ if (info->irq) unbind_from_irqhandler(info->irq, info); info->irq = 0; -} - -static int setup_usbring(struct xenbus_device *dev, + + if (info->urb_ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(info->urb_ring_ref, + (unsigned long)info->urb_ring.sring); + info->urb_ring_ref = GRANT_INVALID_REF; + } + info->urb_ring.sring = NULL; + + if (info->conn_ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(info->conn_ring_ref, + (unsigned long)info->conn_ring.sring); + info->conn_ring_ref = GRANT_INVALID_REF; + } + info->conn_ring.sring = NULL; +} + +static int setup_rings(struct xenbus_device *dev, struct usbfront_info *info) { - usbif_sring_t *sring; + usbif_urb_sring_t *urb_sring; + usbif_conn_sring_t *conn_sring; int err; - info->ring_ref= GRANT_INVALID_REF; - - sring = (usbif_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH); - if (!sring) { - xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); + info->urb_ring_ref = GRANT_INVALID_REF; + info->conn_ring_ref = GRANT_INVALID_REF; + + urb_sring = (usbif_urb_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH); + if (!urb_sring) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating urb ring"); return -ENOMEM; } - SHARED_RING_INIT(sring); - FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); - - err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); + SHARED_RING_INIT(urb_sring); + FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(info->urb_ring.sring)); if (err < 0) { - free_page((unsigned long)sring); - info->ring.sring = NULL; - goto fail; - } - info->ring_ref = err; + free_page((unsigned long)urb_sring); + info->urb_ring.sring = NULL; + goto fail; + } + info->urb_ring_ref = err; + + conn_sring = (usbif_conn_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH); + if (!conn_sring) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating conn ring"); + return -ENOMEM; + } + SHARED_RING_INIT(conn_sring); + FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(info->conn_ring.sring)); + if (err < 0) { + free_page((unsigned long)conn_sring); + info->conn_ring.sring = NULL; + goto fail; + } + info->conn_ring_ref = err; err = bind_listening_port_to_irqhandler( dev->otherend_id, xenhcd_int, SA_SAMPLE_RANDOM, "usbif", info); @@ -101,7 +121,7 @@ static int setup_usbring(struct xenbus_d return 0; fail: - usbif_free(info); + destroy_rings(info); return err; } @@ -112,7 +132,7 @@ static int talk_to_backend(struct xenbus struct xenbus_transaction xbt; int err; - err = setup_usbring(dev, info); + err = setup_rings(dev, info); if (err) goto out; @@ -123,10 +143,17 @@ again: goto destroy_ring; } - err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", - info->ring_ref); - if (err) { - message = "writing ring-ref"; + err = xenbus_printf(xbt, dev->nodename, "urb-ring-ref", "%u", + info->urb_ring_ref); + if (err) { + message = "writing urb-ring-ref"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, "conn-ring-ref", "%u", + info->conn_ring_ref); + if (err) { + message = "writing conn-ring-ref"; goto abort_transaction; } @@ -145,8 +172,6 @@ again: goto destroy_ring; } - xenbus_switch_state(dev, XenbusStateInitialised); - return 0; abort_transaction: @@ -154,10 +179,37 @@ abort_transaction: xenbus_dev_fatal(dev, err, "%s", message); destroy_ring: - usbif_free(info); + destroy_rings(info); out: return err; +} + +static int connect(struct xenbus_device *dev) +{ + struct usbfront_info *info = dev->dev.driver_data; + + usbif_conn_request_t *req; + int i, idx, err; + int notify; + + err = talk_to_backend(dev, info); + if (err) + return err; + + /* prepare ring for hotplug notification */ + for (idx = 0, i = 0; i < USB_CONN_RING_SIZE; i++) { + req = RING_GET_REQUEST(&info->conn_ring, idx); + req->id = idx; + idx++; + } + info->conn_ring.req_prod_pvt = idx; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify); + if (notify) + notify_remote_via_irq(info->irq); + + return 0; } static struct usb_hcd *create_hcd(struct xenbus_device *dev) @@ -165,6 +217,7 @@ static struct usb_hcd *create_hcd(struct int i; int err = 0; int num_ports; + int usb_ver; struct usb_hcd *hcd = NULL; struct usbfront_info *info = NULL; @@ -179,20 +232,38 @@ static struct usb_hcd *create_hcd(struct return ERR_PTR(-EINVAL); } - hcd = usb_create_hcd(&usbfront_hc_driver, &dev->dev, dev->dev.bus_id); + err = xenbus_scanf(XBT_NIL, dev->otherend, + "usb-ver", "%d", &usb_ver); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading usb-ver"); + return ERR_PTR(-EINVAL); + } + switch (usb_ver) { + case USB_VER_USB11: + hcd = usb_create_hcd(&xen_usb11_hc_driver, &dev->dev, dev->dev.bus_id); + break; + case USB_VER_USB20: + hcd = usb_create_hcd(&xen_usb20_hc_driver, &dev->dev, dev->dev.bus_id); + break; + default: + xenbus_dev_fatal(dev, err, "invalid usb-ver"); + return ERR_PTR(-EINVAL); + } if (!hcd) { - xenbus_dev_fatal(dev, err, "fail to allocate USB host controller"); + xenbus_dev_fatal(dev, err, + "fail to allocate USB host controller"); return ERR_PTR(-ENOMEM); } + info = hcd_to_info(hcd); info->xbdev = dev; info->rh_numports = num_ports; - for (i = 0; i < USB_RING_SIZE; i++) { - info->shadow[i].req.id = i+1; + for (i = 0; i < USB_URB_RING_SIZE; i++) { + info->shadow[i].req.id = i + 1; info->shadow[i].urb = NULL; } - info->shadow[USB_RING_SIZE-1].req.id = 0x0fff; + info->shadow[USB_URB_RING_SIZE-1].req.id = 0x0fff; return hcd; } @@ -211,7 +282,8 @@ static int usbfront_probe(struct xenbus_ hcd = create_hcd(dev); if (IS_ERR(hcd)) { err = PTR_ERR(hcd); - xenbus_dev_fatal(dev, err, "fail to create usb host controller"); + xenbus_dev_fatal(dev, err, + "fail to create usb host controller"); goto fail; } @@ -220,22 +292,19 @@ static int usbfront_probe(struct xenbus_ err = usb_add_hcd(hcd, 0, 0); if (err != 0) { - xenbus_dev_fatal(dev, err, "fail to adding USB host controller"); + xenbus_dev_fatal(dev, err, + "fail to adding USB host controller"); goto fail; } init_waitqueue_head(&info->wq); snprintf(name, TASK_COMM_LEN, "xenhcd.%d", hcd->self.busnum); info->kthread = kthread_run(xenhcd_schedule, info, name); - if (IS_ERR(info->kthread)) { - err = PTR_ERR(info->kthread); - info->kthread = NULL; - goto fail; - } - - err = talk_to_backend(dev, info); - if (err) - goto fail; + if (IS_ERR(info->kthread)) { + err = PTR_ERR(info->kthread); + info->kthread = NULL; + goto fail; + } return 0; @@ -245,68 +314,7 @@ fail: return err; } -/* - * 0=disconnected, 1=low_speed, 2=full_speed, 3=high_speed - */ -static void usbfront_do_hotplug(struct usbfront_info *info) -{ - char port_str[8]; - int i; - int err; - int state; - - for (i = 1; i <= info->rh_numports; i++) { - sprintf(port_str, "port-%d", i); - err = xenbus_scanf(XBT_NIL, info->xbdev->otherend, - port_str, "%d", &state); - if (err == 1) - xenhcd_rhport_state_change(info, i, state); - } -} - -static void backend_changed(struct xenbus_device *dev, - enum xenbus_state backend_state) -{ - struct usbfront_info *info = dev->dev.driver_data; - - switch (backend_state) { - case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateUnknown: - case XenbusStateClosed: - break; - - case XenbusStateConnected: - if (dev->state == XenbusStateConnected) - break; - if (dev->state == XenbusStateInitialised) - usbfront_do_hotplug(info); - xenbus_switch_state(dev, XenbusStateConnected); - break; - - case XenbusStateClosing: - xenbus_frontend_closed(dev); - break; - - case XenbusStateReconfiguring: - if (dev->state == XenbusStateConnected) - xenbus_switch_state(dev, XenbusStateReconfiguring); - break; - - case XenbusStateReconfigured: - usbfront_do_hotplug(info); - xenbus_switch_state(dev, XenbusStateConnected); - break; - - default: - xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", - backend_state); - break; - } -} - -static int usbfront_remove(struct xenbus_device *dev) +static void usbfront_disconnect(struct xenbus_device *dev) { struct usbfront_info *info = dev->dev.driver_data; struct usb_hcd *hcd = info_to_hcd(info); @@ -316,7 +324,46 @@ static int usbfront_remove(struct xenbus kthread_stop(info->kthread); info->kthread = NULL; } - usbif_free(info); + xenbus_frontend_closed(dev); +} + +static void backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateConnected: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + if (dev->state != XenbusStateInitialising) + break; + connect(dev); + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateClosing: + usbfront_disconnect(dev); + break; + + default: + xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", + backend_state); + break; + } +} + +static int usbfront_remove(struct xenbus_device *dev) +{ + struct usbfront_info *info = dev->dev.driver_data; + struct usb_hcd *hcd = info_to_hcd(info); + + destroy_rings(info); usb_put_hcd(hcd); return 0; @@ -361,5 +408,5 @@ module_exit(usbfront_exit); module_exit(usbfront_exit); MODULE_AUTHOR(""); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("Xen USB Virtual Host Controller driver (usbfront)"); MODULE_LICENSE("Dual BSD/GPL"); diff -r 7d57b5843b65 -r 498ac445a2a9 include/xen/interface/io/usbif.h --- a/include/xen/interface/io/usbif.h Wed Oct 07 07:33:40 2009 +0100 +++ b/include/xen/interface/io/usbif.h Wed Oct 07 08:42:00 2009 +0100 @@ -31,6 +31,13 @@ #include "ring.h" #include "../grant_table.h" +enum usb_spec_version { + USB_VER_UNKNOWN = 0, + USB_VER_USB11, + USB_VER_USB20, + USB_VER_USB30, /* not supported yet */ +}; + /* * USB pipe in usbif_request * @@ -57,21 +64,26 @@ * 10 = control, 11 = bulk) */ #define usbif_pipeportnum(pipe) ((pipe) & 0x1f) -#define usbif_setportnum_pipe(pipe,portnum) \ +#define usbif_setportnum_pipe(pipe, portnum) \ ((pipe)|(portnum)) + #define usbif_pipeunlink(pipe) ((pipe) & 0x20) +#define usbif_pipesubmit(pipe) (!usbif_pipeunlink(pipe)) #define usbif_setunlink_pipe(pipe) ((pipe)|(0x20)) #define USBIF_BACK_MAX_PENDING_REQS (128) -#define USBIF_MAX_SEGMENTS_PER_REQUEST (10) +#define USBIF_MAX_SEGMENTS_PER_REQUEST (16) +/* + * RING for transferring urbs. + */ struct usbif_request_segment { grant_ref_t gref; uint16_t offset; uint16_t length; }; -struct usbif_request { +struct usbif_urb_request { uint16_t id; /* request id */ uint16_t nr_buffer_segs; /* number of urb->transfer_buffer segments */ @@ -104,18 +116,36 @@ struct usbif_request { /* urb data segments */ struct usbif_request_segment seg[USBIF_MAX_SEGMENTS_PER_REQUEST]; }; -typedef struct usbif_request usbif_request_t; +typedef struct usbif_urb_request usbif_urb_request_t; -struct usbif_response { +struct usbif_urb_response { uint16_t id; /* request id */ uint16_t start_frame; /* start frame (ISO) */ int32_t status; /* status (non-ISO) */ int32_t actual_length; /* actual transfer length */ int32_t error_count; /* number of ISO errors */ }; -typedef struct usbif_response usbif_response_t; +typedef struct usbif_urb_response usbif_urb_response_t; -DEFINE_RING_TYPES(usbif, struct usbif_request, struct usbif_response); -#define USB_RING_SIZE __RING_SIZE((struct usbif_sring *)0, PAGE_SIZE) +DEFINE_RING_TYPES(usbif_urb, struct usbif_urb_request, struct usbif_urb_response); +#define USB_URB_RING_SIZE __RING_SIZE((struct usbif_urb_sring *)0, PAGE_SIZE) + +/* + * RING for notifying connect/disconnect events to frontend + */ +struct usbif_conn_request { + uint16_t id; +}; +typedef struct usbif_conn_request usbif_conn_request_t; + +struct usbif_conn_response { + uint16_t id; /* request id */ + uint8_t portnum; /* port number */ + uint8_t speed; /* usb_device_speed */ +}; +typedef struct usbif_conn_response usbif_conn_response_t; + +DEFINE_RING_TYPES(usbif_conn, struct usbif_conn_request, struct usbif_conn_response); +#define USB_CONN_RING_SIZE __RING_SIZE((struct usbif_conn_sring *)0, PAGE_SIZE) #endif /* __XEN_PUBLIC_IO_USBIF_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |