On Tue, 15 Feb 2005, Greg KH wrote:

Hm, I get the following build error with this patch:
drivers/usb/net/pegasus.c: In function `check_carrier':
drivers/usb/net/pegasus.c:1167: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c: In function `pegasus_probe':
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1198: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c:1244: error: structure has no member named 
`carrier_check'
drivers/usb/net/pegasus.c: In function `pegasus_disconnect':
drivers/usb/net/pegasus.c:1271: error: structure has no member named 
`carrier_check'

So I'm not going to apply it :)

Well, definitely not. Seems like gregkh-2.6 BK tree got corrupted on my machine so i had to clone the repository again.


Attached is a diff between whatever is working for me and the latest gregkh-2.6 tree. Hope this time it'll compile. :-)


Petko



On Thu, Feb 03, 2005 at 06:20:38PM +0200, Petko Manolov wrote:
        Hi Greg,

When the bonding driver attempts to read the link status via
xxx_get_settings() the enslaved usb-eth driver crash the kernel.  Which
shouldn't be much of surprise - since pegasus|rtl8150_get_settins() is
been called from a timer.  The original work was done by Mike Nix -
thanks.

Fixed that using in_atomic() check.  I am not sure this is the best/proper
thing to do, although it seems to work.

Haven't checked the other usb-ethernet drivers, but i suspect they are as
vulnerable as pegasus and rtl8150 are.  It's probably a good idea to warn
their respective maintainers.

--- pegasus.c   2005-02-17 14:18:44.170289624 +0200
+++ /usr/src/linux-2.6.10/drivers/usb/net/pegasus.c     2005-02-02 
10:59:23.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999-2003 Petko Manolov ([EMAIL PROTECTED])
+ *  Copyright (c) 1999-2005 Petko Manolov ([EMAIL PROTECTED])
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -47,7 +47,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.12 (2005/01/13)"
+#define DRIVER_VERSION "v0.6.12 (2005/01/13)"
 #define DRIVER_AUTHOR "Petko Manolov <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -301,20 +301,20 @@
        if (i < REG_TIMEOUT) {
                get_registers(pegasus, PhyData, 2, &regdi);
                *regd = le16_to_cpu(regdi);
-               return 0;
+               return 1;
        }
        warn("%s: failed", __FUNCTION__);
 
-       return 1;
+       return 0;
 }
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
        pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
-       int res;
+       __le16 res;
 
-       read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
-       return res & 0xffff;
+       read_mii_word(pegasus, phy_id, loc, &res);
+       return (int)res;
 }
 
 static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
@@ -636,7 +636,7 @@
 
        return;
 
-      tl_sched:
+tl_sched:
        tasklet_schedule(&pegasus->rx_tl);
 }
 
@@ -845,14 +845,14 @@
 static void set_carrier(struct net_device *net)
 {
        pegasus_t *pegasus = netdev_priv(net);
-       short tmp;
+       __le16 tmp;
 
-       read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+       if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
+               return;
        if (tmp & BMSR_LSTATUS)
                netif_carrier_on(net);
        else
                netif_carrier_off(net);
-
 }
 
 static void free_all_urbs(pegasus_t * pegasus)
@@ -997,8 +997,7 @@
        return set_register(pegasus, WakeupControl, reg78);
 }
 
-static inline void
-pegasus_reset_wol(struct net_device *dev)
+static inline void pegasus_reset_wol(struct net_device *dev)
 {
        struct ethtool_wolinfo wol;
        
@@ -1009,10 +1008,17 @@
 static int
 pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-       pegasus_t *pegasus = netdev_priv(dev);
+       pegasus_t *pegasus;
+
+       if (in_atomic())
+               return 0;
+
+       pegasus = netdev_priv(dev);
        mii_ethtool_gset(&pegasus->mii, ecmd);
+
        return 0;
 }
+
 static int
 pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
@@ -1149,6 +1155,20 @@
                set_register(pegasus, Reg81, 2);
 }
 
+
+struct workqueue_struct *pegasus_workqueue = NULL;
+#define CARRIER_CHECK_DELAY (2 * HZ)
+
+void check_carrier(void *data)
+{
+       pegasus_t *pegasus = data;
+       set_carrier(pegasus->net);
+       if (!(pegasus->flags & PEGASUS_UNPLUG)) {
+               queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
+                       CARRIER_CHECK_DELAY);
+       }
+}
+
 static int pegasus_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1175,6 +1195,8 @@
 
        tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
 
+       INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus);
+
        pegasus->usb = dev;
        pegasus->net = net;
        SET_MODULE_OWNER(net);
@@ -1212,12 +1234,14 @@
                dev_warn(&intf->dev, "can't locate MII phy, using default\n");
                pegasus->phy = 1;
        }
+       pegasus->mii.phy_id = pegasus->phy;
        usb_set_intfdata(intf, pegasus);
        SET_NETDEV_DEV(net, &intf->dev);
        pegasus_reset_wol(net);
        res = register_netdev(net);
        if (res)
                goto out3;
+       queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, 
CARRIER_CHECK_DELAY);
        pr_info("%s: %s\n", net->name, usb_dev_id[dev_index].name);
        return 0;
 
@@ -1239,11 +1263,12 @@
 
        usb_set_intfdata(intf, NULL);
        if (!pegasus) {
-               warn("unregistering non-existant device");
+               warn("unregistering non-existent device");
                return;
        }
 
        pegasus->flags |= PEGASUS_UNPLUG;
+       cancel_delayed_work(&pegasus->carrier_check);
        unregister_netdev(pegasus->net);
        usb_put_dev(interface_to_usbdev(intf));
        free_all_urbs(pegasus);
@@ -1253,7 +1278,7 @@
        free_netdev(pegasus->net);
 }
 
-static int pegasus_suspend (struct usb_interface *intf, pm_message_t state)
+static int pegasus_suspend (struct usb_interface *intf, u32 state)
 {
        struct pegasus *pegasus = usb_get_intfdata(intf);
        
@@ -1281,11 +1306,15 @@
 static int __init pegasus_init(void)
 {
        pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
+       pegasus_workqueue = create_singlethread_workqueue("pegasus");
+       if (!pegasus_workqueue)
+               return -ENOMEM;
        return usb_register(&pegasus_driver);
 }
 
 static void __exit pegasus_exit(void)
 {
+       destroy_workqueue(pegasus_workqueue);
        usb_deregister(&pegasus_driver);
 }
 
--- pegasus.h   2005-02-17 14:18:47.972711568 +0200
+++ /usr/src/linux-2.6.10/drivers/usb/net/pegasus.h     2005-01-24 
12:29:45.000000000 +0200
@@ -96,6 +96,7 @@
        int                     dev_index;
        int                     intr_interval;
        struct tasklet_struct   rx_tl;
+       struct work_struct      carrier_check;
        struct urb              *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
        struct sk_buff          *rx_pool[RX_SKBS];
        struct sk_buff          *rx_skb;

Reply via email to