]> git.hungrycats.org Git - linux/commitdiff
v2.4.12.4 -> v2.4.12.5
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:24:42 +0000 (20:24 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:24:42 +0000 (20:24 -0800)
  - Greg KH: usbnet fix
  - Johannes Erdfelt: uhci.c bulk queueing fixes

Makefile
drivers/char/joystick/analog.c
drivers/usb/uhci.c
drivers/usb/uhci.h
drivers/usb/usbnet.c
fs/buffer.c
mm/page_alloc.c
mm/vmscan.c

index 282423721d6c433d175ada61d86b1cdd4b9714eb..469ed2c44dfc687214f8c87ddb8e739ea7b9b758 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 13
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index d04cb55ea6912e8104a2319d8df517fd4aaf5fae..bbab2f946c306f7967568d5469c252d51644af9e 100644 (file)
@@ -138,7 +138,7 @@ struct analog_port {
 
 #ifdef __i386__
 #define TSC_PRESENT    (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)    do { if (TSC_PRESENT) rdtscl(x); else outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define GET_TIME(x)    do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
 #define DELTA(x,y)     (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
 #define TIME_NAME      (TSC_PRESENT?"TSC":"PIT")
 #elif __x86_64__
@@ -499,7 +499,9 @@ static void analog_init_device(struct analog_port *port, struct analog *analog,
        else
                printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
                port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-               port->speed > 10000 ? "M" : "k", (port->loop * 1000000) / port->speed);
+               port->speed > 10000 ? "M" : "k",
+               port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
+                                   : (port->loop * 1000000) / port->speed);
 }
 
 /*
index 511df4453efe7c7e95092785981c2487b6be02b5..af8f012665b63d3592f9463ccc55a085b18823b4 100644 (file)
@@ -113,44 +113,6 @@ static int uhci_alloc_dev(struct usb_device *dev)
 
 static int uhci_free_dev(struct usb_device *dev)
 {
-       struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-       struct list_head list, *tmp, *head;
-       unsigned long flags;
-
-       /* Walk through the entire URB list and forcefully remove any */
-       /*  URBs that are still active for that device */
-
-       /* Two stage unlink so we don't deadlock on urb_list_lock */
-       INIT_LIST_HEAD(&list);
-
-       spin_lock_irqsave(&uhci->urb_list_lock, flags);
-       head = &uhci->urb_list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-               tmp = tmp->next;
-
-               if (urb->dev == dev) {
-                       list_del(&urb->urb_list);
-                       list_add(&urb->urb_list, &list);
-               }
-       }
-       spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-       head = &list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb *urb = list_entry(tmp, struct urb, urb_list);
-               tmp = tmp->next;
-
-               /* Make sure we block waiting on these to die */
-               urb->transfer_flags &= ~USB_ASYNC_UNLINK;
-
-               /* uhci_unlink_urb will unlink from the temp list */
-               uhci_unlink_urb(urb);
-       }
-
        return 0;
 }
 
@@ -396,50 +358,96 @@ static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
        pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
+static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
 {
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       struct list_head *head, *tmp;
        struct uhci_qh *lqh;
-       unsigned long flags;
-
-       spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
        /* Grab the last QH */
        lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
-       qh->link = lqh->link;
+       if (lqh->urbp) {
+               head = &lqh->urbp->queue_list;
+               tmp = head->next;
+               while (head != tmp) {
+                       struct urb_priv *turbp =
+                               list_entry(tmp, struct urb_priv, queue_list);
+
+                       tmp = tmp->next;
+
+                       turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+               }
+       }
+
+       head = &urbp->queue_list;
+       tmp = head->next;
+       while (head != tmp) {
+               struct urb_priv *turbp =
+                       list_entry(tmp, struct urb_priv, queue_list);
+
+               tmp = tmp->next;
+
+               turbp->qh->link = lqh->link;
+       }
+
+       urbp->qh->link = lqh->link;
        mb();                           /* Ordering is important */
-       lqh->link = qh->dma_handle | UHCI_PTR_QH;
+       lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+       list_add_tail(&urbp->qh->list, &skelqh->list);
+}
 
-       list_add_tail(&qh->list, &skelqh->list);
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+       unsigned long flags;
 
