diff options
Diffstat (limited to 'drivers/net/wireless/libertas/if_sdio.c')
-rw-r--r-- | drivers/net/wireless/libertas/if_sdio.c | 229 |
1 files changed, 121 insertions, 108 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 9804ebc892d4..76caebaa4397 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -65,12 +65,6 @@ static void if_sdio_interrupt(struct sdio_func *func); | |||
65 | */ | 65 | */ |
66 | static u8 user_rmmod; | 66 | static u8 user_rmmod; |
67 | 67 | ||
68 | static char *lbs_helper_name = NULL; | ||
69 | module_param_named(helper_name, lbs_helper_name, charp, 0644); | ||
70 | |||
71 | static char *lbs_fw_name = NULL; | ||
72 | module_param_named(fw_name, lbs_fw_name, charp, 0644); | ||
73 | |||
74 | static const struct sdio_device_id if_sdio_ids[] = { | 68 | static const struct sdio_device_id if_sdio_ids[] = { |
75 | { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, | 69 | { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, |
76 | SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, | 70 | SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, |
@@ -123,11 +117,8 @@ struct if_sdio_card { | |||
123 | int model; | 117 | int model; |
124 | unsigned long ioport; | 118 | unsigned long ioport; |
125 | unsigned int scratch_reg; | 119 | unsigned int scratch_reg; |
126 | 120 | bool started; | |
127 | const char *helper; | 121 | wait_queue_head_t pwron_waitq; |
128 | const char *firmware; | ||
129 | bool helper_allocated; | ||
130 | bool firmware_allocated; | ||
131 | 122 | ||
132 | u8 buffer[65536] __attribute__((aligned(4))); | 123 | u8 buffer[65536] __attribute__((aligned(4))); |
133 | 124 | ||
@@ -140,6 +131,9 @@ struct if_sdio_card { | |||
140 | u8 rx_unit; | 131 | u8 rx_unit; |
141 | }; | 132 | }; |
142 | 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 | |||
143 | /********************************************************************/ | 137 | /********************************************************************/ |
144 | /* I/O */ | 138 | /* I/O */ |
145 | /********************************************************************/ | 139 | /********************************************************************/ |
@@ -680,12 +674,39 @@ out: | |||
680 | return ret; | 674 | return ret; |
681 | } | 675 | } |
682 | 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 | |||
683 | static int if_sdio_prog_firmware(struct if_sdio_card *card) | 706 | static int if_sdio_prog_firmware(struct if_sdio_card *card) |
684 | { | 707 | { |
685 | int ret; | 708 | int ret; |
686 | u16 scratch; | 709 | u16 scratch; |
687 | const struct firmware *helper = NULL; | ||
688 | const struct firmware *mainfw = NULL; | ||
689 | 710 | ||
690 | lbs_deb_enter(LBS_DEB_SDIO); | 711 | lbs_deb_enter(LBS_DEB_SDIO); |
691 | 712 | ||
@@ -719,43 +740,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) | |||
719 | */ | 740 | */ |
720 | if (scratch == IF_SDIO_FIRMWARE_OK) { | 741 | if (scratch == IF_SDIO_FIRMWARE_OK) { |
721 | lbs_deb_sdio("firmware already loaded\n"); | 742 | lbs_deb_sdio("firmware already loaded\n"); |
722 | goto success; | 743 | if_sdio_finish_power_on(card); |
744 | return 0; | ||
723 | } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { | 745 | } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { |
724 | lbs_deb_sdio("firmware may be running\n"); | 746 | lbs_deb_sdio("firmware may be running\n"); |
725 | goto success; | 747 | if_sdio_finish_power_on(card); |
726 | } | 748 | return 0; |
727 | |||
728 | ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, | ||
729 | card->model, &fw_table[0], &helper, &mainfw); | ||
730 | if (ret) { | ||
731 | pr_err("failed to find firmware (%d)\n", ret); | ||
732 | goto out; | ||
733 | } | 749 | } |
734 | 750 | ||
735 | ret = if_sdio_prog_helper(card, helper); | 751 | ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model, |
736 | if (ret) | 752 | fw_table, if_sdio_do_prog_firmware); |
737 | goto out; | ||
738 | |||
739 | lbs_deb_sdio("Helper firmware loaded\n"); | ||
740 | |||
741 | ret = if_sdio_prog_real(card, mainfw); | ||
742 | if (ret) | ||
743 | goto out; | ||
744 | |||
745 | lbs_deb_sdio("Firmware loaded\n"); | ||
746 | |||
747 | success: | ||
748 | sdio_claim_host(card->func); | ||
749 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | ||
750 | sdio_release_host(card->func); | ||
751 | ret = 0; | ||
752 | 753 | ||
753 | out: | 754 | out: |
754 | if (helper) | ||
755 | release_firmware(helper); | ||
756 | if (mainfw) | ||
757 | release_firmware(mainfw); | ||
758 | |||
759 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 755 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
760 | return ret; | 756 | return ret; |
761 | } | 757 | } |
@@ -764,55 +760,15 @@ out: | |||
764 | /* Power management */ | 760 | /* Power management */ |
765 | /********************************************************************/ | 761 | /********************************************************************/ |
766 | 762 | ||
767 | 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) | ||
768 | { | 765 | { |
769 | struct sdio_func *func = card->func; | 766 | struct sdio_func *func = card->func; |
770 | struct lbs_private *priv = card->priv; | 767 | struct lbs_private *priv = card->priv; |
771 | struct mmc_host *host = func->card->host; | ||
772 | int ret; | 768 | int ret; |
773 | 769 | ||
774 | sdio_claim_host(func); | 770 | sdio_claim_host(func); |
775 | 771 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | |
776 | ret = sdio_enable_func(func); | ||
777 | if (ret) | ||
778 | goto release; | ||
779 | |||
780 | /* For 1-bit transfers to the 8686 model, we need to enable the | ||
781 | * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 | ||
782 | * bit to allow access to non-vendor registers. */ | ||
783 | if ((card->model == MODEL_8686) && | ||
784 | (host->caps & MMC_CAP_SDIO_IRQ) && | ||
785 | (host->ios.bus_width == MMC_BUS_WIDTH_1)) { | ||
786 | u8 reg; | ||
787 | |||
788 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
789 | reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); | ||
790 | if (ret) | ||
791 | goto disable; | ||
792 | |||
793 | reg |= SDIO_BUS_ECSI; | ||
794 | sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); | ||
795 | if (ret) | ||
796 | goto disable; | ||
797 | } | ||
798 | |||
799 | card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); | ||
800 | if (ret) | ||
801 | goto disable; | ||
802 | |||
803 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; | ||
804 | if (ret) | ||
805 | goto disable; | ||
806 | |||
807 | card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; | ||
808 | if (ret) | ||
809 | goto disable; | ||
810 | |||
811 | sdio_release_host(func); | ||
812 | ret = if_sdio_prog_firmware(card); | ||
813 | sdio_claim_host(func); | ||
814 | if (ret) | ||
815 | goto disable; | ||
816 | 772 | ||
817 | /* | 773 | /* |
818 | * Get rx_unit if the chip is SD8688 or newer. | 774 | * Get rx_unit if the chip is SD8688 or newer. |
@@ -837,7 +793,7 @@ static int if_sdio_power_on(struct if_sdio_card *card) | |||
837 | */ | 793 | */ |
838 | ret = sdio_claim_irq(func, if_sdio_interrupt); | 794 | ret = sdio_claim_irq(func, if_sdio_interrupt); |
839 | if (ret) | 795 | if (ret) |
840 | goto disable; | 796 | goto release; |
841 | 797 | ||
842 | /* | 798 | /* |
843 | * Enable interrupts now that everything is set up | 799 | * Enable interrupts now that everything is set up |
@@ -863,11 +819,79 @@ static int if_sdio_power_on(struct if_sdio_card *card) | |||
863 | } | 819 | } |
864 | 820 | ||
865 | priv->fw_ready = 1; | 821 | priv->fw_ready = 1; |
822 | wake_up(&card->pwron_waitq); | ||
866 | 823 | ||
867 | 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; | ||
868 | 836 | ||
869 | release_irq: | 837 | release_irq: |
870 | 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 | |||
871 | disable: | 895 | disable: |
872 | sdio_disable_func(func); | 896 | sdio_disable_func(func); |
873 | release: | 897 | release: |
@@ -1074,11 +1098,17 @@ static int if_sdio_power_save(struct lbs_private *priv) | |||
1074 | static int if_sdio_power_restore(struct lbs_private *priv) | 1098 | static int if_sdio_power_restore(struct lbs_private *priv) |
1075 | { | 1099 | { |
1076 | struct if_sdio_card *card = priv->card; | 1100 | struct if_sdio_card *card = priv->card; |
1101 | int r; | ||
1077 | 1102 | ||
1078 | /* 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 */ |
1079 | pm_runtime_get_sync(&card->func->dev); | 1104 | pm_runtime_get_sync(&card->func->dev); |
1080 | 1105 | ||
1081 | 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; | ||
1082 | } | 1112 | } |
1083 | 1113 | ||
1084 | 1114 | ||
@@ -1179,6 +1209,7 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1179 | spin_lock_init(&card->lock); | 1209 | spin_lock_init(&card->lock); |
1180 | card->workqueue = create_workqueue("libertas_sdio"); | 1210 | card->workqueue = create_workqueue("libertas_sdio"); |
1181 | 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); | ||
1182 | 1213 | ||
1183 | /* Check if we support this card */ | 1214 | /* Check if we support this card */ |
1184 | for (i = 0; i < ARRAY_SIZE(fw_table); i++) { | 1215 | for (i = 0; i < ARRAY_SIZE(fw_table); i++) { |
@@ -1220,14 +1251,6 @@ static int if_sdio_probe(struct sdio_func *func, | |||
1220 | if (ret) | 1251 | if (ret) |
1221 | goto err_activate_card; | 1252 | goto err_activate_card; |
1222 | 1253 | ||
1223 | ret = lbs_start_card(priv); | ||
1224 | if_sdio_power_off(card); | ||
1225 | if (ret) | ||
1226 | goto err_activate_card; | ||
1227 | |||
1228 | /* Tell PM core that we don't need the card to be powered now */ | ||
1229 | pm_runtime_put_noidle(&func->dev); | ||
1230 | |||
1231 | out: | 1254 | out: |
1232 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 1255 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
1233 | 1256 | ||
@@ -1244,10 +1267,6 @@ free: | |||
1244 | kfree(packet); | 1267 | kfree(packet); |
1245 | } | 1268 | } |
1246 | 1269 | ||
1247 | if (card->helper_allocated) | ||
1248 | kfree(card->helper); | ||
1249 | if (card->firmware_allocated) | ||
1250 | kfree(card->firmware); | ||
1251 | kfree(card); | 1270 | kfree(card); |
1252 | 1271 | ||
1253 | goto out; | 1272 | goto out; |
@@ -1295,12 +1314,6 @@ static void if_sdio_remove(struct sdio_func *func) | |||
1295 | kfree(packet); | 1314 | kfree(packet); |
1296 | } | 1315 | } |
1297 | 1316 | ||
1298 | if (card->helper_allocated) | ||
1299 | kfree(card->helper); | ||
1300 | if (card->firmware_allocated) | ||
1301 | kfree(card->firmware); | ||
1302 | kfree(card); | ||
1303 | |||
1304 | lbs_deb_leave(LBS_DEB_SDIO); | 1317 | lbs_deb_leave(LBS_DEB_SDIO); |
1305 | } | 1318 | } |
1306 | 1319 | ||