aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2012-04-16 18:53:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-17 14:57:14 -0400
commit66d647efe5e845c77f745478480c5e96218b7f3d (patch)
treec90d6cbbc6780f1a58e1fbfd315ac01b766e206e
parent534111c78c59a8db89c570fd07489243dc366a05 (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.c206
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
134static void if_sdio_finish_power_on(struct if_sdio_card *card);
135static 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
677static 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
701out:
702 release_firmware(helper);
703 release_firmware(mainfw);
704}
705
672static int if_sdio_prog_firmware(struct if_sdio_card *card) 706static 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
736success:
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
742out: 754out:
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
754static int if_sdio_power_on(struct if_sdio_card *card) 763/* Finish power on sequence (after firmware is loaded) */
764static 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
856release_irq: 837release_irq:
857 sdio_release_irq(func); 838 sdio_release_irq(func);
839release:
840 sdio_release_host(func);
841}
842
843static 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
858disable: 895disable:
859 sdio_disable_func(func); 896 sdio_disable_func(func);
860release: 897release:
@@ -1061,11 +1098,17 @@ static int if_sdio_power_save(struct lbs_private *priv)
1061static int if_sdio_power_restore(struct lbs_private *priv) 1098static 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
1218out: 1254out:
1219 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); 1255 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1220 1256