diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-12-23 07:15:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-02 14:31:50 -0500 |
commit | 535765179fd4e8af26b69d2240d7ec33702a370a (patch) | |
tree | a21ca3bdc1b4b5f40e233672f16ec618aab604fa /drivers | |
parent | 6e93d7195e75741e9ebe23ca5591977d0b39ecc0 (diff) |
ar9170: load firmware asynchronously
This converts ar9170 to load firmware asynchronously
out of ->probe() and only register with mac80211 when
all firmware has been loaded successfully. If, on the
other hand, any firmware fails to load, it will now
unbind from the device.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ar9170/ar9170.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ar9170/main.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ar9170/usb.c | 170 |
3 files changed, 111 insertions, 70 deletions
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 8c8ce67971e9..dc662b76a1c8 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h | |||
@@ -166,6 +166,7 @@ struct ar9170 { | |||
166 | struct ath_common common; | 166 | struct ath_common common; |
167 | struct mutex mutex; | 167 | struct mutex mutex; |
168 | enum ar9170_device_state state; | 168 | enum ar9170_device_state state; |
169 | bool registered; | ||
169 | unsigned long bad_hw_nagger; | 170 | unsigned long bad_hw_nagger; |
170 | 171 | ||
171 | int (*open)(struct ar9170 *); | 172 | int (*open)(struct ar9170 *); |
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 8a964f130367..f4650fcdebc9 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c | |||
@@ -2701,7 +2701,8 @@ int ar9170_register(struct ar9170 *ar, struct device *pdev) | |||
2701 | dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", | 2701 | dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", |
2702 | wiphy_name(ar->hw->wiphy)); | 2702 | wiphy_name(ar->hw->wiphy)); |
2703 | 2703 | ||
2704 | return err; | 2704 | ar->registered = true; |
2705 | return 0; | ||
2705 | 2706 | ||
2706 | err_unreg: | 2707 | err_unreg: |
2707 | ieee80211_unregister_hw(ar->hw); | 2708 | ieee80211_unregister_hw(ar->hw); |
@@ -2712,11 +2713,14 @@ err_out: | |||
2712 | 2713 | ||
2713 | void ar9170_unregister(struct ar9170 *ar) | 2714 | void ar9170_unregister(struct ar9170 *ar) |
2714 | { | 2715 | { |
2716 | if (ar->registered) { | ||
2715 | #ifdef CONFIG_AR9170_LEDS | 2717 | #ifdef CONFIG_AR9170_LEDS |
2716 | ar9170_unregister_leds(ar); | 2718 | ar9170_unregister_leds(ar); |
2717 | #endif /* CONFIG_AR9170_LEDS */ | 2719 | #endif /* CONFIG_AR9170_LEDS */ |
2718 | 2720 | ||
2719 | kfree_skb(ar->rx_failover); | ||
2720 | ieee80211_unregister_hw(ar->hw); | 2721 | ieee80211_unregister_hw(ar->hw); |
2722 | } | ||
2723 | |||
2724 | kfree_skb(ar->rx_failover); | ||
2721 | mutex_destroy(&ar->mutex); | 2725 | mutex_destroy(&ar->mutex); |
2722 | } | 2726 | } |
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 0f361186b78f..4e30197afff6 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c | |||
@@ -582,43 +582,6 @@ static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, | |||
582 | return 0; | 582 | return 0; |
583 | } | 583 | } |
584 | 584 | ||
585 | static int ar9170_usb_request_firmware(struct ar9170_usb *aru) | ||
586 | { | ||
587 | int err = 0; | ||
588 | |||
589 | err = request_firmware(&aru->firmware, "ar9170.fw", | ||
590 | &aru->udev->dev); | ||
591 | if (!err) { | ||
592 | aru->init_values = NULL; | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | if (aru->req_one_stage_fw) { | ||
597 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
598 | "not found and is required for this device\n"); | ||
599 | return -EINVAL; | ||
600 | } | ||
601 | |||
602 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
603 | "not found, trying old firmware...\n"); | ||
604 | |||
605 | err = request_firmware(&aru->init_values, "ar9170-1.fw", | ||
606 | &aru->udev->dev); | ||
607 | if (err) { | ||
608 | dev_err(&aru->udev->dev, "file with init values not found.\n"); | ||
609 | return err; | ||
610 | } | ||
611 | |||
612 | err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); | ||
613 | if (err) { | ||
614 | release_firmware(aru->init_values); | ||
615 | dev_err(&aru->udev->dev, "firmware file not found.\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | return err; | ||
620 | } | ||
621 | |||
622 | static int ar9170_usb_reset(struct ar9170_usb *aru) | 585 | static int ar9170_usb_reset(struct ar9170_usb *aru) |
623 | { | 586 | { |
624 | int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); | 587 | int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); |
@@ -757,6 +720,103 @@ err_out: | |||
757 | return err; | 720 | return err; |
758 | } | 721 | } |
759 | 722 | ||
723 | static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) | ||
724 | { | ||
725 | struct device *parent = aru->udev->dev.parent; | ||
726 | |||
727 | /* unbind anything failed */ | ||
728 | if (parent) | ||
729 | down(&parent->sem); | ||
730 | device_release_driver(&aru->udev->dev); | ||
731 | if (parent) | ||
732 | up(&parent->sem); | ||
733 | } | ||
734 | |||
735 | static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) | ||
736 | { | ||
737 | struct ar9170_usb *aru = context; | ||
738 | int err; | ||
739 | |||
740 | aru->firmware = fw; | ||
741 | |||
742 | if (!fw) { | ||
743 | dev_err(&aru->udev->dev, "firmware file not found.\n"); | ||
744 | goto err_freefw; | ||
745 | } | ||
746 | |||
747 | err = ar9170_usb_init_device(aru); | ||
748 | if (err) | ||
749 | goto err_freefw; | ||
750 | |||
751 | err = ar9170_usb_open(&aru->common); | ||
752 | if (err) | ||
753 | goto err_unrx; | ||
754 | |||
755 | err = ar9170_register(&aru->common, &aru->udev->dev); | ||
756 | |||
757 | ar9170_usb_stop(&aru->common); | ||
758 | if (err) | ||
759 | goto err_unrx; | ||
760 | |||
761 | return; | ||
762 | |||
763 | err_unrx: | ||
764 | ar9170_usb_cancel_urbs(aru); | ||
765 | |||
766 | err_freefw: | ||
767 | ar9170_usb_firmware_failed(aru); | ||
768 | } | ||
769 | |||
770 | static void ar9170_usb_firmware_inits(const struct firmware *fw, | ||
771 | void *context) | ||
772 | { | ||
773 | struct ar9170_usb *aru = context; | ||
774 | int err; | ||
775 | |||
776 | if (!fw) { | ||
777 | dev_err(&aru->udev->dev, "file with init values not found.\n"); | ||
778 | ar9170_usb_firmware_failed(aru); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | aru->init_values = fw; | ||
783 | |||
784 | /* ok so we have the init values -- get code for two-stage */ | ||
785 | |||
786 | err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", | ||
787 | &aru->udev->dev, GFP_KERNEL, aru, | ||
788 | ar9170_usb_firmware_finish); | ||
789 | if (err) | ||
790 | ar9170_usb_firmware_failed(aru); | ||
791 | } | ||
792 | |||
793 | static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) | ||
794 | { | ||
795 | struct ar9170_usb *aru = context; | ||
796 | int err; | ||
797 | |||
798 | if (fw) { | ||
799 | ar9170_usb_firmware_finish(fw, context); | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | if (aru->req_one_stage_fw) { | ||
804 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
805 | "not found and is required for this device\n"); | ||
806 | ar9170_usb_firmware_failed(aru); | ||
807 | return; | ||
808 | } | ||
809 | |||
810 | dev_err(&aru->udev->dev, "ar9170.fw firmware file " | ||
811 | "not found, trying old firmware...\n"); | ||
812 | |||
813 | err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", | ||
814 | &aru->udev->dev, GFP_KERNEL, aru, | ||
815 | ar9170_usb_firmware_inits); | ||
816 | if (err) | ||
817 | ar9170_usb_firmware_failed(aru); | ||
818 | } | ||
819 | |||
760 | static bool ar9170_requires_one_stage(const struct usb_device_id *id) | 820 | static bool ar9170_requires_one_stage(const struct usb_device_id *id) |
761 | { | 821 | { |
762 | if (!id->driver_info) | 822 | if (!id->driver_info) |
@@ -814,33 +874,9 @@ static int ar9170_usb_probe(struct usb_interface *intf, | |||
814 | if (err) | 874 | if (err) |
815 | goto err_freehw; | 875 | goto err_freehw; |
816 | 876 | ||
817 | err = ar9170_usb_request_firmware(aru); | 877 | return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", |
818 | if (err) | 878 | &aru->udev->dev, GFP_KERNEL, aru, |
819 | goto err_freehw; | 879 | ar9170_usb_firmware_step2); |
820 | |||
821 | err = ar9170_usb_init_device(aru); | ||
822 | if (err) | ||
823 | goto err_freefw; | ||
824 | |||
825 | err = ar9170_usb_open(ar); | ||
826 | if (err) | ||
827 | goto err_unrx; | ||
828 | |||
829 | err = ar9170_register(ar, &udev->dev); | ||
830 | |||
831 | ar9170_usb_stop(ar); | ||
832 | if (err) | ||
833 | goto err_unrx; | ||
834 | |||
835 | return 0; | ||
836 | |||
837 | err_unrx: | ||
838 | ar9170_usb_cancel_urbs(aru); | ||
839 | |||
840 | err_freefw: | ||
841 | release_firmware(aru->init_values); | ||
842 | release_firmware(aru->firmware); | ||
843 | |||
844 | err_freehw: | 880 | err_freehw: |
845 | usb_set_intfdata(intf, NULL); | 881 | usb_set_intfdata(intf, NULL); |
846 | usb_put_dev(udev); | 882 | usb_put_dev(udev); |
@@ -860,12 +896,12 @@ static void ar9170_usb_disconnect(struct usb_interface *intf) | |||
860 | ar9170_unregister(&aru->common); | 896 | ar9170_unregister(&aru->common); |
861 | ar9170_usb_cancel_urbs(aru); | 897 | ar9170_usb_cancel_urbs(aru); |
862 | 898 | ||
863 | release_firmware(aru->init_values); | ||
864 | release_firmware(aru->firmware); | ||
865 | |||
866 | usb_put_dev(aru->udev); | 899 | usb_put_dev(aru->udev); |
867 | usb_set_intfdata(intf, NULL); | 900 | usb_set_intfdata(intf, NULL); |
868 | ieee80211_free_hw(aru->common.hw); | 901 | ieee80211_free_hw(aru->common.hw); |
902 | |||
903 | release_firmware(aru->init_values); | ||
904 | release_firmware(aru->firmware); | ||
869 | } | 905 | } |
870 | 906 | ||
871 | #ifdef CONFIG_PM | 907 | #ifdef CONFIG_PM |