Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 155380
b: refs/heads/master
c: cb88a1b
h: refs/heads/master
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jul 12, 2009
1 parent ef8de34 commit 553c750
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 18 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 87ea8c887905d8b13ae90b537117592ed027632a
refs/heads/master: cb88a1b887bb8908f6e00ce29e893ea52b074940
4 changes: 4 additions & 0 deletions trunk/drivers/usb/core/hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ struct hc_driver {
/* has a port been handed over to a companion? */
int (*port_handed_over)(struct usb_hcd *, int);

/* CLEAR_TT_BUFFER completion callback */
void (*clear_tt_buffer_complete)(struct usb_hcd *,
struct usb_host_endpoint *);

/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
Expand Down
40 changes: 26 additions & 14 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
* talking to TTs must queue control transfers (not just bulk and iso), so
* both can talk to the same hub concurrently.
*/
static void hub_tt_kevent (struct work_struct *work)
static void hub_tt_work(struct work_struct *work)
{
struct usb_hub *hub =
container_of(work, struct usb_hub, tt.kevent);
container_of(work, struct usb_hub, tt.clear_work);
unsigned long flags;
int limit = 100;

Expand All @@ -462,6 +462,7 @@ static void hub_tt_kevent (struct work_struct *work)
struct list_head *next;
struct usb_tt_clear *clear;
struct usb_device *hdev = hub->hdev;
const struct hc_driver *drv;
int status;

next = hub->tt.clear_list.next;
Expand All @@ -471,21 +472,25 @@ static void hub_tt_kevent (struct work_struct *work)
/* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags);
status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
spin_lock_irqsave (&hub->tt.lock, flags);

if (status)
dev_err (&hdev->dev,
"clear tt %d (%04x) error %d\n",
clear->tt, clear->devinfo, status);

/* Tell the HCD, even if the operation failed */
drv = clear->hcd->driver;
if (drv->clear_tt_buffer_complete)
(drv->clear_tt_buffer_complete)(clear->hcd, clear->ep);

kfree(clear);
spin_lock_irqsave(&hub->tt.lock, flags);
}
spin_unlock_irqrestore (&hub->tt.lock, flags);
}

/**
* usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub
* @udev: the device whose split transaction failed
* @pipe: identifies the endpoint of the failed transaction
* usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub
* @urb: an URB associated with the failed or incomplete split transaction
*
* High speed HCDs use this to tell the hub driver that some split control or
* bulk transaction failed in a way that requires clearing internal state of
Expand All @@ -495,8 +500,10 @@ static void hub_tt_kevent (struct work_struct *work)
* It may not be possible for that hub to handle additional full (or low)
* speed transactions until that state is fully cleared out.
*/
void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
int usb_hub_clear_tt_buffer(struct urb *urb)
{
struct usb_device *udev = urb->dev;
int pipe = urb->pipe;
struct usb_tt *tt = udev->tt;
unsigned long flags;
struct usb_tt_clear *clear;
Expand All @@ -508,7 +515,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {
dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
/* FIXME recover somehow ... RESET_TT? */
return;
return -ENOMEM;
}

/* info that CLEAR_TT_BUFFER needs */
Expand All @@ -520,14 +527,19 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
: (USB_ENDPOINT_XFER_BULK << 11);
if (usb_pipein (pipe))
clear->devinfo |= 1 << 15;


/* info for completion callback */
clear->hcd = bus_to_hcd(udev->bus);
clear->ep = urb->ep;

/* tell keventd to clear state for this TT */
spin_lock_irqsave (&tt->lock, flags);
list_add_tail (&clear->clear_list, &tt->clear_list);
schedule_work (&tt->kevent);
schedule_work(&tt->clear_work);
spin_unlock_irqrestore (&tt->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);

/* If do_delay is false, return the number of milliseconds the caller
* needs to delay.
Expand Down Expand Up @@ -818,7 +830,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
if (hub->has_indicators)
cancel_delayed_work_sync(&hub->leds);
if (hub->tt.hub)
cancel_work_sync(&hub->tt.kevent);
cancel_work_sync(&hub->tt.clear_work);
}

/* caller has locked the hub device */
Expand Down Expand Up @@ -935,7 +947,7 @@ static int hub_configure(struct usb_hub *hub,

spin_lock_init (&hub->tt.lock);
INIT_LIST_HEAD (&hub->tt.clear_list);
INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
INIT_WORK(&hub->tt.clear_work, hub_tt_work);
switch (hdev->descriptor.bDeviceProtocol) {
case 0:
break;
Expand Down
6 changes: 4 additions & 2 deletions trunk/drivers/usb/core/hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,18 @@ struct usb_tt {
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
spinlock_t lock;
struct list_head clear_list; /* of usb_tt_clear */
struct work_struct kevent;
struct work_struct clear_work;
};

struct usb_tt_clear {
struct list_head clear_list;
unsigned tt;
u16 devinfo;
struct usb_hcd *hcd;
struct usb_host_endpoint *ep;
};

extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
extern int usb_hub_clear_tt_buffer(struct urb *urb);
extern void usb_ep0_reinit(struct usb_device *);

#endif /* __LINUX_HUB_H */
2 changes: 1 addition & 1 deletion trunk/drivers/usb/host/ehci-q.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ static int qtd_copy_status (
/* REVISIT ARC-derived cores don't clear the root
* hub TT buffer in this way...
*/
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
usb_hub_clear_tt_buffer(urb);
}
}

Expand Down

0 comments on commit 553c750

Please sign in to comment.