diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-drv.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 132 |
1 files changed, 114 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 35a9d65664e9..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 |
@@ -760,6 +770,50 @@ static int validate_sec_sizes(struct iwl_drv *drv, | |||
760 | return 0; | 770 | return 0; |
761 | } | 771 | } |
762 | 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 | |||
763 | /** | 817 | /** |
764 | * iwl_req_fw_callback - callback when firmware was loaded | 818 | * iwl_req_fw_callback - callback when firmware was loaded |
765 | * | 819 | * |
@@ -909,8 +963,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) | |||
909 | list_add_tail(&drv->list, &op->drv); | 963 | list_add_tail(&drv->list, &op->drv); |
910 | 964 | ||
911 | if (op->ops) { | 965 | if (op->ops) { |
912 | const struct iwl_op_mode_ops *ops = op->ops; | 966 | drv->op_mode = _iwl_op_mode_start(drv, op); |
913 | drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw); | ||
914 | 967 | ||
915 | if (!drv->op_mode) { | 968 | if (!drv->op_mode) { |
916 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 969 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
@@ -970,24 +1023,51 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, | |||
970 | init_completion(&drv->request_firmware_complete); | 1023 | init_completion(&drv->request_firmware_complete); |
971 | INIT_LIST_HEAD(&drv->list); | 1024 | INIT_LIST_HEAD(&drv->list); |
972 | 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 | |||
973 | ret = iwl_request_firmware(drv, true); | 1045 | ret = iwl_request_firmware(drv, true); |
974 | 1046 | ||
975 | if (ret) { | 1047 | if (ret) { |
976 | IWL_ERR(trans, "Couldn't request the fw\n"); | 1048 | IWL_ERR(trans, "Couldn't request the fw\n"); |
977 | kfree(drv); | 1049 | goto err_fw; |
978 | drv = NULL; | ||
979 | } | 1050 | } |
980 | 1051 | ||
981 | 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; | ||
982 | } | 1064 | } |
983 | 1065 | ||
984 | void iwl_drv_stop(struct iwl_drv *drv) | 1066 | void iwl_drv_stop(struct iwl_drv *drv) |
985 | { | 1067 | { |
986 | wait_for_completion(&drv->request_firmware_complete); | 1068 | wait_for_completion(&drv->request_firmware_complete); |
987 | 1069 | ||
988 | /* op_mode can be NULL if its start failed */ | 1070 | _iwl_op_mode_stop(drv); |
989 | if (drv->op_mode) | ||
990 | iwl_op_mode_stop(drv->op_mode); | ||
991 | 1071 | ||
992 | iwl_dealloc_ucode(drv); | 1072 | iwl_dealloc_ucode(drv); |
993 | 1073 | ||
@@ -1001,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv) | |||
1001 | list_del(&drv->list); | 1081 | list_del(&drv->list); |
1002 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1082 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1003 | 1083 | ||
1084 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1085 | debugfs_remove_recursive(drv->dbgfs_drv); | ||
1086 | #endif | ||
1087 | |||
1004 | kfree(drv); | 1088 | kfree(drv); |
1005 | } | 1089 | } |
1006 | 1090 | ||
@@ -1023,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops) | |||
1023 | { | 1107 | { |
1024 | int i; | 1108 | int i; |
1025 | struct iwl_drv *drv; | 1109 | struct iwl_drv *drv; |
1110 | struct iwlwifi_opmode_table *op; | ||
1026 | 1111 | ||
1027 | mutex_lock(&iwlwifi_opmode_table_mtx); | 1112 | mutex_lock(&iwlwifi_opmode_table_mtx); |
1028 | for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { | 1113 | for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { |
1029 | if (strcmp(iwlwifi_opmode_table[i].name, name)) | 1114 | op = &iwlwifi_opmode_table[i]; |
1115 | if (strcmp(op->name, name)) | ||
1030 | continue; | 1116 | continue; |
1031 | iwlwifi_opmode_table[i].ops = ops; | 1117 | op->ops = ops; |
1032 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) | 1118 | /* TODO: need to handle exceptional case */ |
1033 | drv->op_mode = ops->start(drv->trans, drv->cfg, | 1119 | list_for_each_entry(drv, &op->drv, list) |
1034 | &drv->fw); | 1120 | drv->op_mode = _iwl_op_mode_start(drv, op); |
1121 | |||
1035 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1122 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1036 | return 0; | 1123 | return 0; |
1037 | } | 1124 | } |
@@ -1052,12 +1139,9 @@ void iwl_opmode_deregister(const char *name) | |||
1052 | iwlwifi_opmode_table[i].ops = NULL; | 1139 | iwlwifi_opmode_table[i].ops = NULL; |
1053 | 1140 | ||
1054 | /* call the stop routine for all devices */ | 1141 | /* call the stop routine for all devices */ |
1055 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { | 1142 | list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) |
1056 | if (drv->op_mode) { | 1143 | _iwl_op_mode_stop(drv); |
1057 | iwl_op_mode_stop(drv->op_mode); | 1144 | |
1058 | drv->op_mode = NULL; | ||
1059 | } | ||
1060 | } | ||
1061 | mutex_unlock(&iwlwifi_opmode_table_mtx); | 1145 | mutex_unlock(&iwlwifi_opmode_table_mtx); |
1062 | return; | 1146 | return; |
1063 | } | 1147 | } |
@@ -1077,6 +1161,14 @@ static int __init iwl_drv_init(void) | |||
1077 | pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); | 1161 | pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); |
1078 | pr_info(DRV_COPYRIGHT "\n"); | 1162 | pr_info(DRV_COPYRIGHT "\n"); |
1079 | 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 | |||
1080 | return iwl_pci_register_driver(); | 1172 | return iwl_pci_register_driver(); |
1081 | } | 1173 | } |
1082 | module_init(iwl_drv_init); | 1174 | module_init(iwl_drv_init); |
@@ -1084,6 +1176,10 @@ module_init(iwl_drv_init); | |||
1084 | static void __exit iwl_drv_exit(void) | 1176 | static void __exit iwl_drv_exit(void) |
1085 | { | 1177 | { |
1086 | iwl_pci_unregister_driver(); | 1178 | iwl_pci_unregister_driver(); |
1179 | |||
1180 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1181 | debugfs_remove_recursive(iwl_dbgfs_root); | ||
1182 | #endif | ||
1087 | } | 1183 | } |
1088 | module_exit(iwl_drv_exit); | 1184 | module_exit(iwl_drv_exit); |
1089 | 1185 | ||