+       spin_lock_irqsave(&uhci->frame_list_lock, flags);
+       _uhci_insert_qh(uhci, skelqh, urb);
        spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+static void uhci_remove_qh(struct uhci *uhci, struct urb *urb)
 {
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
        unsigned long flags;
-       struct uhci_qh *prevqh;
+       struct uhci_qh *qh = urbp->qh, *pqh;
+
+       if (!qh)
+               return;
 
        /* Only go through the hoops if it's actually linked in */
-       if (list_empty(&qh->list)) {
-               goto list;
-       }
+       if (!list_empty(&qh->list)) {
+               qh->urbp = NULL;
 
-       qh->urbp = NULL;
+               spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-       spin_lock_irqsave(&uhci->frame_list_lock, flags);
+               pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
-       prevqh = list_entry(qh->list.prev, struct uhci_qh, list);
+               if (pqh->urbp) {
+                       struct list_head *head, *tmp;
 
-       prevqh->link = qh->link;
-       mb();
-       qh->element = qh->link = UHCI_PTR_TERM;
+                       head = &pqh->urbp->queue_list;
+                       tmp = head->next;
+                       while (head != tmp) {
+                               struct urb_priv *turbp =
+                                       list_entry(tmp, struct urb_priv, queue_list);
 
-       list_del_init(&qh->list);
+                               tmp = tmp->next;
 
-       spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+                               turbp->qh->link = qh->link;
+                       }
+               }
+
+               pqh->link = qh->link;
+               mb();
+               qh->element = qh->link = UHCI_PTR_TERM;
+
+               list_del_init(&qh->list);
+
+               spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+       }
 
-list:
        spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
        /* Check to see if the remove list is empty. Set the IOC bit */
@@ -464,9 +472,10 @@ static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
 
                tmp = tmp->next;
 
-               td->info &= ~(1 << TD_TOKEN_TOGGLE);
                if (toggle)
-                       td->info |= (1 << TD_TOKEN_TOGGLE);
+                       set_bit(TD_TOKEN_TOGGLE, &td->info);
+               else
+                       clear_bit(TD_TOKEN_TOGGLE, &td->info);
 
                toggle ^= 1;
        }
@@ -481,7 +490,7 @@ static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct u
 {
        struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
        struct list_head *tmp;
-       struct uhci_td *ftd, *lltd;
+       struct uhci_td *lltd;
        unsigned long flags;
 
        eurbp = eurb->hcpriv;
@@ -510,13 +519,15 @@ static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct u
        lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
 
        lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-       ftd = list_entry(urbp->td_list.next, struct uhci_td, list);
 
        uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
 
+       /* All qh's in the queue need to link to the next queue */
+       urbp->qh->link = eurbp->qh->link;
+
        mb();                   /* Make sure we flush everything */
        /* Only support bulk right now, so no depth */
-       lltd->link = ftd->dma_handle;
+       lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
 
        list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
@@ -576,30 +587,9 @@ static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
                usb_pipeout(urb->pipe), toggle);
 
        if (!urbp->queued) {
-               int status;
-
-               /*  The HC may continue using the current QH if it finished */
-               /* all of the TD's in this URB and may have started on the */
-               /* next URB's TD's already, so we'll take over ownership */
-               /* of this QH and use it instead. Don't forget to delete */
-               /* the old QH first */
-               uhci_free_qh(uhci, nurbp->qh);
-
-               nurbp->qh = urbp->qh;
-               nurbp->qh->urbp = nurbp;
-               urbp->qh = NULL;
-
-               /* If the last TD from the first (this) urb didn't */
-               /*  complete, reset qh->element to the first TD in the */
-               /*  next urb */
-               pltd = list_entry(urbp->td_list.prev, struct uhci_td, list);
-               status = uhci_status_bits(pltd->status);
-               if ((status & TD_CTRL_ACTIVE) || uhci_actual_length(pltd->status) < uhci_expected_length(pltd->info)) {
-                       struct uhci_td *ftd = list_entry(nurbp->td_list.next, struct uhci_td, list);
-                       nurbp->qh->element = ftd->dma_handle;
-               }
-
                nurbp->queued = 0;
+
+               _uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
        } else {
                /* We're somewhere in the middle (or end). A bit trickier */
                /*  than the head scenario */
@@ -607,15 +597,10 @@ static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
                                queue_list);
 
                pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-               if (nurbp->queued) {
-                       struct uhci_td *nftd;
-
-                       /* Close the gap between the two */
-                       nftd = list_entry(nurbp->td_list.next, struct uhci_td,
-                                       list);
-                       pltd->link = nftd->dma_handle;
-               } else
-                       /* The next URB happens to be the beggining, so */
+               if (nurbp->queued)
+                       pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
+               else
+                       /* The next URB happens to be the beginning, so */
                        /*  we're the last, end the chain */
                        pltd->link = UHCI_PTR_TERM;
        }
