Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / host / ehci-sched.c
index 2fa1ffe..5871944 100644 (file)
@@ -301,7 +301,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        dev_dbg (&qh->dev->dev,
                "link qh%d-%04x/%p start %d [%d/%d us]\n",
-               period, le32_to_cpup (&qh->hw_info2) & 0xffff,
+               period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
                qh, qh->start, qh->usecs, qh->c_usecs);
 
        /* high bandwidth, or otherwise every microframe */
@@ -385,7 +385,8 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        dev_dbg (&qh->dev->dev,
                "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
-               qh->period, le32_to_cpup (&qh->hw_info2) & 0xffff,
+               qh->period,
+               le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
                qh, qh->start, qh->usecs, qh->c_usecs);
 
        /* qh->qh_next still "live" to HC */
@@ -411,7 +412,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
         * active high speed queues may need bigger delays...
         */
        if (list_empty (&qh->qtd_list)
-                       || (__constant_cpu_to_le32 (0x0ff << 8)
+                       || (__constant_cpu_to_le32 (QH_CMASK)
                                        & qh->hw_info2) != 0)
                wait = 2;
        else
@@ -533,7 +534,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        /* reuse the previous schedule slots, if we can */
        if (frame < qh->period) {
-               uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+               uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
                status = check_intr_schedule (ehci, frame, --uframe,
                                qh, &c_mask);
        } else {
@@ -569,10 +570,10 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
                qh->start = frame;
 
                /* reset S-frame and (maybe) C-frame masks */
-               qh->hw_info2 &= __constant_cpu_to_le32 (~0xffff);
+               qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
                qh->hw_info2 |= qh->period
                        ? cpu_to_le32 (1 << uframe)
-                       : __constant_cpu_to_le32 (0xff);
+                       : __constant_cpu_to_le32 (QH_SMASK);
                qh->hw_info2 |= c_mask;
        } else
                ehci_dbg (ehci, "reused qh %p schedule\n", qh);
@@ -588,7 +589,7 @@ static int intr_submit (
        struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
-       int                     mem_flags
+       gfp_t                   mem_flags
 ) {
        unsigned                epnum;
        unsigned long           flags;
@@ -601,6 +602,12 @@ static int intr_submit (
 
        spin_lock_irqsave (&ehci->lock, flags);
 
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+                              &ehci_to_hcd(ehci)->flags))) {
+               status = -ESHUTDOWN;
+               goto done;
+       }
+
        /* get qh and force any scheduling errors */
        INIT_LIST_HEAD (&empty);
        qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
@@ -633,13 +640,12 @@ done:
 /* ehci_iso_stream ops work with both ITD and SITD */
 
 static struct ehci_iso_stream *
