diff options
author | Daniel Drake <dsd@laptop.org> | 2012-04-16 18:53:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-17 14:57:14 -0400 |
commit | 66d647efe5e845c77f745478480c5e96218b7f3d (patch) | |
tree | c90d6cbbc6780f1a58e1fbfd315ac01b766e206e | |
parent | 534111c78c59a8db89c570fd07489243dc366a05 (diff) |
libertas SDIO: convert to asynchronous firmware loading
Signed-off-by: Daniel Drake <dsd@laptop.org>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/libertas/if_sdio.c | 206 |
1 files changed, 121 insertions, 85 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 6590febb366b..76caebaa4397 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -117,6 +117,8 @@ struct if_sdio_card { | |||
117 | int model; | 117 | int model; |
118 | unsigned long ioport; | 118 | unsigned long ioport; |
119 | unsigned int scratch_reg; | 119 | unsigned int scratch_reg; |
120 | bool started; | ||
121 | wait_queue_head_t pwron_waitq; | ||
120 | 122 | ||
121 | u8 buffer[65536] __attribute__((aligned(4))); | 123 | u8 buffer[65536] __attribute__((aligned(4))); |
122 | 124 | ||
@@ -129,6 +131,9 @@ struct if_sdio_card { | |||
129 | u8 rx_unit; | 131 | u8 rx_unit; |
130 | }; | 132 | }; |
131 | 133 | ||
134 | static void if_sdio_finish_power_on(struct if_sdio_card *card); | ||
135 | static int if_sdio_power_off(struct if_sdio_card *card); | ||
136 | |||
132 | /********************************************************************/ | 137 | /********************************************************************/ |
133 | /* I/O */ | 138 | /* I/O */ |
134 | /********************************************************************/ | 139 | /********************************************************************/ |
@@ -669,12 +674,39 @@ out: | |||
669 | return ret; | 674 | return ret; |
670 | } | 675 | } |
671 | 676 | ||
677 | static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret, | ||
678 | const struct firmware *helper, | ||
679 | const struct firmware *mainfw) | ||
680 | { | ||
681 | struct if_sdio_card *card = priv->card; | ||
682 | |||
683 | if (ret) { | ||
684 | pr_err("failed to find firmware (%d)\n", ret); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | ret = if_sdio_prog_helper(card, helper); | ||
689 | if (ret) | ||
690 | goto out; | ||
691 | |||
692 | lbs_deb_sdio("Helper firmware loaded\n"); | ||
693 | |||
694 | ret = if_sdio_prog_real(card, mainfw); | ||
695 | if (ret) | ||
696 | goto out; | ||
697 | |||
698 | lbs_deb_sdio("Firmware loaded\n"); | ||
699 | if_sdio_finish_power_on(card); | ||
700 | |||
701 | out: | ||
702 | release_firmware(helper); | ||
703 | release_firmware(mainfw); | ||
704 | } | ||
705 | |||
672 | static int if_sdio_prog_firmware(struct if_sdio_card *card) | 706 | static int if_sdio_prog_firmware(struct if_sdio_card *card) |
673 | { | 707 | { |
674 | int ret; | 708 | int ret; |
675 | u16 scratch; | 709 | u16 scratch; |
676 | const struct firmware *helper = NULL; | ||
677 | const struct firmware *mainfw = NULL; | ||
678 | 710 | ||
679 | lbs_deb_enter(LBS_DEB_SDIO); | 711 | lbs_deb_enter(LBS_DEB_SDIO); |
680 | 712 | ||
@@ -708,41 +740,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) | |||
708 | */ | 740 | */ |
709 | if (scratch == IF_SDIO_FIRMWARE_OK) { | 741 | if (scratch == IF_SDIO_FIRMWARE_OK) { |
710 | lbs_deb_sdio("firmware already loaded\n"); | 742 | lbs_deb_sdio("firmware already loaded\n"); |
711 | goto success; | 743 | if_sdio_finish_power_on(card); |
744 | return 0; | ||
712 | } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { | 745 | } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { |
713 | lbs_deb_sdio("firmware may be running\n"); | 746 | lbs_deb_sdio("firmware may be running\n"); |
714 | goto success; | 747 | if_sdio_finish_power_on(card); |
715 | } | 748 | return 0; |
716 | |||
717 | ret = lbs_get_firmware(&card->func->dev, card->model, &fw_table[0], | ||
718 | &helper, &mainfw); | ||
719 | if (ret) { | ||
720 | pr_err("failed to find firmware (%d)\n", ret); | ||
721 | goto out; | ||
722 | } | 749 | } |
723 | 750 | ||
724 | ret = if_sdio_prog_helper(card, helper); | 751 | ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model, |
725 | if (ret) | 752 | fw_table, if_sdio_do_prog_firmware); |
726 | goto out; | ||
727 | |||
728 | lbs_deb_sdio("Helper firmware loaded\n"); | ||
729 | |||
730 | ret = if_sdio_prog_real(card, mainfw); | ||
731 | if (ret) | ||
732 | goto out; | ||
733 | |||
734 | lbs_deb_sdio("Firmware loaded\n"); | ||
735 | |||
736 | success: | ||
737 | sdio_claim_host(card->func); | ||
738 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | ||
739 | sdio_release_host(card->func); | ||
740 | ret = 0; | ||
741 | 753 | ||
742 | out: | 754 | out: |
743 | release_firmware(helper); | ||
744 | release_firmware(mainfw); | ||
745 | |||
746 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 755 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
747 | return ret; | 756 | return ret; |
748 | } | 757 | } |
@@ -751,55 +760,15 @@ out: | |||
751 | /* Power management */ | 760 | /* Power management */ |
752 | /********************************************************************/ | 761 | /********************************************************************/ |
753 | 762 | ||
754 | static int if_sdio_power_on(struct if_sdio_card *card) | 763 | /* Finish power on sequence (after firmware is loaded) */ |
764 | static void if_sdio_finish_power_on(struct if_sdio_card *card) | ||
755 | { | 765 | { |
756 | struct sdio_func *func = card->func; | 766 | struct sdio_func *func = card->func; |
757 | struct lbs_private *priv = card->priv; | 767 | struct lbs_private *priv = card->priv; |
758 | struct mmc_host *host = func->card->host; | ||
759 | int ret; | 768 | int ret; |
760 | 769 | ||
761 | sdio_claim_host(func); | 770 | sdio_claim_host(func); |
762 | 771 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | |
763 | ret = sdio_enable_func(func); | ||
764 | if (ret) | ||
765 | goto release; | ||
766 | |||
767 | /* For 1-bit transfers to the 8686 model, we need to enable the | ||
768 | * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 | ||
769 | * bit to allow access to non-vendor registers. */ | ||
770 | if ((card->model == MODEL_8686) && | ||
771 | (host->caps & MMC_CAP_SDIO_IRQ) && | ||
772 | (host->ios.bus_width == MMC_BUS_WIDTH_1)) { | ||
773 | u8 reg; | ||
774 | |||
775 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
776 | reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); | ||
777 | if (ret) | ||
778 | goto disable; | ||
779 | |||
780 | reg |= SDIO_BUS_ECSI; | ||
781 | sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); | ||
782 | if (ret) | ||
783 | goto disable; | ||
784 | } | ||
785 | |||
786 | card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); | ||
787 | if (ret) | ||
788 | goto disable; | ||
789 | |||
790 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; | ||
791 | if (ret) | ||
792 | goto disable; | ||
793 | |||
794 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; | ||
795 | if (ret) | ||
796 | goto disable; | ||
797 | |||
798 | sdio_release_host(func); | ||
799 | ret = if_sdio_prog_firmware(card); | ||
800 | sdio_claim_host(func); | ||
801 | if (ret) | ||
802 | goto disable; | ||
803 | 772 | ||
804 | /* | 773 | /* |
805 | * Get rx_unit if the chip is SD8688 or newer. | 774 | * Get rx_unit if the chip is SD8688 or newer. |
@@ -824,7 +793,7 @@ static int if_sdio_power_on(struct if_sdio_card *card) | |||
824 | */ | 793 | */ |
825 | ret = sdio_claim_irq(func, if_sdio_interrupt); | 794 | ret = sdio_claim_irq(func, if_sdio_interrupt); |
826 | if (ret) | 795 | if (ret) |
827 | goto disable; | 796 | goto release; |
828 | 797 | ||
829 | /* | 798 | /* |
830 | * Enable interrupts now that everything is set up | 799 | * Enable interrupts now that everything is set up |
@@ -850,11 +819,79 @@ static int if_sdio_power_on(struct if_sdio_card *card) | |||
850 | } | 819 | } |
851 | 820 | ||
852 | priv->fw_ready = 1; | 821 | priv->fw_ready = 1; |
822 | wake_up(&card->pwron_waitq); | ||
853 | 823 | ||
854 | return 0; | 824 | if (!card->started) { |
825 | ret = lbs_start_card(priv); | ||
826 | if_sdio_power_off(card); | ||
827 | if (ret == 0) { | ||
828 | card->started = true; | ||
829 | /* Tell PM core that we don't need the card to be | ||
830 | * powered now */ | ||
831 | pm_runtime_put_noidle(&func->dev); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | return; | ||
855 | 836 | ||
856 | release_irq: | 837 | release_irq: |
857 | sdio_release_irq(func); | 838 | sdio_release_irq(func); |
839 | release: | ||
840 | sdio_release_host(func); | ||
841 | } | ||
842 | |||
843 | static int if_sdio_power_on(struct if_sdio_card *card) | ||
844 | { | ||
845 | struct sdio_func *func = card->func; | ||
846 | struct mmc_host *host = func->card->host; | ||
847 | int ret; | ||
848 | |||
849 | sdio_claim_host(func); | ||
850 | |||
851 | ret = sdio_enable_func(func); | ||
852 | if (ret) | ||
853 | goto release; | ||
854 | |||
855 | /* For 1-bit transfers to the 8686 model, we need to enable the | ||
856 | * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 | ||
857 | * bit to allow access to non-vendor registers. */ | ||
858 | if ((card->model == MODEL_8686) && | ||
859 | (host->caps & MMC_CAP_SDIO_IRQ) && | ||
860 | (host->ios.bus_width == MMC_BUS_WIDTH_1)) { | ||
861 | u8 reg; | ||
862 | |||
863 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
864 | reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); | ||
865 | if (ret) | ||
866 | goto disable; | ||
867 | |||
868 | reg |= SDIO_BUS_ECSI; | ||
869 | sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); | ||
870 | if (ret) | ||
871 | goto disable; | ||
872 | } | ||
873 | |||
874 | card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); | ||
875 | if (ret) | ||
876 | goto disable; | ||
877 | |||
878 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; | ||
879 | if (ret) | ||
880 | goto disable; | ||
881 | |||
882 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; | ||
883 | if (ret) | ||
884 | goto disable; | ||
885 | |||
886 | sdio_release_host(func); | ||
887 | ret = if_sdio_prog_firmware(card); | ||
888 | if (ret) { | ||
889 | sdio_disable_func(func); | ||
890 | return ret; | ||
891 | } | ||
892 | |||
893 | return 0; | ||
894 | |||
858 | disable: | 895 | disable: |
859 | sdio_disable_func(func); | 896 | sdio_disable_func(func); |
860 | release: | 897 | release: |
@@ -1061,11 +1098,17 @@ static int if_sdio_power_save(struct lbs_private *priv) | |||
1061 | static int if_sdio_power_restore(struct lbs_private *priv) | 1098 | static int if_sdio_power_restore(struct lbs_private *priv) |
1062 | { | 1099 | { |
1063 | struct if_sdio_card *card = priv->card; | 1100 | struct if_sdio_card *card = priv->card; |
1101 | int r; | ||
1064 | 1102 | ||
1065 | /* Make sure the card will not be powered off by runtime PM */ | 1103 | /* Make sure the card will not be powered off by runtime PM */ |
1066 | pm_runtime_get_sync(&card->func->dev); | 1104 | pm_runtime_get_sync(&card->func->dev); |
1067 | 1105 | ||
1068 | return if_sdio_power_on(card); | 1106 | r = if_sdio_power_on(card); |
1107 | if (r) | ||
1108 | return r; | ||
1109 | |||
1110 | wait_event(card->pwron_waitq, priv->fw_ready); | ||
1111 | return 0; | ||
1069 | } | 1112 | } |
1070 | 1113 | ||
1071 | 1114 | ||
@@ -1166,6 +1209,7 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1166 | spin_lock_init(&card->lock); | 1209 | spin_lock_init(&card->lock); |
1167 | card->workqueue = create_workqueue("libertas_sdio"); | 1210 | card->workqueue = create_workqueue("libertas_sdio"); |
1168 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); | 1211 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); |
1212 | init_waitqueue_head(&card->pwron_waitq); | ||
1169 | 1213 | ||
1170 | /* Check if we support this card */ | 1214 | /* Check if we support this card */ |
1171 | for (i = 0; i < ARRAY_SIZE(fw_table); i++) { | 1215 | for (i = 0; i < ARRAY_SIZE(fw_table); i++) { |
@@ -1207,14 +1251,6 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1207 | if (ret) | 1251 | if (ret) |
1208 | goto err_activate_card; | 1252 | goto err_activate_card; |
1209 | 1253 | ||
1210 | ret = lbs_start_card(priv); | ||
1211 | if_sdio_power_off(card); | ||
1212 | if (ret) | ||
1213 | goto err_activate_card; | ||
1214 | |||
1215 | /* Tell PM core that we don't need the card to be powered now */ | ||
1216 | pm_runtime_put_noidle(&func->dev); | ||
1217 | |||
1218 | out: | 1254 | out: |
1219 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 1255 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
1220 | 1256 | ||