Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

p54pci: convert driver to use asynchronous firmware loading

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>

authored by

Larry Finger and committed by
John W. Linville
95a96e08 d11d354b

+63 -26
+62 -26
drivers/net/wireless/p54/p54pci.c
··· 488 488 return 0; 489 489 } 490 490 491 + static void p54p_firmware_step2(const struct firmware *fw, 492 + void *context) 493 + { 494 + struct p54p_priv *priv = context; 495 + struct ieee80211_hw *dev = priv->common.hw; 496 + struct pci_dev *pdev = priv->pdev; 497 + int err; 498 + 499 + if (!fw) { 500 + dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n"); 501 + err = -ENOENT; 502 + goto out; 503 + } 504 + 505 + priv->firmware = fw; 506 + 507 + err = p54p_open(dev); 508 + if (err) 509 + goto out; 510 + err = p54_read_eeprom(dev); 511 + p54p_stop(dev); 512 + if (err) 513 + goto out; 514 + 515 + err = p54_register_common(dev, &pdev->dev); 516 + if (err) 517 + goto out; 518 + 519 + out: 520 + 521 + complete(&priv->fw_loaded); 522 + 523 + if (err) { 524 + struct device *parent = pdev->dev.parent; 525 + 526 + if (parent) 527 + device_lock(parent); 528 + 529 + /* 530 + * This will indirectly result in a call to p54p_remove. 531 + * Hence, we don't need to bother with freeing any 532 + * allocated ressources at all. 533 + */ 534 + device_release_driver(&pdev->dev); 535 + 536 + if (parent) 537 + device_unlock(parent); 538 + } 539 + 540 + pci_dev_put(pdev); 541 + } 542 + 491 543 static int __devinit p54p_probe(struct pci_dev *pdev, 492 544 const struct pci_device_id *id) 493 545 { ··· 548 496 unsigned long mem_addr, mem_len; 549 497 int err; 550 498 499 + pci_dev_get(pdev); 551 500 err = pci_enable_device(pdev); 552 501 if (err) { 553 502 dev_err(&pdev->dev, "Cannot enable new PCI device\n"); ··· 590 537 priv = dev->priv; 591 538 priv->pdev = pdev; 592 539 540 + init_completion(&priv->fw_loaded); 593 541 SET_IEEE80211_DEV(dev, &pdev->dev); 594 542 pci_set_drvdata(pdev, dev); 595 543 ··· 615 561 spin_lock_init(&priv->lock); 616 562 tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); 617 563 618 - err = request_firmware(&priv->firmware, "isl3886pci", 619 - &priv->pdev->dev); 620 - if (err) { 621 - dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n"); 622 - err = request_firmware(&priv->firmware, "isl3886", 623 - &priv->pdev->dev); 624 - if (err) 625 - goto err_free_common; 626 - } 564 + err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci", 565 + &priv->pdev->dev, GFP_KERNEL, 566 + priv, p54p_firmware_step2); 567 + if (!err) 568 + return 0; 627 569 628 - err = p54p_open(dev); 629 - if (err) 630 - goto err_free_common; 631 - err = p54_read_eeprom(dev); 632 - p54p_stop(dev); 633 - if (err) 634 - goto err_free_common; 635 - 636 - err = p54_register_common(dev, &pdev->dev); 637 - if (err) 638 - goto err_free_common; 639 - 640 - return 0; 641 - 642 - err_free_common: 643 - release_firmware(priv->firmware); 644 570 pci_free_consistent(pdev, sizeof(*priv->ring_control), 645 571 priv->ring_control, priv->ring_control_dma); 646 572 ··· 635 601 pci_release_regions(pdev); 636 602 err_disable_dev: 637 603 pci_disable_device(pdev); 604 + pci_dev_put(pdev); 638 605 return err; 639 606 } 640 607 ··· 647 612 if (!dev) 648 613 return; 649 614 650 - p54_unregister_common(dev); 651 615 priv = dev->priv; 616 + wait_for_completion(&priv->fw_loaded); 617 + p54_unregister_common(dev); 652 618 release_firmware(priv->firmware); 653 619 pci_free_consistent(pdev, sizeof(*priv->ring_control), 654 620 priv->ring_control, priv->ring_control_dma);
+1
drivers/net/wireless/p54/p54pci.h
··· 105 105 struct sk_buff *tx_buf_data[32]; 106 106 struct sk_buff *tx_buf_mgmt[4]; 107 107 struct completion boot_comp; 108 + struct completion fw_loaded; 108 109 }; 109 110 110 111 #endif /* P54USB_H */