-iso_stream_alloc (int mem_flags)
+iso_stream_alloc (gfp_t mem_flags)
 {
        struct ehci_iso_stream *stream;
 
-       stream = kmalloc(sizeof *stream, mem_flags);
+       stream = kzalloc(sizeof *stream, mem_flags);
        if (likely (stream != NULL)) {
-               memset (stream, 0, sizeof(*stream));
                INIT_LIST_HEAD(&stream->td_list);
                INIT_LIST_HEAD(&stream->free_list);
                stream->next_uframe = -1;
@@ -700,6 +706,8 @@ iso_stream_init (
 
        } else {
                u32             addr;
+               int             think_time;
+               int             hs_transfers;
 
                addr = dev->ttport << 24;
                if (!ehci_is_TDI(ehci)
@@ -709,6 +717,10 @@ iso_stream_init (
                addr |= epnum << 8;
                addr |= dev->devnum;
                stream->usecs = HS_USECS_ISO (maxp);
+               think_time = dev->tt ? dev->tt->think_time : 0;
+               stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
+                               dev->speed, is_input, 1, maxp));
+               hs_transfers = max (1u, (maxp + 187) / 188);
                if (is_input) {
                        u32     tmp;
 
@@ -717,12 +729,11 @@ iso_stream_init (
                        stream->usecs = HS_USECS_ISO (1);
                        stream->raw_mask = 1;
 
-                       /* pessimistic c-mask */
-                       tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
-                                       / (125 * 1000);
-                       stream->raw_mask |= 3 << (tmp + 9);
+                       /* c-mask as specified in USB 2.0 11.18.4 3.c */
+                       tmp = (1 << (hs_transfers + 2)) - 1;
+                       stream->raw_mask |= tmp << (8 + 2);
                } else
-                       stream->raw_mask = smask_out [maxp / 188];
+                       stream->raw_mask = smask_out [hs_transfers - 1];
                bandwidth = stream->usecs + stream->c_usecs;
                bandwidth /= 1 << (interval + 2);
 
@@ -847,15 +858,14 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
 /* ehci_iso_sched ops can be ITD-only or SITD-only */
 
 static struct ehci_iso_sched *
-iso_sched_alloc (unsigned packets, int mem_flags)
+iso_sched_alloc (unsigned packets, gfp_t mem_flags)
 {
        struct ehci_iso_sched   *iso_sched;
        int                     size = sizeof *iso_sched;
 
        size += packets * sizeof (struct ehci_iso_packet);
-       iso_sched = kmalloc (size, mem_flags);
+       iso_sched = kzalloc(size, mem_flags);
        if (likely (iso_sched != NULL)) {
-               memset(iso_sched, 0, size);
                INIT_LIST_HEAD (&iso_sched->td_list);
        }
        return iso_sched;
@@ -894,7 +904,7 @@ itd_sched_init (
                trans |= length << 16;
                uframe->transaction = cpu_to_le32 (trans);
 
-               /* might need to cross a buffer page within a td */
+               /* might need to cross a buffer page within a uframe */
                uframe->bufp = (buf & ~(u64)0x0fff);
                buf += length;
                if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
@@ -920,7 +930,7 @@ itd_urb_transaction (
        struct ehci_iso_stream  *stream,
        struct ehci_hcd         *ehci,
        struct urb              *urb,
-       int                     mem_flags
+       gfp_t                   mem_flags
 )
 {
        struct ehci_itd         *itd;
@@ -1053,6 +1063,7 @@ sitd_slot_ok (
 
                /* for IN, check CSPLIT */
                if (stream->c_usecs) {
+                       uf = uframe & 7;
                        max_used = 100 - stream->c_usecs;
                        do {
                                tmp = 1 << uf;
@@ -1194,6 +1205,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
 {
        int i;
 
+       /* it's been recently zeroed */
        itd->hw_next = EHCI_LIST_END;
        itd->hw_bufp [0] = stream->buf0;
        itd->hw_bufp [1] = stream->buf1;
@@ -1210,8 +1222,7 @@ itd_patch (
        struct ehci_itd         *itd,
        struct ehci_iso_sched   *iso_sched,
        unsigned                index,
-       u16                     uframe,
-       int                     first
+       u16                     uframe
 )
 {
        struct ehci_iso_packet  *uf = &iso_sched->packet [index];
@@ -1228,7 +1239,7 @@ itd_patch (
        itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
 
        /* iso_frame_desc[].offset must be strictly increasing */
-       if (unlikely (!first && uf->cross)) {
+       if (unlikely (uf->cross)) {
                u64     bufp = uf->bufp + 4096;
                itd->pg = ++pg;
                itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
@@ -1257,7 +1268,7 @@ itd_link_urb (
        struct ehci_iso_stream  *stream
 )
 {
-       int                     packet, first = 1;
+       int                     packet;
        unsigned                next_uframe, uframe, frame;
        struct ehci_iso_sched   *iso_sched = urb->hcpriv;
        struct ehci_itd         *itd;
@@ -1290,7 +1301,6 @@ itd_link_urb (
                        list_move_tail (&itd->itd_list, &stream->td_list);
                        itd->stream = iso_stream_get (stream);
                        itd->urb = usb_get_urb (urb);
-                       first = 1;
                        itd_init (stream, itd);
                }
 
@@ -1298,8 +1308,7 @@ itd_link_urb (
                frame = next_uframe >> 3;
 
                itd->usecs [uframe] = stream->usecs;
-               itd_patch (itd, iso_sched, packet, uframe, first);
-               first = 0;
+               itd_patch (itd, iso_sched, packet, uframe);
 
                next_uframe += stream->interval;
                stream->depth += stream->interval;
@@ -1389,7 +1398,7 @@ itd_complete (
         */
 
        /* give urb back to the driver ... can be out-of-order */
-       dev = usb_get_dev (urb->dev);
+       dev = urb->dev;
        ehci_urb_done (ehci, urb, regs);
        urb = NULL;
 
@@ -1408,14 +1417,14 @@ itd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
-       usb_put_dev (dev);
 
        return 1;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
+       gfp_t mem_flags)
 {
        int                     status = -EINVAL;
        unsigned long           flags;
@@ -1453,7 +1462,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
-       status = iso_stream_schedule (ehci, urb, stream);
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+                              &ehci_to_hcd(ehci)->flags)))
+               status = -ESHUTDOWN;
+       else
+               status = iso_stream_schedule (ehci, urb, stream);
        if (likely (status == 0))
                itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1526,7 +1539,7 @@ sitd_urb_transaction (
        struct ehci_iso_stream  *stream,
        struct ehci_hcd         *ehci,
        struct urb              *urb,
-       int                     mem_flags
+       gfp_t                   mem_flags
 )
 {
        struct ehci_sitd        *sitd;
@@ -1750,7 +1763,7 @@ sitd_complete (
         */
 
        /* give urb back to the driver */
-       dev = usb_get_dev (urb->dev);
+       dev = urb->dev;
        ehci_urb_done (ehci, urb, regs);
        urb = NULL;
 
@@ -1769,13 +1782,13 @@ sitd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
-       usb_put_dev (dev);
 
        return 1;
 }
 
 
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+       gfp_t mem_flags)
 {
        int                     status = -EINVAL;
        unsigned long           flags;
@@ -1811,7 +1824,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
-       status = iso_stream_schedule (ehci, urb, stream);
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+                              &ehci_to_hcd(ehci)->flags)))
+               status = -ESHUTDOWN;
+       else
+               status = iso_stream_schedule (ehci, urb, stream);
        if (status == 0)
                sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1825,7 +1842,7 @@ done:
 #else
 
 static inline int
-sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
 {
        ehci_dbg (ehci, "split iso support is disabled\n");
        return -ENOSYS;