diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-drv.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 167 |
1 files changed, 133 insertions, 34 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index cc41cfaedfbd..198634b75ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/dma-mapping.h> | 64 | #include <linux/dma-mapping.h> |
65 | #include <linux/firmware.h> | 65 | #include <linux/firmware.h> |
66 | #include <linux/module.h> | 66 | #include <linux/module.h> |
67 | #include <linux/vmalloc.h> | ||
67 | 68 | ||
68 | #include "iwl-drv.h" | 69 | #include "iwl-drv.h" |
69 | #include "iwl-debug.h" | 70 | #include "iwl-debug.h" |
@@ -101,6 +102,10 @@ MODULE_VERSION(DRV_VERSION); | |||
101 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | 102 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); |
102 | MODULE_LICENSE("GPL"); | 103 | MODULE_LICENSE("GPL"); |
103 | 104 | ||
105 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
106 | static struct dentry *iwl_dbgfs_root; | ||
107 | #endif | ||
108 | |||
104 | /** | 109 | /** |
105 | * struct iwl_drv - drv common data | 110 | * struct iwl_drv - drv common data |
106 | * @list: list of drv structures using this opmode | 111 | * @list: list of drv structures using this opmode |
@@ -126,6 +131,12 @@ struct iwl_drv { | |||
126 | char firmware_name[25]; /* name of firmware file to load */ | 131 | char firmware_name[25]; /* name of firmware file to load */ |
127 | 132 | ||
128 | struct completion request_firmware_complete; | 133 | struct completion request_firmware_complete; |
134 | |||
135 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
136 | struct dentry *dbgfs_drv; | ||
137 | struct dentry *dbgfs_trans; | ||
138 | struct dentry *dbgfs_op_mode; | ||
139 | #endif | ||
129 | }; | 140 | }; |
130 | 141 | ||
131 | #define DVM_OP_MODE 0 | 142 | #define DVM_OP_MODE 0 |
@@ -154,10 +165,8 @@ struct fw_sec { | |||
154 | 165 | ||
155 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) | 166 | static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) |
156 | { | 167 | { |
157 | if (desc->v_addr) | 168 | vfree(desc->data); |
158 | dma_free_coherent(drv->trans->dev, desc->len, | 169 | desc->data = NULL; |
159 | desc->v_addr, desc->p_addr); | ||
160 | desc->v_addr = NULL; | ||
161 | desc->len = 0; | 170 | desc->len = 0; |
162 | } | 171 | } |
163 | 172 | ||
@@ -176,25 +185,29 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) | |||
176 | } | 185 | } |
177 | 186 | ||
178 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, | 187 | static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, |
179 | struct fw_sec *sec) | 188 | struct fw_sec *sec) |
180 | { | 189 | { |
181 | if (!sec || !sec->size) { | 190 | void *data; |
182 | desc->v_addr = NULL; | 191 | |
192 | desc->data = NULL; | ||
193 | |||
194 | if (!sec || !sec->size) | ||
183 | return -EINVAL; | 195 | return -EINVAL; |
184 | } | ||
185 | 196 | ||
186 | desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size, | 197 | data = vmalloc(sec->size); |
187 | &desc->p_addr, GFP_KERNEL); | 198 | if (!data) |
188 | if (!desc->v_addr) | ||
189 | return -ENOMEM; | 199 | return -ENOMEM; |
190 | 200 | ||
191 | desc->len = sec->size; | 201 | desc->len = sec->size; |
192 | desc->offset = sec->offset; | 202 | desc->offset = sec->offset; |
193 | memcpy(desc->v_addr, sec->data, sec->size); | 203 | memcpy(data, sec->data, desc->len); |
204 | desc->data = data; | ||
205 | |||
194 | return 0; | 206 | return 0; |
195 | } | 207 | } |
196 | 208 | ||
197 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); | 209 | static void iwl_req_fw_callback(const struct firmware *ucode_raw, |
210 | void *context); | ||
198 | 211 | ||
199 | #define UCODE_EXPERIMENTAL_INDEX 100 | 212 | #define UCODE_EXPERIMENTAL_INDEX 100 |
200 | #define UCODE_EXPERIMENTAL_TAG "exp" | 213 | #define UCODE_EXPERIMENTAL_TAG "exp" |
@@ -231,7 +244,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) | |||
231 | 244 | ||
232 | return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, | 245 | return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, |
233 | drv->trans->dev, | 246 | drv->trans->dev, |
234 | GFP_KERNEL, drv, iwl_ucode_callback); | 247 | GFP_KERNEL, drv, iwl_req_fw_callback); |
235 | } | 248 | } |
236 | 249 | ||
237 | struct fw_img_parsing { | 250 | struct fw_img_parsing { |
@@ -759,13 +772,57 @@ static int validate_sec_sizes(struct iwl_drv *drv, | |||
759 | return 0; | 772 | return 0; |
760 | } | 773 | } |
761 | 774 | ||
775 | static struct iwl_op_mode * | ||
776 | _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) | ||
777 | { | ||
778 | const struct iwl_op_mode_ops *ops = op->ops; | ||
779 | struct dentry *dbgfs_dir = NULL; | ||
780 | struct iwl_op_mode *op_mode = NULL; | ||
781 | |||
782 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
783 | drv->dbgfs_op_mode = debugfs_create_dir(op->name, | ||
784 | drv->dbgfs_drv); | ||
785 | if (!drv->dbgfs_op_mode) { | ||
786 | IWL_ERR(drv, | ||
787 | "failed to create opmode debugfs directory\n"); | ||
788 | return op_mode; | ||
789 | } | ||
790 | dbgfs_dir = drv->dbgfs_op_mode; | ||
791 | #endif | ||
792 | |||
793 | op_mode = ops->start(drv->trans, drv->cfg, &drv->fw, dbgfs_dir); | ||
794 | |||
795 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
796 | if (!op_mode) { | ||
797 | debugfs_remove_recursive(drv->dbgfs_op_mode); | ||
798 | drv->dbgfs_op_mode = NULL; | ||
799 | } | ||
800 | #endif | ||
801 | |||
802 | return op_mode; | ||
803 | } | ||
804 | |||
805 | static void _iwl_op_mode_stop(struct iwl_drv *drv) | ||
806 | { | ||
807 | /* op_mode can be NULL if its start failed */ | ||
808 | if (drv->op_mode) { | ||
809 | iwl_op_mode_stop(drv->op_mode); | ||
810 | drv->op_mode = NULL; | ||
811 | |||
812 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
813 | debugfs_remove_recursive(drv->dbgfs_op_mode); | ||
814 | drv->dbgfs_op_mode = NULL; | ||
815 | #endif | ||
816 | } | ||
817 | } | ||
818 | |||
762 | /** | 819 | /** |
763 | * iwl_ucode_callback - callback when firmware was loaded | 820 | * iwl_req_fw_callback - callback when firmware was loaded |
764 | * | 821 | * |
765 | * If loaded successfully, copies the firmware into buffers | 822 | * If loaded successfully, copies the firmware into buffers |
766 | * for the card to fetch (via DMA). | 823 | * for the card to fetch (via DMA). |
767 | */ | 824 | */ |
768 | static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | 825 | static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) |
769 | { | 826 | { |
770 | struct iwl_drv *drv = context; | 827 | struct iwl_drv *drv = context; |
771 | struct iwl_fw *fw = &drv->fw; | 828 | struct iwl_fw *fw = &drv->fw; |
@@ -908,8 +965,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
908 | list_add_tail(&drv->list, &op->drv); | 965 | list_add_tail(&drv->list, &op->drv); |
909 | 966 | ||
910 | if (op->ops) { | 967 | if (op->ops) { |
911 | const struct iwl_op_mode_ops *ops = op->ops; | 968 | drv->op_mode = _iwl_op_mode_start(drv, op); |
912 | drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw); | ||
913 | 969 | ||
914 | if (!drv->op_mode) { | 970 | if (!drv->op_mode) { |
915 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 971 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
@@ -969,24 +1025,51 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, | |||
969 | init_completion(&drv->request_firmware_complete); | 1025 | init_completion(&drv->request_firmware_complete); |
970 | INIT_LIST_HEAD(&drv->list); | 1026 | INIT_LIST_HEAD(&drv->list); |
971 | 1027 | ||
1028 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1029 | /* Create the device debugfs entries. */ | ||
1030 | drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), | ||
1031 | iwl_dbgfs_root); | ||
1032 | |||
1033 | if (!drv->dbgfs_drv) { | ||
1034 | IWL_ERR(drv, "failed to create debugfs directory\n"); | ||
1035 | goto err_free_drv; | ||
1036 | } | ||
1037 | |||
1038 | /* Create transport layer debugfs dir */ | ||
1039 | drv->trans->dbgfs_dir = debugfs_create_dir("trans", drv->dbgfs_drv); | ||
1040 | |||
1041 | if (!drv->trans->dbgfs_dir) { | ||
1042 | IWL_ERR(drv, "failed to create transport debugfs directory\n"); | ||
1043 | goto err_free_dbgfs; | ||
1044 | } | ||
1045 | #endif | ||
1046 | |||
972 | ret = iwl_request_firmware(drv, true); | 1047 | ret = iwl_request_firmware(drv, true); |
973 | 1048 | ||
974 | if (ret) { | 1049 | if (ret) { |
975 | IWL_ERR(trans, "Couldn't request the fw\n"); | 1050 | IWL_ERR(trans, "Couldn't request the fw\n"); |
976 | kfree(drv); | 1051 | goto err_fw; |
977 | drv = NULL; | ||
978 | } | 1052 | } |
979 | 1053 | ||
980 | return drv; | 1054 | return drv; |
1055 | |||
1056 | err_fw: | ||
1057 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1058 | err_free_dbgfs: | ||
1059 | debugfs_remove_recursive(drv->dbgfs_drv); | ||
1060 | err_free_drv: | ||
1061 | #endif | ||
1062 | kfree(drv); | ||
1063 | drv = NULL; | ||
1064 | |||
1065 | return drv; | ||
981 | } | 1066 | } |
982 | 1067 | ||
983 | void iwl_drv_stop(struct iwl_drv *drv) | 1068 | void iwl_drv_stop(struct iwl_drv *drv) |
984 | { | 1069 | { |
985 | wait_for_completion(&drv->request_firmware_complete); | 1070 | wait_for_completion(&drv->request_firmware_complete); |
986 | 1071 | ||
987 | /* op_mode can be NULL if its start failed */ | 1072 | _iwl_op_mode_stop(drv); |
988 | if (drv->op_mode) | ||
989 | iwl_op_mode_stop(drv->op_mode); | ||
990 | 1073 | ||
991 | iwl_dealloc_ucode(drv); | 1074 | iwl_dealloc_ucode(drv); |
992 | 1075 | ||
@@ -1000,6 +1083,10 @@ void iwl_drv_stop(struct iwl_drv *drv) | |||
1000 | list_del(&drv->list); | 1083 | list_del(&drv->list); |
1001 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1084 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1002 | 1085 | ||
1086 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1087 | debugfs_remove_recursive(drv->dbgfs_drv); | ||
1088 | #endif | ||
1089 | |||
1003 | kfree(drv); | 1090 | kfree(drv); |
1004 | } | 1091 | } |
1005 | 1092 | ||
@@ -1022,15 +1109,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops) | |||
1022 | { | 1109 | { |
1023 | int i; | 1110 | int i; |
1024 | struct iwl_drv *drv; | 1111 | struct iwl_drv *drv; |
1112 | struct iwlwifi_opmode_table *op; | ||
1025 | 1113 | ||
1026 | mutex_lock(&iwlwifi_opmode_table_mtx); | 1114 | mutex_lock(&iwlwifi_opmode_table_mtx); |
1027 | for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { | 1115 | for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { |
1028 | if (strcmp(iwlwifi_opmode_table[i].name, name)) | 1116 | op = &iwlwifi_opmode_table[i]; |
1117 | if (strcmp(op->name, name)) | ||
1029 | continue; | 1118 | continue; |
1030 | iwlwifi_opmode_table[i].ops = ops; | 1119 | op->ops = ops; |
1031 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | 1120 | /* TODO: need to handle exceptional case */ |
1032 | drv->op_mode = ops->start(drv->trans, drv->cfg, | 1121 | list_for_each_entry(drv, &op->drv, list) |
1033 | &drv->fw); | 1122 | drv->op_mode = _iwl_op_mode_start(drv, op); |
1123 | |||
1034 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1124 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1035 | return 0; | 1125 | return 0; |
1036 | } | 1126 | } |
@@ -1051,12 +1141,9 @@ void iwl_opmode_deregister(const char *name) | |||
1051 | iwlwifi_opmode_table[i].ops = NULL; | 1141 | iwlwifi_opmode_table[i].ops = NULL; |
1052 | 1142 | ||
1053 | /* call the stop routine for all devices */ | 1143 | /* call the stop routine for all devices */ |
1054 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { | 1144 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) |
1055 | if (drv->op_mode) { | 1145 | _iwl_op_mode_stop(drv); |
1056 | iwl_op_mode_stop(drv->op_mode); | 1146 | |
1057 | drv->op_mode = NULL; | ||
1058 | } | ||
1059 | } | ||
1060 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1147 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1061 | return; | 1148 | return; |
1062 | } | 1149 | } |
@@ -1076,6 +1163,14 @@ static int __init iwl_drv_init(void) | |||
1076 | pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); | 1163 | pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); |
1077 | pr_info(DRV_COPYRIGHT "\n"); | 1164 | pr_info(DRV_COPYRIGHT "\n"); |
1078 | 1165 | ||
1166 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1167 | /* Create the root of iwlwifi debugfs subsystem. */ | ||
1168 | iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL); | ||
1169 | |||
1170 | if (!iwl_dbgfs_root) | ||
1171 | return -EFAULT; | ||
1172 | #endif | ||
1173 | |||
1079 | return iwl_pci_register_driver(); | 1174 | return iwl_pci_register_driver(); |
1080 | } | 1175 | } |
1081 | module_init(iwl_drv_init); | 1176 | module_init(iwl_drv_init); |
@@ -1083,6 +1178,10 @@ module_init(iwl_drv_init); | |||
1083 | static void __exit iwl_drv_exit(void) | 1178 | static void __exit iwl_drv_exit(void) |
1084 | { | 1179 | { |
1085 | iwl_pci_unregister_driver(); | 1180 | iwl_pci_unregister_driver(); |
1181 | |||
1182 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1183 | debugfs_remove_recursive(iwl_dbgfs_root); | ||
1184 | #endif | ||
1086 | } | 1185 | } |
1087 | module_exit(iwl_drv_exit); | 1186 | module_exit(iwl_drv_exit); |
1088 | 1187 | ||