Commit 04538a25 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] UHCI: Eliminate the TD-removal list

This patch (as682) gets rid of the TD-removal list in uhci-hcd.  It is
no longer needed because now TDs are not freed until we know the
hardware isn't using them.  It also simplifies the code for adding and
removing TDs to/from URBs.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a0b458b6
...@@ -492,7 +492,6 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -492,7 +492,6 @@ static int uhci_start(struct usb_hcd *hcd)
spin_lock_init(&uhci->lock); spin_lock_init(&uhci->lock);
INIT_LIST_HEAD(&uhci->td_remove_list);
INIT_LIST_HEAD(&uhci->idle_qh_list); INIT_LIST_HEAD(&uhci->idle_qh_list);
init_waitqueue_head(&uhci->waitqh); init_waitqueue_head(&uhci->waitqh);
......
...@@ -228,7 +228,6 @@ struct uhci_td { ...@@ -228,7 +228,6 @@ struct uhci_td {
dma_addr_t dma_handle; dma_addr_t dma_handle;
struct list_head list; struct list_head list;
struct list_head remove_list;
int frame; /* for iso: what frame? */ int frame; /* for iso: what frame? */
struct list_head fl_list; struct list_head fl_list;
...@@ -420,10 +419,6 @@ struct uhci_hcd { ...@@ -420,10 +419,6 @@ struct uhci_hcd {
unsigned long resuming_ports; unsigned long resuming_ports;
unsigned long ports_timeout; /* Time to stop signalling */ unsigned long ports_timeout; /* Time to stop signalling */
/* List of TDs that are done, but waiting to be freed (race) */
struct list_head td_remove_list;
unsigned int td_remove_age; /* Age in frames */
struct list_head idle_qh_list; /* Where the idle QHs live */ struct list_head idle_qh_list; /* Where the idle QHs live */
int rh_numports; /* Number of root-hub ports */ int rh_numports; /* Number of root-hub ports */
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
* (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
*/ */
static void uhci_free_pending_tds(struct uhci_hcd *uhci);
/* /*
* Technically, updating td->status here is a race, but it's not really a * Technically, updating td->status here is a race, but it's not really a
...@@ -51,7 +50,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) ...@@ -51,7 +50,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
td->frame = -1; td->frame = -1;
INIT_LIST_HEAD(&td->list); INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list); INIT_LIST_HEAD(&td->fl_list);
return td; return td;
...@@ -61,8 +59,6 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) ...@@ -61,8 +59,6 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{ {
if (!list_empty(&td->list)) if (!list_empty(&td->list))
dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
if (!list_empty(&td->remove_list))
dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
if (!list_empty(&td->fl_list)) if (!list_empty(&td->fl_list))
dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
...@@ -77,6 +73,16 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status, ...@@ -77,6 +73,16 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
td->buffer = cpu_to_le32(buffer); td->buffer = cpu_to_le32(buffer);
} }
static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
{
list_add_tail(&td->list, &urbp->td_list);
}
static void uhci_remove_td_from_urbp(struct uhci_td *td)
{
list_del_init(&td->list);
}
/* /*
* We insert Isochronous URBs directly into the frame list at the beginning * We insert Isochronous URBs directly into the frame list at the beginning
*/ */
...@@ -421,21 +427,6 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, ...@@ -421,21 +427,6 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
return urbp; return urbp;
} }
static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
list_add_tail(&td->list, &urbp->td_list);
}
static void uhci_remove_td_from_urb(struct uhci_td *td)
{
if (list_empty(&td->list))
return;
list_del_init(&td->list);
}
static void uhci_free_urb_priv(struct uhci_hcd *uhci, static void uhci_free_urb_priv(struct uhci_hcd *uhci,
struct urb_priv *urbp) struct urb_priv *urbp)
{ {
...@@ -445,20 +436,9 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, ...@@ -445,20 +436,9 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
urbp->urb); urbp->urb);
uhci_get_current_frame_number(uhci);
if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
uhci_free_pending_tds(uhci);
uhci->td_remove_age = uhci->frame_number;
}
/* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the TDs. */
if (list_empty(&uhci->td_remove_list))
uhci_set_next_interrupt(uhci);
list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
uhci_remove_td_from_urb(td); uhci_remove_td_from_urbp(td);
list_add(&td->remove_list, &uhci->td_remove_list); uhci_free_td(uhci, td);
} }
urbp->urb->hcpriv = NULL; urbp->urb->hcpriv = NULL;
...@@ -529,6 +509,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -529,6 +509,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
int len = urb->transfer_buffer_length; int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma; dma_addr_t data = urb->transfer_dma;
__le32 *plink; __le32 *plink;
struct urb_priv *urbp = urb->hcpriv;
/* The "pipe" thing contains the destination in bits 8--18 */ /* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
...@@ -542,7 +523,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -542,7 +523,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* Build the TD for the control request setup packet * Build the TD for the control request setup packet
*/ */
td = qh->dummy_td; td = qh->dummy_td;
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(8), uhci_fill_td(td, status, destination | uhci_explen(8),
urb->setup_dma); urb->setup_dma);
plink = &td->link; plink = &td->link;
...@@ -574,7 +555,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -574,7 +555,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
/* Alternate Data0/1 (start with Data1) */ /* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE; destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_explen(pktsze), uhci_fill_td(td, status, destination | uhci_explen(pktsze),
data); data);
plink = &td->link; plink = &td->link;
...@@ -605,7 +586,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -605,7 +586,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
status &= ~TD_CTRL_SPD; status &= ~TD_CTRL_SPD;
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status | TD_CTRL_IOC, uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0); destination | uhci_explen(0), 0);
plink = &td->link; plink = &td->link;
...@@ -640,7 +621,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, ...@@ -640,7 +621,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
nomem: nomem:
/* Remove the dummy TD from the td_list so it doesn't get freed */ /* Remove the dummy TD from the td_list so it doesn't get freed */
uhci_remove_td_from_urb(qh->dummy_td); uhci_remove_td_from_urbp(qh->dummy_td);
return -ENOMEM; return -ENOMEM;
} }
...@@ -656,6 +637,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -656,6 +637,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
int len = urb->transfer_buffer_length; int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma; dma_addr_t data = urb->transfer_dma;
__le32 *plink; __le32 *plink;
struct urb_priv *urbp = urb->hcpriv;
unsigned int toggle; unsigned int toggle;
if (len < 0) if (len < 0)
...@@ -693,7 +675,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -693,7 +675,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
goto nomem; goto nomem;
*plink = cpu_to_le32(td->dma_handle); *plink = cpu_to_le32(td->dma_handle);
} }
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, uhci_fill_td(td, status,
destination | uhci_explen(pktsze) | destination | uhci_explen(pktsze) |
(toggle << TD_TOKEN_TOGGLE_SHIFT), (toggle << TD_TOKEN_TOGGLE_SHIFT),
...@@ -721,7 +703,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -721,7 +703,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
goto nomem; goto nomem;
*plink = cpu_to_le32(td->dma_handle); *plink = cpu_to_le32(td->dma_handle);
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, uhci_fill_td(td, status,
destination | uhci_explen(0) | destination | uhci_explen(0) |
(toggle << TD_TOKEN_TOGGLE_SHIFT), (toggle << TD_TOKEN_TOGGLE_SHIFT),
...@@ -758,7 +740,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, ...@@ -758,7 +740,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
nomem: nomem:
/* Remove the dummy TD from the td_list so it doesn't get freed */ /* Remove the dummy TD from the td_list so it doesn't get freed */
uhci_remove_td_from_urb(qh->dummy_td); uhci_remove_td_from_urbp(qh->dummy_td);
return -ENOMEM; return -ENOMEM;
} }
...@@ -830,8 +812,8 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, ...@@ -830,8 +812,8 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
td = list_entry(tmp, struct uhci_td, list); td = list_entry(tmp, struct uhci_td, list);
tmp = tmp->prev; tmp = tmp->prev;
uhci_remove_td_from_urb(td); uhci_remove_td_from_urbp(td);
list_add(&td->remove_list, &uhci->td_remove_list); uhci_free_td(uhci, td);
} }
return ret; return ret;
} }
...@@ -885,10 +867,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) ...@@ -885,10 +867,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
ret = 1; ret = 1;
} }
uhci_remove_td_from_urb(td); uhci_remove_td_from_urbp(td);
if (qh->post_td) if (qh->post_td)
list_add(&qh->post_td->remove_list, uhci_free_td(uhci, qh->post_td);
&uhci->td_remove_list);
qh->post_td = td; qh->post_td = td;
if (ret != 0) if (ret != 0)
...@@ -957,7 +938,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, ...@@ -957,7 +938,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
if (!td) if (!td)
return -ENOMEM; return -ENOMEM;
uhci_add_td_to_urb(urb, td); uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status, destination | uhci_fill_td(td, status, destination |
uhci_explen(urb->iso_frame_desc[i].length), uhci_explen(urb->iso_frame_desc[i].length),
urb->transfer_dma + urb->transfer_dma +
...@@ -1267,17 +1248,6 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, ...@@ -1267,17 +1248,6 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
uhci_make_qh_idle(uhci, qh); uhci_make_qh_idle(uhci, qh);
} }
static void uhci_free_pending_tds(struct uhci_hcd *uhci)
{
struct uhci_td *td, *tmp;
list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
list_del_init(&td->remove_list);
uhci_free_td(uhci, td);
}
}
/* /*
* Process events in the schedule, but only in one thread at a time * Process events in the schedule, but only in one thread at a time
*/ */
...@@ -1298,9 +1268,6 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) ...@@ -1298,9 +1268,6 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
uhci_clear_next_interrupt(uhci); uhci_clear_next_interrupt(uhci);
uhci_get_current_frame_number(uhci); uhci_get_current_frame_number(uhci);
if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
uhci_free_pending_tds(uhci);
/* Go through all the QH queues and process the URBs in each one */ /* Go through all the QH queues and process the URBs in each one */
for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
uhci->next_qh = list_entry(uhci->skelqh[i]->node.next, uhci->next_qh = list_entry(uhci->skelqh[i]->node.next,
...@@ -1316,12 +1283,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) ...@@ -1316,12 +1283,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
goto rescan; goto rescan;
uhci->scan_in_progress = 0; uhci->scan_in_progress = 0;
/* If the controller is stopped, we can finish these off right now */ if (list_empty(&uhci->skel_unlink_qh->node))
if (uhci->is_stopped)
uhci_free_pending_tds(uhci);
if (list_empty(&uhci->td_remove_list) &&
list_empty(&uhci->skel_unlink_qh->node))
uhci_clear_next_interrupt(uhci); uhci_clear_next_interrupt(uhci);
else else
uhci_set_next_interrupt(uhci); uhci_set_next_interrupt(uhci);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment