Skip to content

Commit

Permalink
p54pci: convert driver to use asynchronous firmware loading
Browse files Browse the repository at this point in the history
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 using request_firmware_nowait()
and delaying the start of mac80211 until the firmware is loaded.

To prevent the possibility of the driver being unloaded while the firmware
loading callback is still active, a completion queue entry is used.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Larry Finger authored and John W. Linville committed Aug 6, 2012
1 parent d11d354 commit 95a96e0
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 26 deletions.
88 changes: 62 additions & 26 deletions drivers/net/wireless/p54/p54pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,58 @@ static int p54p_open(struct ieee80211_hw *dev)
return 0;
}

static void p54p_firmware_step2(const struct firmware *fw,
void *context)
{
struct p54p_priv *priv = context;
struct ieee80211_hw *dev = priv->common.hw;
struct pci_dev *pdev = priv->pdev;
int err;

if (!fw) {
dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
err = -ENOENT;
goto out;
}

priv->firmware = fw;

err = p54p_open(dev);
if (err)
goto out;
err = p54_read_eeprom(dev);
p54p_stop(dev);
if (err)
goto out;

err = p54_register_common(dev, &pdev->dev);
if (err)
goto out;

out:

complete(&priv->fw_loaded);

if (err) {
struct device *parent = pdev->dev.parent;

if (parent)
device_lock(parent);

/*
* This will indirectly result in a call to p54p_remove.
* Hence, we don't need to bother with freeing any
* allocated ressources at all.
*/
device_release_driver(&pdev->dev);

if (parent)
device_unlock(parent);
}

pci_dev_put(pdev);
}

static int __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
Expand All @@ -496,6 +548,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
unsigned long mem_addr, mem_len;
int err;

pci_dev_get(pdev);
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n");
Expand Down Expand Up @@ -537,6 +590,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv = dev->priv;
priv->pdev = pdev;

init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);

Expand All @@ -561,32 +615,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);

err = request_firmware(&priv->firmware, "isl3886pci",
&priv->pdev->dev);
if (err) {
dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
err = request_firmware(&priv->firmware, "isl3886",
&priv->pdev->dev);
if (err)
goto err_free_common;
}

err = p54p_open(dev);
if (err)
goto err_free_common;
err = p54_read_eeprom(dev);
p54p_stop(dev);
if (err)
goto err_free_common;

err = p54_register_common(dev, &pdev->dev);
if (err)
goto err_free_common;

return 0;
err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
&priv->pdev->dev, GFP_KERNEL,
priv, p54p_firmware_step2);
if (!err)
return 0;

err_free_common:
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);

Expand All @@ -601,6 +635,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
pci_dev_put(pdev);
return err;
}

Expand All @@ -612,8 +647,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;

p54_unregister_common(dev);
priv = dev->priv;
wait_for_completion(&priv->fw_loaded);
p54_unregister_common(dev);
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/p54/p54pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ struct p54p_priv {
struct sk_buff *tx_buf_data[32];
struct sk_buff *tx_buf_mgmt[4];
struct completion boot_comp;
struct completion fw_loaded;
};

#endif /* P54USB_H */
Expand Down

0 comments on commit 95a96e0

Please sign in to comment.