diff options
author | Vasily Khoruzhick <anarsoul@gmail.com> | 2011-01-21 15:44:48 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-03 16:38:25 -0500 |
commit | 16f775befc1ccf67e6b223c4d9bb17ac3502ab2c (patch) | |
tree | d8b3f752295c9aa98037950e522a25f4d857017a /drivers/net/wireless/libertas | |
parent | dbd98308a5dc6bc7e8e79ca8b7a0038638d24605 (diff) |
libertas_spi: Use workqueue in hw_host_to_card
Use workqueue to perform SPI xfers, it's necessary to fix
nasty "BUG: scheduling while atomic", because
spu_write() calls spi_sync() and spi_sync() may sleep, but
hw_host_to_card() callback can be called from atomic context.
Remove kthread completely, workqueue now does its job.
Restore intermediate buffers which were removed in commit
86c34fe89e9cad9e1ba4d1a8bbf98259035f4caf that introduced
mentioned bug.
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/if_spi.c | 368 |
1 files changed, 239 insertions, 129 deletions
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 00600239a053..f6c2cd665f49 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -20,10 +20,8 @@ | |||
20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | #include <linux/firmware.h> | 21 | #include <linux/firmware.h> |
22 | #include <linux/jiffies.h> | 22 | #include <linux/jiffies.h> |
23 | #include <linux/kthread.h> | ||
24 | #include <linux/list.h> | 23 | #include <linux/list.h> |
25 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
26 | #include <linux/semaphore.h> | ||
27 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
28 | #include <linux/spi/libertas_spi.h> | 26 | #include <linux/spi/libertas_spi.h> |
29 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
@@ -34,6 +32,12 @@ | |||
34 | #include "dev.h" | 32 | #include "dev.h" |
35 | #include "if_spi.h" | 33 | #include "if_spi.h" |
36 | 34 | ||
35 | struct if_spi_packet { | ||
36 | struct list_head list; | ||
37 | u16 blen; | ||
38 | u8 buffer[0] __attribute__((aligned(4))); | ||
39 | }; | ||
40 | |||
37 | struct if_spi_card { | 41 | struct if_spi_card { |
38 | struct spi_device *spi; | 42 | struct spi_device *spi; |
39 | struct lbs_private *priv; | 43 | struct lbs_private *priv; |
@@ -51,18 +55,36 @@ struct if_spi_card { | |||
51 | unsigned long spu_reg_delay; | 55 | unsigned long spu_reg_delay; |
52 | 56 | ||
53 | /* Handles all SPI communication (except for FW load) */ | 57 | /* Handles all SPI communication (except for FW load) */ |
54 | struct task_struct *spi_thread; | 58 | struct workqueue_struct *workqueue; |
55 | int run_thread; | 59 | struct work_struct packet_work; |
56 | |||
57 | /* Used to wake up the spi_thread */ | ||
58 | struct semaphore spi_ready; | ||
59 | struct semaphore spi_thread_terminated; | ||
60 | 60 | ||
61 | u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; | 61 | u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; |
62 | |||
63 | /* A buffer of incoming packets from libertas core. | ||
64 | * Since we can't sleep in hw_host_to_card, we have to buffer | ||
65 | * them. */ | ||
66 | struct list_head cmd_packet_list; | ||
67 | struct list_head data_packet_list; | ||
68 | |||
69 | /* Protects cmd_packet_list and data_packet_list */ | ||
70 | spinlock_t buffer_lock; | ||
62 | }; | 71 | }; |
63 | 72 | ||
64 | static void free_if_spi_card(struct if_spi_card *card) | 73 | static void free_if_spi_card(struct if_spi_card *card) |
65 | { | 74 | { |
75 | struct list_head *cursor, *next; | ||
76 | struct if_spi_packet *packet; | ||
77 | |||
78 | list_for_each_safe(cursor, next, &card->cmd_packet_list) { | ||
79 | packet = container_of(cursor, struct if_spi_packet, list); | ||
80 | list_del(&packet->list); | ||
81 | kfree(packet); | ||
82 | } | ||
83 | list_for_each_safe(cursor, next, &card->data_packet_list) { | ||
84 | packet = container_of(cursor, struct if_spi_packet, list); | ||
85 | list_del(&packet->list); | ||
86 | kfree(packet); | ||
87 | } | ||
66 | spi_set_drvdata(card->spi, NULL); | 88 | spi_set_drvdata(card->spi, NULL); |
67 | kfree(card); | 89 | kfree(card); |
68 | } | 90 | } |
@@ -622,7 +644,7 @@ out: | |||
622 | /* | 644 | /* |
623 | * SPI Transfer Thread | 645 | * SPI Transfer Thread |
624 | * | 646 | * |
625 | * The SPI thread handles all SPI transfers, so there is no need for a lock. | 647 | * The SPI worker handles all SPI transfers, so there is no need for a lock. |
626 | */ | 648 | */ |
627 | 649 | ||
628 | /* Move a command from the card to the host */ | 650 | /* Move a command from the card to the host */ |
@@ -742,6 +764,40 @@ out: | |||
742 | return err; | 764 | return err; |
743 | } | 765 | } |
744 | 766 | ||
767 | /* Move data or a command from the host to the card. */ | ||
768 | static void if_spi_h2c(struct if_spi_card *card, | ||
769 | struct if_spi_packet *packet, int type) | ||
770 | { | ||
771 | int err = 0; | ||
772 | u16 int_type, port_reg; | ||
773 | |||
774 | switch (type) { | ||
775 | case MVMS_DAT: | ||
776 | int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER; | ||
777 | port_reg = IF_SPI_DATA_RDWRPORT_REG; | ||
778 | break; | ||
779 | case MVMS_CMD: | ||
780 | int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER; | ||
781 | port_reg = IF_SPI_CMD_RDWRPORT_REG; | ||
782 | break; | ||
783 | default: | ||
784 | lbs_pr_err("can't transfer buffer of type %d\n", type); | ||
785 | err = -EINVAL; | ||
786 | goto out; | ||
787 | } | ||
788 | |||
789 | /* Write the data to the card */ | ||
790 | err = spu_write(card, port_reg, packet->buffer, packet->blen); | ||
791 | if (err) | ||
792 | goto out; | ||
793 | |||
794 | out: | ||
795 | kfree(packet); | ||
796 | |||
797 | if (err) | ||
798 | lbs_pr_err("%s: error %d\n", __func__, err); | ||
799 | } | ||
800 | |||
745 | /* Inform the host about a card event */ | 801 | /* Inform the host about a card event */ |
746 | static void if_spi_e2h(struct if_spi_card *card) | 802 | static void if_spi_e2h(struct if_spi_card *card) |
747 | { | 803 | { |
@@ -766,71 +822,88 @@ out: | |||
766 | lbs_pr_err("%s: error %d\n", __func__, err); | 822 | lbs_pr_err("%s: error %d\n", __func__, err); |
767 | } | 823 | } |
768 | 824 | ||
769 | static int lbs_spi_thread(void *data) | 825 | static void if_spi_host_to_card_worker(struct work_struct *work) |
770 | { | 826 | { |
771 | int err; | 827 | int err; |
772 | struct if_spi_card *card = data; | 828 | struct if_spi_card *card; |
773 | u16 hiStatus; | 829 | u16 hiStatus; |
830 | unsigned long flags; | ||
831 | struct if_spi_packet *packet; | ||
774 | 832 | ||
775 | while (1) { | 833 | card = container_of(work, struct if_spi_card, packet_work); |
776 | /* Wait to be woken up by one of two things. First, our ISR | ||
777 | * could tell us that something happened on the WLAN. | ||
778 | * Secondly, libertas could call hw_host_to_card with more | ||
779 | * data, which we might be able to send. | ||
780 | */ | ||
781 | do { | ||
782 | err = down_interruptible(&card->spi_ready); | ||
783 | if (!card->run_thread) { | ||
784 | up(&card->spi_thread_terminated); | ||
785 | do_exit(0); | ||
786 | } | ||
787 | } while (err == -EINTR); | ||
788 | 834 | ||
789 | /* Read the host interrupt status register to see what we | 835 | lbs_deb_enter(LBS_DEB_SPI); |
790 | * can do. */ | 836 | |
791 | err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, | 837 | /* Read the host interrupt status register to see what we |
792 | &hiStatus); | 838 | * can do. */ |
793 | if (err) { | 839 | err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, |
794 | lbs_pr_err("I/O error\n"); | 840 | &hiStatus); |
841 | if (err) { | ||
842 | lbs_pr_err("I/O error\n"); | ||
843 | goto err; | ||
844 | } | ||
845 | |||
846 | if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) { | ||
847 | err = if_spi_c2h_cmd(card); | ||
848 | if (err) | ||
795 | goto err; | 849 | goto err; |
796 | } | 850 | } |
851 | if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) { | ||
852 | err = if_spi_c2h_data(card); | ||
853 | if (err) | ||
854 | goto err; | ||
855 | } | ||
797 | 856 | ||
798 | if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) { | 857 | /* workaround: in PS mode, the card does not set the Command |
799 | err = if_spi_c2h_cmd(card); | 858 | * Download Ready bit, but it sets TX Download Ready. */ |
800 | if (err) | 859 | if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || |
801 | goto err; | 860 | (card->priv->psstate != PS_STATE_FULL_POWER && |
802 | } | 861 | (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { |
803 | if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) { | 862 | /* This means two things. First of all, |
804 | err = if_spi_c2h_data(card); | 863 | * if there was a previous command sent, the card has |
805 | if (err) | 864 | * successfully received it. |
806 | goto err; | 865 | * Secondly, it is now ready to download another |
866 | * command. | ||
867 | */ | ||
868 | lbs_host_to_card_done(card->priv); | ||
869 | |||
870 | /* Do we have any command packets from the host to | ||
871 | * send? */ | ||
872 | packet = NULL; | ||
873 | spin_lock_irqsave(&card->buffer_lock, flags); | ||
874 | if (!list_empty(&card->cmd_packet_list)) { | ||
875 | packet = (struct if_spi_packet *)(card-> | ||
876 | cmd_packet_list.next); | ||
877 | list_del(&packet->list); | ||
807 | } | 878 | } |
879 | spin_unlock_irqrestore(&card->buffer_lock, flags); | ||
808 | 880 | ||
809 | /* workaround: in PS mode, the card does not set the Command | 881 | if (packet) |
810 | * Download Ready bit, but it sets TX Download Ready. */ | 882 | if_spi_h2c(card, packet, MVMS_CMD); |
811 | if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || | 883 | } |
812 | (card->priv->psstate != PS_STATE_FULL_POWER && | 884 | if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { |
813 | (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { | 885 | /* Do we have any data packets from the host to |
814 | lbs_host_to_card_done(card->priv); | 886 | * send? */ |
887 | packet = NULL; | ||
888 | spin_lock_irqsave(&card->buffer_lock, flags); | ||
889 | if (!list_empty(&card->data_packet_list)) { | ||
890 | packet = (struct if_spi_packet *)(card-> | ||
891 | data_packet_list.next); | ||
892 | list_del(&packet->list); | ||
815 | } | 893 | } |
894 | spin_unlock_irqrestore(&card->buffer_lock, flags); | ||
816 | 895 | ||
817 | if (hiStatus & IF_SPI_HIST_CARD_EVENT) | 896 | if (packet) |
818 | if_spi_e2h(card); | 897 | if_spi_h2c(card, packet, MVMS_DAT); |
898 | } | ||
899 | if (hiStatus & IF_SPI_HIST_CARD_EVENT) | ||
900 | if_spi_e2h(card); | ||
819 | 901 | ||
820 | err: | 902 | err: |
821 | if (err) | 903 | if (err) |
822 | lbs_pr_err("%s: got error %d\n", __func__, err); | 904 | lbs_pr_err("%s: got error %d\n", __func__, err); |
823 | } | ||
824 | } | ||
825 | 905 | ||
826 | /* Block until lbs_spi_thread thread has terminated */ | 906 | lbs_deb_leave(LBS_DEB_SPI); |
827 | static void if_spi_terminate_spi_thread(struct if_spi_card *card) | ||
828 | { | ||
829 | /* It would be nice to use kthread_stop here, but that function | ||
830 | * can't wake threads waiting for a semaphore. */ | ||
831 | card->run_thread = 0; | ||
832 | up(&card->spi_ready); | ||
833 | down(&card->spi_thread_terminated); | ||
834 | } | 907 | } |
835 | 908 | ||
836 | /* | 909 | /* |
@@ -842,18 +915,40 @@ static int if_spi_host_to_card(struct lbs_private *priv, | |||
842 | u8 type, u8 *buf, u16 nb) | 915 | u8 type, u8 *buf, u16 nb) |
843 | { | 916 | { |
844 | int err = 0; | 917 | int err = 0; |
918 | unsigned long flags; | ||
845 | struct if_spi_card *card = priv->card; | 919 | struct if_spi_card *card = priv->card; |
920 | struct if_spi_packet *packet; | ||
921 | u16 blen; | ||
846 | 922 | ||
847 | lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); | 923 | lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); |
848 | 924 | ||
849 | nb = ALIGN(nb, 4); | 925 | if (nb == 0) { |
926 | lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb); | ||
927 | err = -EINVAL; | ||
928 | goto out; | ||
929 | } | ||
930 | blen = ALIGN(nb, 4); | ||
931 | packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC); | ||
932 | if (!packet) { | ||
933 | err = -ENOMEM; | ||
934 | goto out; | ||
935 | } | ||
936 | packet->blen = blen; | ||
937 | memcpy(packet->buffer, buf, nb); | ||
938 | memset(packet->buffer + nb, 0, blen - nb); | ||
850 | 939 | ||
851 | switch (type) { | 940 | switch (type) { |
852 | case MVMS_CMD: | 941 | case MVMS_CMD: |
853 | err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, buf, nb); | 942 | priv->dnld_sent = DNLD_CMD_SENT; |
943 | spin_lock_irqsave(&card->buffer_lock, flags); | ||
944 | list_add_tail(&packet->list, &card->cmd_packet_list); | ||
945 | spin_unlock_irqrestore(&card->buffer_lock, flags); | ||
854 | break; | 946 | break; |
855 | case MVMS_DAT: | 947 | case MVMS_DAT: |
856 | err = spu_write(card, IF_SPI_DATA_RDWRPORT_REG, buf, nb); | 948 | priv->dnld_sent = DNLD_DATA_SENT; |
949 | spin_lock_irqsave(&card->buffer_lock, flags); | ||
950 | list_add_tail(&packet->list, &card->data_packet_list); | ||
951 | spin_unlock_irqrestore(&card->buffer_lock, flags); | ||
857 | break; | 952 | break; |
858 | default: | 953 | default: |
859 | lbs_pr_err("can't transfer buffer of type %d", type); | 954 | lbs_pr_err("can't transfer buffer of type %d", type); |
@@ -861,6 +956,9 @@ static int if_spi_host_to_card(struct lbs_private *priv, | |||
861 | break; | 956 | break; |
862 | } | 957 | } |
863 | 958 | ||
959 | /* Queue spi xfer work */ | ||
960 | queue_work(card->workqueue, &card->packet_work); | ||
961 | out: | ||
864 | lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); | 962 | lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); |
865 | return err; | 963 | return err; |
866 | } | 964 | } |
@@ -869,13 +967,14 @@ static int if_spi_host_to_card(struct lbs_private *priv, | |||
869 | * Host Interrupts | 967 | * Host Interrupts |
870 | * | 968 | * |
871 | * Service incoming interrupts from the WLAN device. We can't sleep here, so | 969 | * Service incoming interrupts from the WLAN device. We can't sleep here, so |
872 | * don't try to talk on the SPI bus, just wake up the SPI thread. | 970 | * don't try to talk on the SPI bus, just queue the SPI xfer work. |
873 | */ | 971 | */ |
874 | static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) | 972 | static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) |
875 | { | 973 | { |
876 | struct if_spi_card *card = dev_id; | 974 | struct if_spi_card *card = dev_id; |
877 | 975 | ||
878 | up(&card->spi_ready); | 976 | queue_work(card->workqueue, &card->packet_work); |
977 | |||
879 | return IRQ_HANDLED; | 978 | return IRQ_HANDLED; |
880 | } | 979 | } |
881 | 980 | ||
@@ -883,56 +982,26 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) | |||
883 | * SPI callbacks | 982 | * SPI callbacks |
884 | */ | 983 | */ |
885 | 984 | ||
886 | static int __devinit if_spi_probe(struct spi_device *spi) | 985 | static int if_spi_init_card(struct if_spi_card *card) |
887 | { | 986 | { |
888 | struct if_spi_card *card; | 987 | struct spi_device *spi = card->spi; |
889 | struct lbs_private *priv = NULL; | 988 | int err, i; |
890 | struct libertas_spi_platform_data *pdata = spi->dev.platform_data; | ||
891 | int err = 0, i; | ||
892 | u32 scratch; | 989 | u32 scratch; |
893 | struct sched_param param = { .sched_priority = 1 }; | ||
894 | const struct firmware *helper = NULL; | 990 | const struct firmware *helper = NULL; |
895 | const struct firmware *mainfw = NULL; | 991 | const struct firmware *mainfw = NULL; |
896 | 992 | ||
897 | lbs_deb_enter(LBS_DEB_SPI); | 993 | lbs_deb_enter(LBS_DEB_SPI); |
898 | 994 | ||
899 | if (!pdata) { | 995 | err = spu_init(card, card->pdata->use_dummy_writes); |
900 | err = -EINVAL; | ||
901 | goto out; | ||
902 | } | ||
903 | |||
904 | if (pdata->setup) { | ||
905 | err = pdata->setup(spi); | ||
906 | if (err) | ||
907 | goto out; | ||
908 | } | ||
909 | |||
910 | /* Allocate card structure to represent this specific device */ | ||
911 | card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL); | ||
912 | if (!card) { | ||
913 | err = -ENOMEM; | ||
914 | goto out; | ||
915 | } | ||
916 | spi_set_drvdata(spi, card); | ||
917 | card->pdata = pdata; | ||
918 | card->spi = spi; | ||
919 | card->prev_xfer_time = jiffies; | ||
920 | |||
921 | sema_init(&card->spi_ready, 0); | ||
922 | sema_init(&card->spi_thread_terminated, 0); | ||
923 | |||
924 | /* Initialize the SPI Interface Unit */ | ||
925 | err = spu_init(card, pdata->use_dummy_writes); | ||
926 | if (err) | 996 | if (err) |
927 | goto free_card; | 997 | goto out; |
928 | err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); | 998 | err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); |
929 | if (err) | 999 | if (err) |
930 | goto free_card; | 1000 | goto out; |
931 | 1001 | ||
932 | /* Firmware load */ | ||
933 | err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); | 1002 | err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); |
934 | if (err) | 1003 | if (err) |
935 | goto free_card; | 1004 | goto out; |
936 | if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) | 1005 | if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC) |
937 | lbs_deb_spi("Firmware is already loaded for " | 1006 | lbs_deb_spi("Firmware is already loaded for " |
938 | "Marvell WLAN 802.11 adapter\n"); | 1007 | "Marvell WLAN 802.11 adapter\n"); |
@@ -946,7 +1015,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
946 | lbs_pr_err("Unsupported chip_id: 0x%02x\n", | 1015 | lbs_pr_err("Unsupported chip_id: 0x%02x\n", |
947 | card->card_id); | 1016 | card->card_id); |
948 | err = -ENODEV; | 1017 | err = -ENODEV; |
949 | goto free_card; | 1018 | goto out; |
950 | } | 1019 | } |
951 | 1020 | ||
952 | err = lbs_get_firmware(&card->spi->dev, NULL, NULL, | 1021 | err = lbs_get_firmware(&card->spi->dev, NULL, NULL, |
@@ -954,7 +1023,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
954 | &mainfw); | 1023 | &mainfw); |
955 | if (err) { | 1024 | if (err) { |
956 | lbs_pr_err("failed to find firmware (%d)\n", err); | 1025 | lbs_pr_err("failed to find firmware (%d)\n", err); |
957 | goto free_card; | 1026 | goto out; |
958 | } | 1027 | } |
959 | 1028 | ||
960 | lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " | 1029 | lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter " |
@@ -966,15 +1035,68 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
966 | spi->max_speed_hz); | 1035 | spi->max_speed_hz); |
967 | err = if_spi_prog_helper_firmware(card, helper); | 1036 | err = if_spi_prog_helper_firmware(card, helper); |
968 | if (err) | 1037 | if (err) |
969 | goto free_card; | 1038 | goto out; |
970 | err = if_spi_prog_main_firmware(card, mainfw); | 1039 | err = if_spi_prog_main_firmware(card, mainfw); |
971 | if (err) | 1040 | if (err) |
972 | goto free_card; | 1041 | goto out; |
973 | lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); | 1042 | lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n"); |
974 | } | 1043 | } |
975 | 1044 | ||
976 | err = spu_set_interrupt_mode(card, 0, 1); | 1045 | err = spu_set_interrupt_mode(card, 0, 1); |
977 | if (err) | 1046 | if (err) |
1047 | goto out; | ||
1048 | |||
1049 | out: | ||
1050 | if (helper) | ||
1051 | release_firmware(helper); | ||
1052 | if (mainfw) | ||
1053 | release_firmware(mainfw); | ||
1054 | |||
1055 | lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); | ||
1056 | |||
1057 | return err; | ||
1058 | } | ||
1059 | |||
1060 | static int __devinit if_spi_probe(struct spi_device *spi) | ||
1061 | { | ||
1062 | struct if_spi_card *card; | ||
1063 | struct lbs_private *priv = NULL; | ||
1064 | struct libertas_spi_platform_data *pdata = spi->dev.platform_data; | ||
1065 | int err = 0; | ||
1066 | |||
1067 | lbs_deb_enter(LBS_DEB_SPI); | ||
1068 | |||
1069 | if (!pdata) { | ||
1070 | err = -EINVAL; | ||
1071 | goto out; | ||
1072 | } | ||
1073 | |||
1074 | if (pdata->setup) { | ||
1075 | err = pdata->setup(spi); | ||
1076 | if (err) | ||
1077 | goto out; | ||
1078 | } | ||
1079 | |||
1080 | /* Allocate card structure to represent this specific device */ | ||
1081 | card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL); | ||
1082 | if (!card) { | ||
1083 | err = -ENOMEM; | ||
1084 | goto teardown; | ||
1085 | } | ||
1086 | spi_set_drvdata(spi, card); | ||
1087 | card->pdata = pdata; | ||
1088 | card->spi = spi; | ||
1089 | card->prev_xfer_time = jiffies; | ||
1090 | |||
1091 | INIT_LIST_HEAD(&card->cmd_packet_list); | ||
1092 | INIT_LIST_HEAD(&card->data_packet_list); | ||
1093 | spin_lock_init(&card->buffer_lock); | ||
1094 | |||
1095 | /* Initialize the SPI Interface Unit */ | ||
1096 | |||
1097 | /* Firmware load */ | ||
1098 | err = if_spi_init_card(card); | ||
1099 | if (err) | ||
978 | goto free_card; | 1100 | goto free_card; |
979 | 1101 | ||
980 | /* Register our card with libertas. | 1102 | /* Register our card with libertas. |
@@ -993,27 +1115,16 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
993 | priv->fw_ready = 1; | 1115 | priv->fw_ready = 1; |
994 | 1116 | ||
995 | /* Initialize interrupt handling stuff. */ | 1117 | /* Initialize interrupt handling stuff. */ |
996 | card->run_thread = 1; | 1118 | card->workqueue = create_workqueue("libertas_spi"); |
997 | card->spi_thread = kthread_run(lbs_spi_thread, card, "lbs_spi_thread"); | 1119 | INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); |
998 | if (IS_ERR(card->spi_thread)) { | ||
999 | card->run_thread = 0; | ||
1000 | err = PTR_ERR(card->spi_thread); | ||
1001 | lbs_pr_err("error creating SPI thread: err=%d\n", err); | ||
1002 | goto remove_card; | ||
1003 | } | ||
1004 | if (sched_setscheduler(card->spi_thread, SCHED_FIFO, ¶m)) | ||
1005 | lbs_pr_err("Error setting scheduler, using default.\n"); | ||
1006 | 1120 | ||
1007 | err = request_irq(spi->irq, if_spi_host_interrupt, | 1121 | err = request_irq(spi->irq, if_spi_host_interrupt, |
1008 | IRQF_TRIGGER_FALLING, "libertas_spi", card); | 1122 | IRQF_TRIGGER_FALLING, "libertas_spi", card); |
1009 | if (err) { | 1123 | if (err) { |
1010 | lbs_pr_err("can't get host irq line-- request_irq failed\n"); | 1124 | lbs_pr_err("can't get host irq line-- request_irq failed\n"); |
1011 | goto terminate_thread; | 1125 | goto terminate_workqueue; |
1012 | } | 1126 | } |
1013 | 1127 | ||
1014 | /* poke the IRQ handler so that we don't miss the first interrupt */ | ||
1015 | up(&card->spi_ready); | ||
1016 | |||
1017 | /* Start the card. | 1128 | /* Start the card. |
1018 | * This will call register_netdev, and we'll start | 1129 | * This will call register_netdev, and we'll start |
1019 | * getting interrupts... */ | 1130 | * getting interrupts... */ |
@@ -1028,18 +1139,16 @@ static int __devinit if_spi_probe(struct spi_device *spi) | |||
1028 | 1139 | ||
1029 | release_irq: | 1140 | release_irq: |
1030 | free_irq(spi->irq, card); | 1141 | free_irq(spi->irq, card); |
1031 | terminate_thread: | 1142 | terminate_workqueue: |
1032 | if_spi_terminate_spi_thread(card); | 1143 | flush_workqueue(card->workqueue); |
1033 | remove_card: | 1144 | destroy_workqueue(card->workqueue); |
1034 | lbs_remove_card(priv); /* will call free_netdev */ | 1145 | lbs_remove_card(priv); /* will call free_netdev */ |
1035 | free_card: | 1146 | free_card: |
1036 | free_if_spi_card(card); | 1147 | free_if_spi_card(card); |
1148 | teardown: | ||
1149 | if (pdata->teardown) | ||
1150 | pdata->teardown(spi); | ||
1037 | out: | 1151 | out: |
1038 | if (helper) | ||
1039 | release_firmware(helper); | ||
1040 | if (mainfw) | ||
1041 | release_firmware(mainfw); | ||
1042 | |||
1043 | lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); | 1152 | lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); |
1044 | return err; | 1153 | return err; |
1045 | } | 1154 | } |
@@ -1056,7 +1165,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) | |||
1056 | lbs_remove_card(priv); /* will call free_netdev */ | 1165 | lbs_remove_card(priv); /* will call free_netdev */ |
1057 | 1166 | ||
1058 | free_irq(spi->irq, card); | 1167 | free_irq(spi->irq, card); |
1059 | if_spi_terminate_spi_thread(card); | 1168 | flush_workqueue(card->workqueue); |
1169 | destroy_workqueue(card->workqueue); | ||
1060 | if (card->pdata->teardown) | 1170 | if (card->pdata->teardown) |
1061 | card->pdata->teardown(spi); | 1171 | card->pdata->teardown(spi); |
1062 | free_if_spi_card(card); | 1172 | free_if_spi_card(card); |