@@ -639,6 +624,7 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
        memset((void *)urbp, 0, sizeof(*urbp));
 
        urbp->inserttime = jiffies;
+       urbp->fsbrtime = jiffies;
        urbp->urb = urb;
        urbp->dev = urb->dev;
        
@@ -900,19 +886,19 @@ static int uhci_submit_control(struct urb *urb)
        if (!qh)
                return -ENOMEM;
 
+       urbp->qh = qh;
+       qh->urbp = urbp;
+
        /* Low speed or small transfers gets a different queue and treatment */
        if (urb->pipe & TD_CTRL_LS) {
                uhci_insert_tds_in_qh(qh, urb, 0);
-               uhci_insert_qh(uhci, uhci->skel_ls_control_qh, qh);
+               uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
        } else {
                uhci_insert_tds_in_qh(qh, urb, 1);
-               uhci_insert_qh(uhci, uhci->skel_hs_control_qh, qh);
+               uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
                uhci_inc_fsbr(uhci, urb);
        }
 
-       urbp->qh = qh;
-       qh->urbp = urbp;
-
        return -EINPROGRESS;
 }
 
@@ -961,6 +947,7 @@ static int uhci_result_control(struct urb *urb)
                    !(td->status & TD_CTRL_ACTIVE)) {
                        uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
                        urbp->fsbr_timeout = 0;
+                       urbp->fsbrtime = jiffies;
                        clear_bit(TD_CTRL_IOC_BIT, &td->status);
                }
 
@@ -1043,7 +1030,7 @@ static int usb_control_retrigger_status(struct urb *urb)
        urbp->short_control_packet = 1;
 
        /* Create a new QH to avoid pointer overwriting problems */
-       uhci_remove_qh(uhci, urbp->qh);
+       uhci_remove_qh(uhci, urb);
 
        /* Delete all of the TD's except for the status TD at the end */
        head = &urbp->td_list;
@@ -1071,9 +1058,9 @@ static int usb_control_retrigger_status(struct urb *urb)
 
        /* Low speed or small transfers gets a different queue and treatment */
        if (urb->pipe & TD_CTRL_LS)
-               uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urbp->qh);
+               uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
        else
-               uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urbp->qh);
+               uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 
        return -EINPROGRESS;
 }
@@ -1134,6 +1121,7 @@ static int uhci_result_interrupt(struct urb *urb)
                    !(td->status & TD_CTRL_ACTIVE)) {
                        uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
                        urbp->fsbr_timeout = 0;
+                       urbp->fsbrtime = jiffies;
                        clear_bit(TD_CTRL_IOC_BIT, &td->status);
                }
 
