diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-drv.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 151 |
1 files changed, 119 insertions, 32 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 17485e715424..05302d6f989f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -67,9 +67,11 @@ | |||
67 | 67 | ||
68 | #include "iwl-drv.h" | 68 | #include "iwl-drv.h" |
69 | #include "iwl-trans.h" | 69 | #include "iwl-trans.h" |
70 | #include "iwl-shared.h" | ||
71 | #include "iwl-op-mode.h" | 70 | #include "iwl-op-mode.h" |
72 | #include "iwl-agn-hw.h" | 71 | #include "iwl-agn-hw.h" |
72 | #include "iwl-fw.h" | ||
73 | #include "iwl-config.h" | ||
74 | #include "iwl-modparams.h" | ||
73 | 75 | ||
74 | /* private includes */ | 76 | /* private includes */ |
75 | #include "iwl-fw-file.h" | 77 | #include "iwl-fw-file.h" |
@@ -77,8 +79,10 @@ | |||
77 | /** | 79 | /** |
78 | * struct iwl_drv - drv common data | 80 | * struct iwl_drv - drv common data |
79 | * @fw: the iwl_fw structure | 81 | * @fw: the iwl_fw structure |
80 | * @shrd: pointer to common shared structure | ||
81 | * @op_mode: the running op_mode | 82 | * @op_mode: the running op_mode |
83 | * @trans: transport layer | ||
84 | * @dev: for debug prints only | ||
85 | * @cfg: configuration struct | ||
82 | * @fw_index: firmware revision to try loading | 86 | * @fw_index: firmware revision to try loading |
83 | * @firmware_name: composite filename of ucode file to load | 87 | * @firmware_name: composite filename of ucode file to load |
84 | * @request_firmware_complete: the firmware has been obtained from user space | 88 | * @request_firmware_complete: the firmware has been obtained from user space |
@@ -86,8 +90,10 @@ | |||
86 | struct iwl_drv { | 90 | struct iwl_drv { |
87 | struct iwl_fw fw; | 91 | struct iwl_fw fw; |
88 | 92 | ||
89 | struct iwl_shared *shrd; | ||
90 | struct iwl_op_mode *op_mode; | 93 | struct iwl_op_mode *op_mode; |
94 | struct iwl_trans *trans; | ||
95 | struct device *dev; | ||
96 | const struct iwl_cfg *cfg; | ||
91 | 97 | ||
92 | int fw_index; /* firmware we're trying to load */ | 98 | int fw_index; /* firmware we're trying to load */ |
93 | char firmware_name[25]; /* name of firmware file to load */ | 99 | char firmware_name[25]; /* name of firmware file to load */ |
@@ -110,7 +116,7 @@ struct fw_sec { | |||
110 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | 116 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) |
111 | { | 117 | { |
112 | if (desc->v_addr) | 118 | if (desc->v_addr) |
113 | dma_free_coherent(trans(drv)->dev, desc->len, | 119 | dma_free_coherent(drv->trans->dev, desc->len, |
114 | desc->v_addr, desc->p_addr); | 120 | desc->v_addr, desc->p_addr); |
115 | desc->v_addr = NULL; | 121 | desc->v_addr = NULL; |
116 | desc->len = 0; | 122 | desc->len = 0; |
@@ -138,7 +144,7 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | |||
138 | return -EINVAL; | 144 | return -EINVAL; |
139 | } | 145 | } |
140 | 146 | ||
141 | desc->v_addr = dma_alloc_coherent(trans(drv)->dev, sec->size, | 147 | desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size, |
142 | &desc->p_addr, GFP_KERNEL); | 148 | &desc->p_addr, GFP_KERNEL); |
143 | if (!desc->v_addr) | 149 | if (!desc->v_addr) |
144 | return -ENOMEM; | 150 | return -ENOMEM; |
@@ -156,8 +162,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | |||
156 | 162 | ||
157 | static int iwl_request_firmware(struct iwl_drv *drv, bool first) | 163 | static int iwl_request_firmware(struct iwl_drv *drv, bool first) |
158 | { | 164 | { |
159 | const struct iwl_cfg *cfg = cfg(drv); | 165 | const char *name_pre = drv->cfg->fw_name_pre; |
160 | const char *name_pre = cfg->fw_name_pre; | ||
161 | char tag[8]; | 166 | char tag[8]; |
162 | 167 | ||
163 | if (first) { | 168 | if (first) { |
@@ -166,14 +171,14 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
166 | strcpy(tag, UCODE_EXPERIMENTAL_TAG); | 171 | strcpy(tag, UCODE_EXPERIMENTAL_TAG); |
167 | } else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) { | 172 | } else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) { |
168 | #endif | 173 | #endif |
169 | drv->fw_index = cfg->ucode_api_max; | 174 | drv->fw_index = drv->cfg->ucode_api_max; |
170 | sprintf(tag, "%d", drv->fw_index); | 175 | sprintf(tag, "%d", drv->fw_index); |
171 | } else { | 176 | } else { |
172 | drv->fw_index--; | 177 | drv->fw_index--; |
173 | sprintf(tag, "%d", drv->fw_index); | 178 | sprintf(tag, "%d", drv->fw_index); |
174 | } | 179 | } |
175 | 180 | ||
176 | if (drv->fw_index < cfg->ucode_api_min) { | 181 | if (drv->fw_index < drv->cfg->ucode_api_min) { |
177 | IWL_ERR(drv, "no suitable firmware found!\n"); | 182 | IWL_ERR(drv, "no suitable firmware found!\n"); |
178 | return -ENOENT; | 183 | return -ENOENT; |
179 | } | 184 | } |
@@ -186,7 +191,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
186 | drv->firmware_name); | 191 | drv->firmware_name); |
187 | 192 | ||
188 | return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, | 193 | return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, |
189 | trans(drv)->dev, | 194 | drv->trans->dev, |
190 | GFP_KERNEL, drv, iwl_ucode_callback); | 195 | GFP_KERNEL, drv, iwl_ucode_callback); |
191 | } | 196 | } |
192 | 197 | ||
@@ -725,14 +730,13 @@ static int validate_sec_sizes(struct iwl_drv *drv, | |||
725 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | 730 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) |
726 | { | 731 | { |
727 | struct iwl_drv *drv = context; | 732 | struct iwl_drv *drv = context; |
728 | const struct iwl_cfg *cfg = cfg(drv); | ||
729 | struct iwl_fw *fw = &drv->fw; | 733 | struct iwl_fw *fw = &drv->fw; |
730 | struct iwl_ucode_header *ucode; | 734 | struct iwl_ucode_header *ucode; |
731 | int err; | 735 | int err; |
732 | struct iwl_firmware_pieces pieces; | 736 | struct iwl_firmware_pieces pieces; |
733 | const unsigned int api_max = cfg->ucode_api_max; | 737 | const unsigned int api_max = drv->cfg->ucode_api_max; |
734 | unsigned int api_ok = cfg->ucode_api_ok; | 738 | unsigned int api_ok = drv->cfg->ucode_api_ok; |
735 | const unsigned int api_min = cfg->ucode_api_min; | 739 | const unsigned int api_min = drv->cfg->ucode_api_min; |
736 | u32 api_ver; | 740 | u32 api_ver; |
737 | int i; | 741 | int i; |
738 | 742 | ||
@@ -811,7 +815,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
811 | * In mvm uCode there is no difference between data and instructions | 815 | * In mvm uCode there is no difference between data and instructions |
812 | * sections. | 816 | * sections. |
813 | */ | 817 | */ |
814 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, cfg)) | 818 | if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) |
815 | goto try_again; | 819 | goto try_again; |
816 | 820 | ||
817 | /* Allocate ucode buffers for card's bus-master loading ... */ | 821 | /* Allocate ucode buffers for card's bus-master loading ... */ |
@@ -835,14 +839,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
835 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; | 839 | fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; |
836 | else | 840 | else |
837 | fw->init_evtlog_size = | 841 | fw->init_evtlog_size = |
838 | cfg->base_params->max_event_log_size; | 842 | drv->cfg->base_params->max_event_log_size; |
839 | fw->init_errlog_ptr = pieces.init_errlog_ptr; | 843 | fw->init_errlog_ptr = pieces.init_errlog_ptr; |
840 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; | 844 | fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; |
841 | if (pieces.inst_evtlog_size) | 845 | if (pieces.inst_evtlog_size) |
842 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; | 846 | fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; |
843 | else | 847 | else |
844 | fw->inst_evtlog_size = | 848 | fw->inst_evtlog_size = |
845 | cfg->base_params->max_event_log_size; | 849 | drv->cfg->base_params->max_event_log_size; |
846 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; | 850 | fw->inst_errlog_ptr = pieces.inst_errlog_ptr; |
847 | 851 | ||
848 | /* | 852 | /* |
@@ -858,7 +862,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
858 | release_firmware(ucode_raw); | 862 | release_firmware(ucode_raw); |
859 | complete(&drv->request_firmware_complete); | 863 | complete(&drv->request_firmware_complete); |
860 | 864 | ||
861 | drv->op_mode = iwl_dvm_ops.start(drv->shrd->trans, &drv->fw); | 865 | drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw); |
862 | 866 | ||
863 | if (!drv->op_mode) | 867 | if (!drv->op_mode) |
864 | goto out_unbind; | 868 | goto out_unbind; |
@@ -878,24 +882,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
878 | release_firmware(ucode_raw); | 882 | release_firmware(ucode_raw); |
879 | out_unbind: | 883 | out_unbind: |
880 | complete(&drv->request_firmware_complete); | 884 | complete(&drv->request_firmware_complete); |
881 | device_release_driver(trans(drv)->dev); | 885 | device_release_driver(drv->trans->dev); |
882 | } | 886 | } |
883 | 887 | ||
884 | int iwl_drv_start(struct iwl_shared *shrd, | 888 | struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, |
885 | struct iwl_trans *trans, const struct iwl_cfg *cfg) | 889 | const struct iwl_cfg *cfg) |
886 | { | 890 | { |
887 | struct iwl_drv *drv; | 891 | struct iwl_drv *drv; |
888 | int ret; | 892 | int ret; |
889 | 893 | ||
890 | shrd->cfg = cfg; | ||
891 | |||
892 | drv = kzalloc(sizeof(*drv), GFP_KERNEL); | 894 | drv = kzalloc(sizeof(*drv), GFP_KERNEL); |
893 | if (!drv) { | 895 | if (!drv) { |
894 | dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv"); | 896 | dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv"); |
895 | return -ENOMEM; | 897 | return NULL; |
896 | } | 898 | } |
897 | drv->shrd = shrd; | 899 | drv->trans = trans; |
898 | shrd->drv = drv; | 900 | drv->dev = trans->dev; |
901 | drv->cfg = cfg; | ||
899 | 902 | ||
900 | init_completion(&drv->request_firmware_complete); | 903 | init_completion(&drv->request_firmware_complete); |
901 | 904 | ||
@@ -904,16 +907,14 @@ int iwl_drv_start(struct iwl_shared *shrd, | |||
904 | if (ret) { | 907 | if (ret) { |
905 | dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); | 908 | dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); |
906 | kfree(drv); | 909 | kfree(drv); |
907 | shrd->drv = NULL; | 910 | drv = NULL; |
908 | } | 911 | } |
909 | 912 | ||
910 | return ret; | 913 | return drv; |
911 | } | 914 | } |
912 | 915 | ||
913 | void iwl_drv_stop(struct iwl_shared *shrd) | 916 | void iwl_drv_stop(struct iwl_drv *drv) |
914 | { | 917 | { |
915 | struct iwl_drv *drv = shrd->drv; | ||
916 | |||
917 | wait_for_completion(&drv->request_firmware_complete); | 918 | wait_for_completion(&drv->request_firmware_complete); |
918 | 919 | ||
919 | /* op_mode can be NULL if its start failed */ | 920 | /* op_mode can be NULL if its start failed */ |
@@ -923,5 +924,91 @@ void iwl_drv_stop(struct iwl_shared *shrd) | |||
923 | iwl_dealloc_ucode(drv); | 924 | iwl_dealloc_ucode(drv); |
924 | 925 | ||
925 | kfree(drv); | 926 | kfree(drv); |
926 | shrd->drv = NULL; | ||
927 | } | 927 | } |
928 | |||
929 | |||
930 | /* shared module parameters */ | ||
931 | struct iwl_mod_params iwlwifi_mod_params = { | ||
932 | .amsdu_size_8K = 1, | ||
933 | .restart_fw = 1, | ||
934 | .plcp_check = true, | ||
935 | .bt_coex_active = true, | ||
936 | .power_level = IWL_POWER_INDEX_1, | ||
937 | .bt_ch_announce = true, | ||
938 | .auto_agg = true, | ||
939 | /* the rest are 0 by default */ | ||
940 | }; | ||
941 | |||
942 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
943 | module_param_named(debug, iwlwifi_mod_params.debug_level, uint, | ||
944 | S_IRUGO | S_IWUSR); | ||
945 | MODULE_PARM_DESC(debug, "debug output mask"); | ||
946 | #endif | ||
947 | |||
948 | module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO); | ||
949 | MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); | ||
950 | module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); | ||
951 | MODULE_PARM_DESC(11n_disable, | ||
952 | "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); | ||
953 | module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, | ||
954 | int, S_IRUGO); | ||
955 | MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); | ||
956 | module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO); | ||
957 | MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); | ||
958 | |||
959 | module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, | ||
960 | int, S_IRUGO); | ||
961 | MODULE_PARM_DESC(antenna_coupling, | ||
962 | "specify antenna coupling in dB (defualt: 0 dB)"); | ||
963 | |||
964 | module_param_named(bt_ch_inhibition, iwlwifi_mod_params.bt_ch_announce, | ||
965 | bool, S_IRUGO); | ||
966 | MODULE_PARM_DESC(bt_ch_inhibition, | ||
967 | "Enable BT channel inhibition (default: enable)"); | ||
968 | |||
969 | module_param_named(plcp_check, iwlwifi_mod_params.plcp_check, bool, S_IRUGO); | ||
970 | MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); | ||
971 | |||
972 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); | ||
973 | MODULE_PARM_DESC(wd_disable, | ||
974 | "Disable stuck queue watchdog timer 0=system default, " | ||
975 | "1=disable, 2=enable (default: 0)"); | ||
976 | |||
977 | /* | ||
978 | * set bt_coex_active to true, uCode will do kill/defer | ||
979 | * every time the priority line is asserted (BT is sending signals on the | ||
980 | * priority line in the PCIx). | ||
981 | * set bt_coex_active to false, uCode will ignore the BT activity and | ||
982 | * perform the normal operation | ||
983 | * | ||
984 | * User might experience transmit issue on some platform due to WiFi/BT | ||
985 | * co-exist problem. The possible behaviors are: | ||
986 | * Able to scan and finding all the available AP | ||
987 | * Not able to associate with any AP | ||
988 | * On those platforms, WiFi communication can be restored by set | ||
989 | * "bt_coex_active" module parameter to "false" | ||
990 | * | ||
991 | * default: bt_coex_active = true (BT_COEX_ENABLE) | ||
992 | */ | ||
993 | module_param_named(bt_coex_active, iwlwifi_mod_params.bt_coex_active, | ||
994 | bool, S_IRUGO); | ||
995 | MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)"); | ||
996 | |||
997 | module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, S_IRUGO); | ||
998 | MODULE_PARM_DESC(led_mode, "0=system default, " | ||
999 | "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)"); | ||
1000 | |||
1001 | module_param_named(power_save, iwlwifi_mod_params.power_save, | ||
1002 | bool, S_IRUGO); | ||
1003 | MODULE_PARM_DESC(power_save, | ||
1004 | "enable WiFi power management (default: disable)"); | ||
1005 | |||
1006 | module_param_named(power_level, iwlwifi_mod_params.power_level, | ||
1007 | int, S_IRUGO); | ||
1008 | MODULE_PARM_DESC(power_level, | ||
1009 | "default power save level (range from 1 - 5, default: 1)"); | ||
1010 | |||
1011 | module_param_named(auto_agg, iwlwifi_mod_params.auto_agg, | ||
1012 | bool, S_IRUGO); | ||
1013 | MODULE_PARM_DESC(auto_agg, | ||
1014 | "enable agg w/o check traffic load (default: enable)"); | ||