Commit d2435050 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

USB: make ehci driver use a kref instead of an atomic_t

parent cb71655f
...@@ -965,7 +965,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) ...@@ -965,7 +965,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
goto rescan; goto rescan;
case QH_STATE_IDLE: /* fully unlinked */ case QH_STATE_IDLE: /* fully unlinked */
if (list_empty (&qh->qtd_list)) { if (list_empty (&qh->qtd_list)) {
qh_put (ehci, qh); qh_put (qh);
break; break;
} }
/* else FALL THROUGH */ /* else FALL THROUGH */
......
...@@ -87,6 +87,22 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) ...@@ -87,6 +87,22 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
} }
static void qh_destroy (struct kref *kref)
{
struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
struct ehci_hcd *ehci = qh->ehci;
/* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n");
BUG ();
}
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
usb_put_dev (qh->dev);
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
}
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
{ {
struct ehci_qh *qh; struct ehci_qh *qh;
...@@ -98,7 +114,8 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -98,7 +114,8 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
return qh; return qh;
memset (qh, 0, sizeof *qh); memset (qh, 0, sizeof *qh);
atomic_set (&qh->refcount, 1); kref_init(&qh->kref, qh_destroy);
qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list); // INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list); INIT_LIST_HEAD (&qh->qtd_list);
...@@ -114,25 +131,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -114,25 +131,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
} }
/* to share a qh (cpu threads, or hc) */ /* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh) static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{ {
atomic_inc (&qh->refcount); kref_get(&qh->kref);
return qh; return qh;
} }
static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) static inline void qh_put (struct ehci_qh *qh)
{ {
if (!atomic_dec_and_test (&qh->refcount)) kref_put(&qh->kref);
return;
/* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n");
BUG ();
}
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
usb_put_dev (qh->dev);
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -145,7 +152,7 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -145,7 +152,7 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci) static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{ {
if (ehci->async) if (ehci->async)
qh_put (ehci, ehci->async); qh_put (ehci->async);
ehci->async = 0; ehci->async = 0;
/* DMA consistent memory and pools */ /* DMA consistent memory and pools */
......
...@@ -193,7 +193,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs) ...@@ -193,7 +193,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
/* ... update hc-wide periodic stats (for usbfs) */ /* ... update hc-wide periodic stats (for usbfs) */
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--; hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
} }
qh_put (ehci, qh); qh_put (qh);
} }
spin_lock (&urb->lock); spin_lock (&urb->lock);
...@@ -708,7 +708,7 @@ qh_make ( ...@@ -708,7 +708,7 @@ qh_make (
default: default:
dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done: done:
qh_put (ehci, qh); qh_put (qh);
return 0; return 0;
} }
...@@ -951,7 +951,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -951,7 +951,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
// qh->hw_next = cpu_to_le32 (qh->qh_dma); // qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = 0; qh->qh_next.qh = 0;
qh_put (ehci, qh); // refcount from reclaim qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim; next = qh->reclaim;
...@@ -965,7 +965,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -965,7 +965,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
&& HCD_IS_RUNNING (ehci->hcd.state)) && HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh); qh_link_async (ehci, qh);
else { else {
qh_put (ehci, qh); // refcount from async list qh_put (qh); // refcount from async list
/* it's not free to turn the async schedule on/off; leave it /* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties. * active but idle for a while once it empties.
...@@ -1067,7 +1067,7 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1067,7 +1067,7 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
qh = qh_get (qh); qh = qh_get (qh);
qh->stamp = ehci->stamp; qh->stamp = ehci->stamp;
temp = qh_completions (ehci, qh, regs); temp = qh_completions (ehci, qh, regs);
qh_put (ehci, qh); qh_put (qh);
if (temp != 0) { if (temp != 0) {
goto rescan; goto rescan;
} }
......
...@@ -312,7 +312,7 @@ static void intr_deschedule ( ...@@ -312,7 +312,7 @@ static void intr_deschedule (
do { do {
periodic_unlink (ehci, frame, qh); periodic_unlink (ehci, frame, qh);
qh_put (ehci, qh); qh_put (qh);
frame += qh->period; frame += qh->period;
} while (frame < ehci->periodic_size); } while (frame < ehci->periodic_size);
...@@ -355,7 +355,7 @@ static void intr_deschedule ( ...@@ -355,7 +355,7 @@ static void intr_deschedule (
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d", dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
qh, qh->period, frame, qh, qh->period, frame,
atomic_read (&qh->refcount), ehci->periodic_sched); atomic_read (&qh->kref.refcount), ehci->periodic_sched);
} }
static int check_period ( static int check_period (
...@@ -1846,7 +1846,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) ...@@ -1846,7 +1846,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
modified = qh_completions (ehci, temp.qh, regs); modified = qh_completions (ehci, temp.qh, regs);
if (unlikely (list_empty (&temp.qh->qtd_list))) if (unlikely (list_empty (&temp.qh->qtd_list)))
intr_deschedule (ehci, temp.qh, 0); intr_deschedule (ehci, temp.qh, 0);
qh_put (ehci, temp.qh); qh_put (temp.qh);
break; break;
case Q_TYPE_FSTN: case Q_TYPE_FSTN:
/* for "save place" FSTNs, look at QH entries /* for "save place" FSTNs, look at QH entries
......
...@@ -366,7 +366,8 @@ struct ehci_qh { ...@@ -366,7 +366,8 @@ struct ehci_qh {
struct ehci_qtd *dummy; struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */ struct ehci_qh *reclaim; /* next to reclaim */
atomic_t refcount; struct ehci_hcd *ehci;
struct kref kref;
unsigned stamp; unsigned stamp;
u8 qh_state; u8 qh_state;
......
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