@@ -1147,10 +1135,6 @@ static int uhci_result_interrupt(struct urb *urb)
                        goto td_error;
 
                if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-                       usb_settoggle(urb->dev, uhci_endpoint(td->info),
-                               uhci_packetout(td->info),
-                               uhci_toggle(td->info) ^ 1);
-
                        if (urb->transfer_flags & USB_DISABLE_SPD) {
                                ret = -EREMOTEIO;
                                goto err;
@@ -1303,7 +1287,7 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
        if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
                uhci_append_queued_urb(uhci, eurb, urb);
        else
-               uhci_insert_qh(uhci, uhci->skel_bulk_qh, qh);
+               uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
 
        uhci_inc_fsbr(uhci, urb);
 
@@ -1681,6 +1665,7 @@ static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
 
 static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
 {
+       struct list_head *head, *tmp;
        struct urb_priv *urbp = urb->hcpriv;
 
        /* We can get called when urbp allocation fails, so check */
@@ -1689,15 +1674,30 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
 
        uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
 
+       head = &urbp->td_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+               tmp = tmp->next;
+
+               /* Control and Isochronous ignore the toggle, so this */
+               /* is safe for all types */
+               if (!(td->status & TD_CTRL_ACTIVE) &&
+                   uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+                   tmp == head) {
+                       usb_settoggle(urb->dev, uhci_endpoint(td->info),
+                               uhci_packetout(td->info),
+                               uhci_toggle(td->info) ^ 1);
+               }
+       }
+
        uhci_delete_queued_urb(uhci, urb);
 
-       if (urbp->qh)
-               /* The interrupt loop will reclaim the QH's */
-               uhci_remove_qh(uhci, urbp->qh);
+       /* The interrupt loop will reclaim the QH's */
+       uhci_remove_qh(uhci, urb);
 }
 
-/* FIXME: If we forcefully unlink an urb, we should reset the toggle for */
-/*  that pipe to match what actually completed */
 static int uhci_unlink_urb(struct urb *urb)
 {
        struct uhci *uhci;
@@ -1951,11 +1951,11 @@ static void rh_int_timer_do(unsigned long ptr)
                tmp = tmp->next;
 
                /* Check if the FSBR timed out */
-               if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+               if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))
                        uhci_fsbr_timeout(uhci, u);
 
                /* Check if the URB timed out */
-               if (u->timeout && time_after_eq(jiffies, u->timeout)) {
+               if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
                        list_del(&u->urb_list);
                        list_add_tail(&u->urb_list, &list);
                }
