ChangeSet 1.1371.759.35, 2004/04/27 14:45:49-07:00, greg@kroah.com USB: make ehci driver use a kref instead of an atomic_t drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/ehci-mem.c | 39 +++++++++++++++++++++++---------------- drivers/usb/host/ehci-q.c | 10 +++++----- drivers/usb/host/ehci-sched.c | 6 +++--- drivers/usb/host/ehci.h | 3 ++- 5 files changed, 34 insertions(+), 26 deletions(-) diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Fri May 14 15:32:02 2004 +++ b/drivers/usb/host/ehci-hcd.c Fri May 14 15:32:02 2004 @@ -965,7 +965,7 @@ goto rescan; case QH_STATE_IDLE: /* fully unlinked */ if (list_empty (&qh->qtd_list)) { - qh_put (ehci, qh); + qh_put (qh); break; } /* else FALL THROUGH */ diff -Nru a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c --- a/drivers/usb/host/ehci-mem.c Fri May 14 15:32:02 2004 +++ b/drivers/usb/host/ehci-mem.c Fri May 14 15:32:02 2004 @@ -87,6 +87,22 @@ } +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) { struct ehci_qh *qh; @@ -98,7 +114,8 @@ return qh; memset (qh, 0, sizeof *qh); - atomic_set (&qh->refcount, 1); + kref_init(&qh->kref, qh_destroy); + qh->ehci = ehci; qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); @@ -114,25 +131,15 @@ } /* 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; } -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)) - 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); + kref_put(&qh->kref); } /*-------------------------------------------------------------------------*/ @@ -145,7 +152,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) { if (ehci->async) - qh_put (ehci, ehci->async); + qh_put (ehci->async); ehci->async = 0; /* DMA consistent memory and pools */ diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Fri May 14 15:32:02 2004 +++ b/drivers/usb/host/ehci-q.c Fri May 14 15:32:02 2004 @@ -193,7 +193,7 @@ /* ... update hc-wide periodic stats (for usbfs) */ hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--; } - qh_put (ehci, qh); + qh_put (qh); } spin_lock (&urb->lock); @@ -708,7 +708,7 @@ default: dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); done: - qh_put (ehci, qh); + qh_put (qh); return 0; } @@ -951,7 +951,7 @@ // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; 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) */ next = qh->reclaim; @@ -965,7 +965,7 @@ && HCD_IS_RUNNING (ehci->hcd.state)) qh_link_async (ehci, qh); 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 * active but idle for a while once it empties. @@ -1067,7 +1067,7 @@ qh = qh_get (qh); qh->stamp = ehci->stamp; temp = qh_completions (ehci, qh, regs); - qh_put (ehci, qh); + qh_put (qh); if (temp != 0) { goto rescan; } diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c Fri May 14 15:32:02 2004 +++ b/drivers/usb/host/ehci-sched.c Fri May 14 15:32:02 2004 @@ -312,7 +312,7 @@ do { periodic_unlink (ehci, frame, qh); - qh_put (ehci, qh); + qh_put (qh); frame += qh->period; } while (frame < ehci->periodic_size); @@ -355,7 +355,7 @@ dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d", qh, qh->period, frame, - atomic_read (&qh->refcount), ehci->periodic_sched); + atomic_read (&qh->kref.refcount), ehci->periodic_sched); } static int check_period ( @@ -1846,7 +1846,7 @@ modified = qh_completions (ehci, temp.qh, regs); if (unlikely (list_empty (&temp.qh->qtd_list))) intr_deschedule (ehci, temp.qh, 0); - qh_put (ehci, temp.qh); + qh_put (temp.qh); break; case Q_TYPE_FSTN: /* for "save place" FSTNs, look at QH entries diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h Fri May 14 15:32:02 2004 +++ b/drivers/usb/host/ehci.h Fri May 14 15:32:02 2004 @@ -366,7 +366,8 @@ struct ehci_qtd *dummy; struct ehci_qh *reclaim; /* next to reclaim */ - atomic_t refcount; + struct ehci_hcd *ehci; + struct kref kref; unsigned stamp; u8 qh_state;