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