index d9e728b299633e348e650ebe6a58bd0681161a9f..c2b17f6705a1245769dc4b4184ff9c8b5276ebd9 100644 (file)
@@ -345,6 +345,7 @@ struct urb_priv {
        int status;                     /* Final status */
 
        unsigned long inserttime;       /* In jiffies */
+       unsigned long fsbrtime; /* In jiffies */
 
        struct list_head queue_list;
        struct list_head complete_list;
index 32d9f6936e2eed021cd26e7cec5063057606e758..6981f543fe9cc59dcc112d5381eb921e53b2f7cb 100644 (file)
@@ -15,7 +15,7 @@
  * support as appropriate.  Devices currently supported include:
  *
  *     - AnchorChip 2720
- *     - Belkin F5U104 (custom)
+ *     - Belkin, eTEK (interops with Win32 drivers)
  *     - "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *     - NetChip 1080 (interoperates with NetChip Win32 drivers)
  *     - Prolific PL-2301/2302 (replaces "plusb" driver)
@@ -73,6 +73,9 @@
  *             Win32 Belkin driver; other cleanups (db).
  * 16-jul-2001 Bugfixes for uhci oops-on-unplug, Belkin support, various
  *             cleanups for problems not yet seen in the field. (db)
+ * 17-oct-2001 Handle "Advance USBNET" product, like Belkin/eTEK devices,
+ *             from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
+ *             rx unlinks somehow weren't async; minor cleanup.
  *
  *-------------------------------------------------------------------------*/
 
 
 
 #define        CONFIG_USB_AN2720
-#define        CONFIG_USB_BELKIN_F5U104
+#define        CONFIG_USB_BELKIN
 #define        CONFIG_USB_LINUXDEV
 #define        CONFIG_USB_NET1080
 #define        CONFIG_USB_PL2301
 #endif
 
 // packets are always ethernet inside
-// ... except they can be bigger (up to 64K with this framing)
+// ... except they can be bigger (limit of 64K with NetChip framing)
 #define MIN_PACKET     sizeof(struct ethhdr)
 #define MAX_PACKET     32768
 
@@ -161,7 +164,7 @@ struct usbnet {
        struct sk_buff_head     txq;
        struct sk_buff_head     done;
        struct tasklet_struct   bh;
-       struct tq_struct ctrl_task;
+       struct tq_struct        ctrl_task;
 };
 
 // device-specific info used by the driver
@@ -169,7 +172,8 @@ struct driver_info {
        char            *description;
 
        int             flags;
-#define FLAG_FRAMING   0x0001          /* guard against device dropouts */ 
+#define FLAG_FRAMING_NC        0x0001          /* guard against device dropouts */ 
+#define FLAG_NO_SETINT 0x0010          /* device can't set_interface() */
 
        /* reset device ... can sleep */
        int     (*reset)(struct usbnet *);
@@ -251,7 +255,7 @@ struct nc_trailer {
        u16     packet_id;
 } __attribute__((__packed__));
 
-// packets may use FLAG_FRAMING and optional pad
+// packets may use FLAG_FRAMING_NC and optional pad
 #define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
                                + sizeof (struct ethhdr) \
                                + (mtu) \
@@ -288,22 +292,24 @@ static const struct driver_info   an2720_info = {
 
 
 \f
-#ifdef CONFIG_USB_BELKIN_F5U104
+#ifdef CONFIG_USB_BELKIN
 
 /*-------------------------------------------------------------------------
  *
  * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller
  *
+ * ... also two eTEK designs, including one sold as "Advance USBNET"
+ *
  *-------------------------------------------------------------------------*/
 
 static const struct driver_info        belkin_info = {
-       description:    "Belkin USB Direct Connect (F5U104)",
+       description:    "Belkin, eTEK, or compatible",
 
        in: 1, out: 1,          // direction distinguishes these
        epsize: 64,
 };
 
-#endif /* CONFIG_USB_BELKIN_F5U104 */
+#endif /* CONFIG_USB_BELKIN */
 
 
 \f
@@ -632,7 +638,7 @@ static int net1080_check_connect (struct usbnet *dev)
 
 static const struct driver_info        net1080_info = {
        description:    "NetChip TurboCONNECT",
-       flags:          FLAG_FRAMING,
+       flags:          FLAG_FRAMING_NC,
        reset:          net1080_reset,
        check_connect:  net1080_check_connect,
 
@@ -729,9 +735,9 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
 {
        struct usbnet   *dev = (struct usbnet *) net->priv;
 
-       if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
+       if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
                return -EINVAL;
-       if (((dev->driver_info->flags) & FLAG_FRAMING)) {
+       if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) {
                if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
                        return -EINVAL;
        // no second zero-length packet read wanted after mtu-sized packets
@@ -779,9 +785,11 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
        unsigned long           lockflags;
        size_t                  size;
 
-       size = (dev->driver_info->flags & FLAG_FRAMING)
-                       ? FRAMED_SIZE (dev->net.mtu)
-                       : (sizeof (struct ethhdr) + dev->net.mtu);
+       if (dev->driver_info->flags & FLAG_FRAMING_NC)
+               size = FRAMED_SIZE (dev->net.mtu);
+       else
+               size = (sizeof (struct ethhdr) + dev->net.mtu);
+
        if ((skb = alloc_skb (size, flags)) == 0) {
                dbg ("no rx skb");
                tasklet_schedule (&dev->bh);
@@ -798,9 +806,15 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
        FILL_BULK_URB (urb, dev->udev,
                usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
                skb->data, size, rx_complete, skb);
+       urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef REALLY_QUEUE
        urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
+#if 0
+       // Idle-but-posted reads with UHCI really chew up
+       // PCI bandwidth unless FSBR is disabled
+       urb->transfer_flags |= USB_NO_FSBR;
+#endif
 
        spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -827,7 +841,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
 
 static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 {
-       if (dev->driver_info->flags & FLAG_FRAMING) {
+       if (dev->driver_info->flags & FLAG_FRAMING_NC) {
                struct nc_header        *header;
                struct nc_trailer       *trailer;
 
@@ -1083,9 +1097,11 @@ static int usbnet_open (struct net_device *net)
        }
 
        netif_start_queue (net);
-       devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %sframed",
+       devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
                RX_QLEN, TX_QLEN, dev->net.mtu,
-               (info->flags & FLAG_FRAMING) ? "" : "un"
+               (info->flags & FLAG_FRAMING_NC)
+                   ? "NetChip"
+                   : "raw"
                );
 
        // delay posting reads until we're fully open
@@ -1194,7 +1210,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 
        flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
 
-       if (info->flags & FLAG_FRAMING) {
+       if (info->flags & FLAG_FRAMING_NC) {
                struct sk_buff  *skb2;
                skb2 = fixup_skb (skb, flags);
                if (!skb2) {
@@ -1215,7 +1231,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
        entry->state = tx_start;
        entry->length = length;
 
-       if (info->flags & FLAG_FRAMING) {
+       if (info->flags & FLAG_FRAMING_NC) {
                header = (struct nc_header *) skb_push (skb, sizeof *header);
                header->hdr_len = cpu_to_le16 (sizeof (*header));
                header->packet_len = cpu_to_le16 (length);
@@ -1223,31 +1239,31 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
                        *skb_put (skb, 1) = PAD_BYTE;
                trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
        } else if ((length % EP_SIZE (dev)) == 0) {
-                       if (skb_shared (skb)) {
-                               struct sk_buff *skb2;
-                               skb2 = skb_unshare (skb, flags);
-                               if (!skb2) {
-                                       dbg ("can't unshare skb");
-                                       goto drop;
-                               }
-                               skb = skb2;
+               // not all hardware behaves with USB_ZERO_PACKET,
+               // so we add an extra one-byte packet
+               if (skb_shared (skb)) {
+                       struct sk_buff *skb2;
+                       skb2 = skb_unshare (skb, flags);
+                       if (!skb2) {
+                               dbg ("can't unshare skb");
+                               goto drop;
                        }
-                       skb->len++;
+                       skb = skb2;
                }
+               skb->len++;
+       }
 
        FILL_BULK_URB (urb, dev->udev,
                        usb_sndbulkpipe (dev->udev, info->out),
                        skb->data, skb->len, tx_complete, skb);
-       // Idle-but-posted reads with UHCI really chew up
-       // PCI bandwidth unless FSBR is disabled
-       urb->transfer_flags |= USB_ASYNC_UNLINK | USB_NO_FSBR;
+       urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef REALLY_QUEUE
        urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
        // FIXME urb->timeout = ... jiffies ... ;
 
        spin_lock_irqsave (&dev->txq.lock, flags);
-       if (info->flags & FLAG_FRAMING) {
+       if (info->flags & FLAG_FRAMING_NC) {
                header->packet_id = cpu_to_le16 (dev->packet_id++);
                put_unaligned (header->packet_id, &trailer->packet_id);
 #if 0
@@ -1408,9 +1424,12 @@ usbnet_probe (struct usb_device *udev, unsigned ifnum,
                return 0;
        }
 
-       if (usb_set_interface (udev, ifnum, altnum) < 0) {
-               err ("set_interface failed");
-               return 0;
+       // more sanity (unless the device is broken)
+       if (!(info->flags & FLAG_NO_SETINT)) {
+               if (usb_set_interface (udev, ifnum, altnum) < 0) {
+                       err ("set_interface failed");
+                       return 0;
+               }
        }
 
        // set up our own records
@@ -1484,6 +1503,18 @@ static const struct usb_device_id        products [] = {
 },
 #endif
 
+#ifdef CONFIG_USB_BELKIN
+{
+       USB_DEVICE (0x050d, 0x0004),    // Belkin
+       driver_info:    (unsigned long) &belkin_info,
+}, {
+       USB_DEVICE (0x056c, 0x8100),    // eTEK
+       driver_info:    (unsigned long) &belkin_info,
+}, {
+       USB_DEVICE (0x0525, 0x9901),    // Advance USBNET (eTEK)
+       driver_info:    (unsigned long) &belkin_info,
+},
+#endif
 
 // GeneSys GL620USB (www.genesyslogic.com.tw)
 // (patch exists against an older driver version)
@@ -1508,16 +1539,6 @@ static const struct usb_device_id        products [] = {
 },
 #endif
 
-#ifdef CONFIG_USB_BELKIN_F5U104
-{
-       USB_DEVICE (0x050d, 0x0004),    // Belkin
-       driver_info:    (unsigned long) &belkin_info,
-}, {
-       USB_DEVICE (0x056c, 0x8100),    // eTEK
-       driver_info:    (unsigned long) &belkin_info,
-},
-#endif
-
 #ifdef CONFIG_USB_PL2301
 {
        USB_DEVICE (0x067b, 0x0000),    // PL-2301
@@ -1563,6 +1584,7 @@ static void __exit usbnet_exit (void)
 }
 module_exit (usbnet_exit);
 
+EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");
-MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (Belkin, Linux, NetChip, Prolific, ...)");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)");
+MODULE_LICENSE ("GPL");
index 42ba99f03e3c5f178a2fc52b8ee9b6c13bf0fa74..46e878ff906c3523050e08e9436877da70ff4000 100644 (file)
@@ -1131,31 +1131,13 @@ void __brelse(struct buffer_head * buf)
 }
 
 /*
- * bforget() is like brelse(), except it might discard any
+ * bforget() is like brelse(), except it discards any
  * potentially dirty data.
  */
 void __bforget(struct buffer_head * buf)
 {
-       /* grab the lru lock here so that "b_count" is stable */
-       spin_lock(&lru_list_lock);
-       write_lock(&hash_table_lock);
-       if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
-               goto in_use;
-
-       /* Mark it clean */
-       clear_bit(BH_Dirty, &buf->b_state);
-       write_unlock(&hash_table_lock);
-
-       /* After which we can remove it from all queues */
-       remove_inode_queue(buf);
-       __remove_from_lru_list(buf);
-       buf->b_list = BUF_CLEAN;
-       spin_unlock(&lru_list_lock);
-       return;
-
-in_use:
-       write_unlock(&hash_table_lock);
-       spin_unlock(&lru_list_lock);
+       mark_buffer_clean(buf);
+       __brelse(buf);
 }
 
 /**
index f92e13e8d8210b12da5032f33f70166e88cbd5a0..d1d69e6976b09938a2ddc08de83f4eb59c949222 100644 (file)
@@ -394,7 +394,7 @@ rebalance:
        }
 
        /* Don't let big-order allocations loop */
-       if (order)
+       if (order > 1)
                return NULL;
 
        /* Yield for kswapd, and try again */
index 41d651f6720fbb8b53392d64273e5b1e2159f94b..412a2f7694d7eb1d99b158028c4bf9f0526e5d2d 100644 (file)
@@ -346,11 +346,7 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
 
                page = list_entry(entry, struct page, lru);
 
-               if (unlikely(!PageInactive(page) && !PageActive(page)))
-                       BUG();
-
-               /* Mapping-less page on LRU-list? */
-               if (unlikely(!page->mapping))
+               if (unlikely(!PageInactive(page)))
                        BUG();
 
                list_del(entry);
@@ -363,31 +359,17 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
                        continue;
 
                /* Racy check to avoid trylocking when not worthwhile */
-               if (!is_page_cache_freeable(page))
-                       continue;
-
-               if (unlikely(TryLockPage(page))) {
-                       if (gfp_mask & __GFP_FS) {
-                               page_cache_get(page);
-                               spin_unlock(&pagemap_lru_lock);
-                               wait_on_page(page);
-                               page_cache_release(page);
-                               spin_lock(&pagemap_lru_lock);
-                       }
+               if (!page->buffers && page_count(page) != 1)
                        continue;
-               }
 
                /*
-                * Still strictly racy - we don't own the pagecache lock,
-                * so somebody might look up the page while we do this.
-                * It's just a heuristic, though.
+                * The page is locked. IO in progress?
+                * Move it to the back of the list.
                 */
-               if (!is_page_cache_freeable(page)) {
-                       UnlockPage(page);
+               if (unlikely(TryLockPage(page)))
                        continue;
-               }
 
-               if (PageDirty(page)) {
+               if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
                        /*
                         * It is not critical here to write it only if
                         * the page is unmapped beause any direct writer
@@ -461,6 +443,9 @@ static int shrink_cache(int nr_pages, int max_scan, unsigned int gfp_mask)
                        }
                }
 
+               if (unlikely(!page->mapping))
+                       BUG();
+
                if (unlikely(!spin_trylock(&pagecache_lock))) {
                        /* we hold the page lock so the page cannot go away from under us */
                        spin_unlock(&pagemap_lru_lock);