Search Linux Wireless

[RFC/RFT 3/5] p54usb: Load firmware from work queue and not from probe routine

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Drivers that load firmware from their probe routine have problems with the
latest versions of udev as they get timeouts while waiting for user
space to start. The problem is fixed by loading the firmware and starting
mac80211 from a delayed_work queue. By using this method, most of the
original code is preserved.

Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
---
 drivers/net/wireless/p54/p54usb.c |  120 +++++++++++++++++-------------------
 drivers/net/wireless/p54/p54usb.h |    1 +
 2 files changed, 58 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index f4d28c3..b8eff19 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -836,9 +836,33 @@ fail:
 	return err;
 }
 
-static int p54u_load_firmware(struct ieee80211_hw *dev)
+static int p54u_open(struct ieee80211_hw *dev)
 {
 	struct p54u_priv *priv = dev->priv;
+	int err;
+
+	err = p54u_init_urbs(dev);
+	if (err)
+		return err;
+
+	priv->common.open = p54u_init_urbs;
+
+	return 0;
+}
+
+static void p54u_stop(struct ieee80211_hw *dev)
+{
+	/* TODO: figure out how to reliably stop the 3887 and net2280 so
+	   the hardware is still usable next time we want to start it.
+	   until then, we just stop listening to the hardware.. */
+	p54u_free_urbs(dev);
+}
+
+static void p54u_load_firmware(struct work_struct *work)
+{
+	struct p54u_priv *priv = container_of(to_delayed_work(work),
+				 struct p54u_priv, firmware_load);
+	struct ieee80211_hw *dev = usb_get_intfdata(priv->intf);
 	int err, i;
 
 	BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
@@ -847,59 +871,53 @@ static int p54u_load_firmware(struct ieee80211_hw *dev)
 		if (p54u_fwlist[i].type == priv->hw_type)
 			break;
 
-	if (i == __NUM_P54U_HWTYPES)
-		return -EOPNOTSUPP;
+	if (i == __NUM_P54U_HWTYPES) {
+		dev_err(&priv->udev->dev, "Device not supported\n");
+		return;
+	}
 
 	err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
 	if (err) {
-		dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
-					  "(%d)!\n", p54u_fwlist[i].fw, err);
-
 		err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
 				       &priv->udev->dev);
-		if (err)
-			return err;
+
+		if (err) {
+			dev_err(&priv->udev->dev,
+				"(p54usb) cannot load firmware %s or %s(%d)!\n",
+				p54u_fwlist[i].fw, p54u_fwlist[i].fw_legacy,
+				err);
+			return;
+		}
 	}
 
 	err = p54_parse_firmware(dev, priv->fw);
-	if (err)
-		goto out;
+	if (err) {
+		dev_err(&priv->udev->dev, "Error parsing firmware\n");
+		return;
+	}
 
 	if (priv->common.fw_interface != p54u_fwlist[i].intf) {
 		dev_err(&priv->udev->dev, "wrong firmware, please get "
 			"a firmware for \"%s\" and try again.\n",
 			p54u_fwlist[i].hw);
-		err = -EINVAL;
+		return;
 	}
-
-out:
-	if (err)
-		release_firmware(priv->fw);
-
-	return err;
-}
-
-static int p54u_open(struct ieee80211_hw *dev)
-{
-	struct p54u_priv *priv = dev->priv;
-	int err;
-
-	err = p54u_init_urbs(dev);
+	err = priv->upload_fw(dev);
 	if (err) {
-		return err;
+		dev_err(&priv->udev->dev, "Error uploading firmware\n");
+		return;
 	}
 
-	priv->common.open = p54u_init_urbs;
-
-	return 0;
-}
+	p54u_open(dev);
+	err = p54_read_eeprom(dev);
+	if (err)
+		dev_err(&priv->udev->dev, "Error reading eeprom\n");
+	p54u_stop(dev);
+	if (err)
+		return;
 
-static void p54u_stop(struct ieee80211_hw *dev)
-{
-	/* TODO: figure out how to reliably stop the 3887 and net2280 so
-	   the hardware is still usable next time we want to start it.
-	   until then, we just stop listening to the hardware.. */
-	p54u_free_urbs(dev);
+	/* firmware available - start operations */
+	err = p54_register_common(dev, &priv->udev->dev);
 }
 
 static int __devinit p54u_probe(struct usb_interface *intf,
@@ -969,34 +987,10 @@ static int __devinit p54u_probe(struct usb_interface *intf,
 		priv->common.tx = p54u_tx_net2280;
 		priv->upload_fw = p54u_upload_firmware_net2280;
 	}
-	err = p54u_load_firmware(dev);
-	if (err)
-		goto err_free_dev;
-
-	err = priv->upload_fw(dev);
-	if (err)
-		goto err_free_fw;
-
-	p54u_open(dev);
-	err = p54_read_eeprom(dev);
-	p54u_stop(dev);
-	if (err)
-		goto err_free_fw;
-
-	err = p54_register_common(dev, &udev->dev);
-	if (err)
-		goto err_free_fw;
-
+	/* setup and start delayed work to load firmware */
+	INIT_DELAYED_WORK(&priv->firmware_load, p54u_load_firmware);
+	schedule_delayed_work(&priv->firmware_load, HZ);
 	return 0;
-
-err_free_fw:
-	release_firmware(priv->fw);
-
-err_free_dev:
-	p54_free_common(dev);
-	usb_set_intfdata(intf, NULL);
-	usb_put_dev(udev);
-	return err;
 }
 
 static void __devexit p54u_disconnect(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index ed4034a..6070a21 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -143,6 +143,7 @@ struct p54u_priv {
 	struct sk_buff_head rx_queue;
 	struct usb_anchor submitted;
 	const struct firmware *fw;
+	struct delayed_work firmware_load;
 };
 
 #endif /* P54USB_H */
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux