diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-08-22 14:15:47 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-08-22 14:15:47 -0400 |
commit | 6de3f7e911d27d6737c79b3f6b5069044ea408ec (patch) | |
tree | 186dcf1897be76a4155f5a22a7f242c29f328c5a /drivers/net | |
parent | 33dd7699cefd175c3a5d3d6077db9c8d8322c9a7 (diff) | |
parent | 40503f7b48260a91ab65a4f8b00a2c6f004fa807 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/agn.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/debugfs.c | 56 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/main.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/sta.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/tx.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.c | 141 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-drv.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-op-mode.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/drv.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/internal.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/rx.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 26 |
15 files changed, 241 insertions, 93 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f0b8c1f7591c..75e12f29d9eb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -487,16 +487,13 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) | |||
487 | } | 487 | } |
488 | 488 | ||
489 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 489 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
490 | int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); | 490 | int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir); |
491 | void iwl_dbgfs_unregister(struct iwl_priv *priv); | ||
492 | #else | 491 | #else |
493 | static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | 492 | static inline int iwl_dbgfs_register(struct iwl_priv *priv, |
493 | struct dentry *dbgfs_dir) | ||
494 | { | 494 | { |
495 | return 0; | 495 | return 0; |
496 | } | 496 | } |
497 | static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) | ||
498 | { | ||
499 | } | ||
500 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 497 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
501 | 498 | ||
502 | #ifdef CONFIG_IWLWIFI_DEBUG | 499 | #ifdef CONFIG_IWLWIFI_DEBUG |
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 46782f1102ac..ce826bc5f111 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c | |||
@@ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); | |||
2349 | * Create the debugfs files and directories | 2349 | * Create the debugfs files and directories |
2350 | * | 2350 | * |
2351 | */ | 2351 | */ |
2352 | int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | 2352 | int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) |
2353 | { | 2353 | { |
2354 | struct dentry *phyd = priv->hw->wiphy->debugfsdir; | 2354 | struct dentry *dir_data, *dir_rf, *dir_debug; |
2355 | struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; | ||
2356 | 2355 | ||
2357 | dir_drv = debugfs_create_dir(name, phyd); | 2356 | priv->debugfs_dir = dbgfs_dir; |
2358 | if (!dir_drv) | ||
2359 | return -ENOMEM; | ||
2360 | |||
2361 | priv->debugfs_dir = dir_drv; | ||
2362 | 2357 | ||
2363 | dir_data = debugfs_create_dir("data", dir_drv); | 2358 | dir_data = debugfs_create_dir("data", dbgfs_dir); |
2364 | if (!dir_data) | 2359 | if (!dir_data) |
2365 | goto err; | 2360 | goto err; |
2366 | dir_rf = debugfs_create_dir("rf", dir_drv); | 2361 | dir_rf = debugfs_create_dir("rf", dbgfs_dir); |
2367 | if (!dir_rf) | 2362 | if (!dir_rf) |
2368 | goto err; | 2363 | goto err; |
2369 | dir_debug = debugfs_create_dir("debug", dir_drv); | 2364 | dir_debug = debugfs_create_dir("debug", dbgfs_dir); |
2370 | if (!dir_debug) | 2365 | if (!dir_debug) |
2371 | goto err; | 2366 | goto err; |
2372 | 2367 | ||
@@ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
2412 | /* Calibrations disabled/enabled status*/ | 2407 | /* Calibrations disabled/enabled status*/ |
2413 | DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); | 2408 | DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); |
2414 | 2409 | ||
2415 | if (iwl_trans_dbgfs_register(priv->trans, dir_debug)) | 2410 | /* |
2416 | goto err; | 2411 | * Create a symlink with mac80211. This is not very robust, as it does |
2412 | * not remove the symlink created. The implicit assumption is that | ||
2413 | * when the opmode exits, mac80211 will also exit, and will remove | ||
2414 | * this symlink as part of its cleanup. | ||
2415 | */ | ||
2416 | if (priv->mac80211_registered) { | ||
2417 | char buf[100]; | ||
2418 | struct dentry *mac80211_dir, *dev_dir, *root_dir; | ||
2419 | |||
2420 | dev_dir = dbgfs_dir->d_parent; | ||
2421 | root_dir = dev_dir->d_parent; | ||
2422 | mac80211_dir = priv->hw->wiphy->debugfsdir; | ||
2423 | |||
2424 | snprintf(buf, 100, "../../%s/%s", root_dir->d_name.name, | ||
2425 | dev_dir->d_name.name); | ||
2426 | |||
2427 | if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf)) | ||
2428 | goto err; | ||
2429 | } | ||
2430 | |||
2417 | return 0; | 2431 | return 0; |
2418 | 2432 | ||
2419 | err: | 2433 | err: |
2420 | IWL_ERR(priv, "Can't create the debugfs directory\n"); | 2434 | IWL_ERR(priv, "failed to create the dvm debugfs entries\n"); |
2421 | iwl_dbgfs_unregister(priv); | ||
2422 | return -ENOMEM; | 2435 | return -ENOMEM; |
2423 | } | 2436 | } |
2424 | |||
2425 | /** | ||
2426 | * Remove the debugfs files and directories | ||
2427 | * | ||
2428 | */ | ||
2429 | void iwl_dbgfs_unregister(struct iwl_priv *priv) | ||
2430 | { | ||
2431 | if (!priv->debugfs_dir) | ||
2432 | return; | ||
2433 | |||
2434 | debugfs_remove_recursive(priv->debugfs_dir); | ||
2435 | priv->debugfs_dir = NULL; | ||
2436 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index e64af60a37c1..ff8162d4c454 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, | |||
195 | ARRAY_SIZE(iwlagn_iface_combinations_dualmode); | 195 | ARRAY_SIZE(iwlagn_iface_combinations_dualmode); |
196 | } | 196 | } |
197 | 197 | ||
198 | hw->wiphy->max_remain_on_channel_duration = 1000; | 198 | hw->wiphy->max_remain_on_channel_duration = 500; |
199 | 199 | ||
200 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | | 200 | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | |
201 | WIPHY_FLAG_DISABLE_BEACON_HINTS | | 201 | WIPHY_FLAG_DISABLE_BEACON_HINTS | |
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 84d3db5aa506..7ff3f1430678 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -862,7 +862,8 @@ void iwl_down(struct iwl_priv *priv) | |||
862 | * No race since we hold the mutex here and a new one | 862 | * No race since we hold the mutex here and a new one |
863 | * can't come in at this time. | 863 | * can't come in at this time. |
864 | */ | 864 | */ |
865 | ieee80211_remain_on_channel_expired(priv->hw); | 865 | if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT) |
866 | ieee80211_remain_on_channel_expired(priv->hw); | ||
866 | 867 | ||
867 | exit_pending = | 868 | exit_pending = |
868 | test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); | 869 | test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); |
@@ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data) | |||
994 | iwlagn_prepare_restart(priv); | 995 | iwlagn_prepare_restart(priv); |
995 | mutex_unlock(&priv->mutex); | 996 | mutex_unlock(&priv->mutex); |
996 | iwl_cancel_deferred_work(priv); | 997 | iwl_cancel_deferred_work(priv); |
997 | ieee80211_restart_hw(priv->hw); | 998 | if (priv->mac80211_registered) |
999 | ieee80211_restart_hw(priv->hw); | ||
1000 | else | ||
1001 | IWL_ERR(priv, | ||
1002 | "Cannot request restart before registrating with mac80211"); | ||
998 | } else { | 1003 | } else { |
999 | WARN_ON(1); | 1004 | WARN_ON(1); |
1000 | } | 1005 | } |
@@ -1222,7 +1227,8 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) | |||
1222 | 1227 | ||
1223 | static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | 1228 | static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, |
1224 | const struct iwl_cfg *cfg, | 1229 | const struct iwl_cfg *cfg, |
1225 | const struct iwl_fw *fw) | 1230 | const struct iwl_fw *fw, |
1231 | struct dentry *dbgfs_dir) | ||
1226 | { | 1232 | { |
1227 | struct iwl_priv *priv; | 1233 | struct iwl_priv *priv; |
1228 | struct ieee80211_hw *hw; | 1234 | struct ieee80211_hw *hw; |
@@ -1466,13 +1472,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1466 | if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) | 1472 | if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) |
1467 | goto out_destroy_workqueue; | 1473 | goto out_destroy_workqueue; |
1468 | 1474 | ||
1469 | if (iwl_dbgfs_register(priv, DRV_NAME)) | 1475 | if (iwl_dbgfs_register(priv, dbgfs_dir)) |
1470 | IWL_ERR(priv, | 1476 | goto out_mac80211_unregister; |
1471 | "failed to create debugfs files. Ignoring error\n"); | ||
1472 | 1477 | ||
1473 | return op_mode; | 1478 | return op_mode; |
1474 | 1479 | ||
1480 | out_mac80211_unregister: | ||
1481 | iwlagn_mac_unregister(priv); | ||
1475 | out_destroy_workqueue: | 1482 | out_destroy_workqueue: |
1483 | iwl_tt_exit(priv); | ||
1484 | iwl_testmode_free(priv); | ||
1485 | iwl_cancel_deferred_work(priv); | ||
1476 | destroy_workqueue(priv->workqueue); | 1486 | destroy_workqueue(priv->workqueue); |
1477 | priv->workqueue = NULL; | 1487 | priv->workqueue = NULL; |
1478 | iwl_uninit_drv(priv); | 1488 | iwl_uninit_drv(priv); |
@@ -1493,8 +1503,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) | |||
1493 | 1503 | ||
1494 | IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); | 1504 | IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); |
1495 | 1505 | ||
1496 | iwl_dbgfs_unregister(priv); | ||
1497 | |||
1498 | iwl_testmode_free(priv); | 1506 | iwl_testmode_free(priv); |
1499 | iwlagn_mac_unregister(priv); | 1507 | iwlagn_mac_unregister(priv); |
1500 | 1508 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index b29b798f7550..fe36a38f3505 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -150,7 +150,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
150 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); | 150 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); |
151 | 151 | ||
152 | if (!(flags & CMD_ASYNC)) { | 152 | if (!(flags & CMD_ASYNC)) { |
153 | cmd.flags |= CMD_WANT_SKB; | 153 | cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD; |
154 | might_sleep(); | 154 | might_sleep(); |
155 | } | 155 | } |
156 | 156 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index d17799b316d7..f5ca73a89870 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -433,7 +433,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, | |||
433 | * only. Check this here. | 433 | * only. Check this here. |
434 | */ | 434 | */ |
435 | if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON && | 435 | if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON && |
436 | tid_data->agg.state != IWL_AGG_OFF, | 436 | tid_data->agg.state != IWL_AGG_OFF, |
437 | "Tx while agg.state = %d", tid_data->agg.state)) | 437 | "Tx while agg.state = %d", tid_data->agg.state)) |
438 | goto drop_unlock_sta; | 438 | goto drop_unlock_sta; |
439 | 439 | ||
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 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 2cbf137b25bf..285de5f68c05 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h | |||
@@ -90,9 +90,9 @@ | |||
90 | * 4) The bus specific component configures the bus | 90 | * 4) The bus specific component configures the bus |
91 | * 5) The bus specific component calls to the drv bus agnostic part | 91 | * 5) The bus specific component calls to the drv bus agnostic part |
92 | * (iwl_drv_start) | 92 | * (iwl_drv_start) |
93 | * 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback | 93 | * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback |
94 | * 7) iwl_ucode_callback parses the fw file | 94 | * 7) iwl_req_fw_callback parses the fw file |
95 | * 8) iwl_ucode_callback starts the wifi implementation to matches the fw | 95 | * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw |
96 | */ | 96 | */ |
97 | 97 | ||
98 | struct iwl_drv; | 98 | struct iwl_drv; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 64886f95664f..c8d9b9517468 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -134,7 +134,8 @@ struct iwl_cfg; | |||
134 | struct iwl_op_mode_ops { | 134 | struct iwl_op_mode_ops { |
135 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 135 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, |
136 | const struct iwl_cfg *cfg, | 136 | const struct iwl_cfg *cfg, |
137 | const struct iwl_fw *fw); | 137 | const struct iwl_fw *fw, |
138 | struct dentry *dbgfs_dir); | ||
138 | void (*stop)(struct iwl_op_mode *op_mode); | 139 | void (*stop)(struct iwl_op_mode *op_mode); |
139 | int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, | 140 | int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, |
140 | struct iwl_device_cmd *cmd); | 141 | struct iwl_device_cmd *cmd); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 92576a3e84ef..ff1154232885 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -184,14 +184,20 @@ struct iwl_rx_packet { | |||
184 | * @CMD_SYNC: The caller will be stalled until the fw responds to the command | 184 | * @CMD_SYNC: The caller will be stalled until the fw responds to the command |
185 | * @CMD_ASYNC: Return right away and don't want for the response | 185 | * @CMD_ASYNC: Return right away and don't want for the response |
186 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the | 186 | * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the |
187 | * response. | 187 | * response. The caller needs to call iwl_free_resp when done. |
188 | * @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the | ||
189 | * response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be | ||
190 | * copied. The pointer passed to the response handler is in the transport | ||
191 | * ownership and don't need to be freed by the op_mode. This also means | ||
192 | * that the pointer is invalidated after the op_mode's handler returns. | ||
188 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. | 193 | * @CMD_ON_DEMAND: This command is sent by the test mode pipe. |
189 | */ | 194 | */ |
190 | enum CMD_MODE { | 195 | enum CMD_MODE { |
191 | CMD_SYNC = 0, | 196 | CMD_SYNC = 0, |
192 | CMD_ASYNC = BIT(0), | 197 | CMD_ASYNC = BIT(0), |
193 | CMD_WANT_SKB = BIT(1), | 198 | CMD_WANT_SKB = BIT(1), |
194 | CMD_ON_DEMAND = BIT(2), | 199 | CMD_WANT_HCMD = BIT(2), |
200 | CMD_ON_DEMAND = BIT(3), | ||
195 | }; | 201 | }; |
196 | 202 | ||
197 | #define DEF_CMD_PAYLOAD_SIZE 320 | 203 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -460,6 +466,8 @@ struct iwl_trans { | |||
460 | size_t dev_cmd_headroom; | 466 | size_t dev_cmd_headroom; |
461 | char dev_cmd_pool_name[50]; | 467 | char dev_cmd_pool_name[50]; |
462 | 468 | ||
469 | struct dentry *dbgfs_dir; | ||
470 | |||
463 | /* pointer to trans specific struct */ | 471 | /* pointer to trans specific struct */ |
464 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 472 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
465 | char trans_specific[0] __aligned(sizeof(void *)); | 473 | char trans_specific[0] __aligned(sizeof(void *)); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index f4c3500b68c6..89bfb43f4946 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -282,8 +282,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
282 | if (!trans_pcie->drv) | 282 | if (!trans_pcie->drv) |
283 | goto out_free_trans; | 283 | goto out_free_trans; |
284 | 284 | ||
285 | /* register transport layer debugfs here */ | ||
286 | if (iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir)) | ||
287 | goto out_free_drv; | ||
288 | |||
285 | return 0; | 289 | return 0; |
286 | 290 | ||
291 | out_free_drv: | ||
292 | iwl_drv_stop(trans_pcie->drv); | ||
287 | out_free_trans: | 293 | out_free_trans: |
288 | iwl_trans_pcie_free(iwl_trans); | 294 | iwl_trans_pcie_free(iwl_trans); |
289 | pci_set_drvdata(pdev, NULL); | 295 | pci_set_drvdata(pdev, NULL); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index d9694c58208c..3ef8d5adc991 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -184,6 +184,7 @@ struct iwl_queue { | |||
184 | 184 | ||
185 | struct iwl_pcie_tx_queue_entry { | 185 | struct iwl_pcie_tx_queue_entry { |
186 | struct iwl_device_cmd *cmd; | 186 | struct iwl_device_cmd *cmd; |
187 | struct iwl_device_cmd *copy_cmd; | ||
187 | struct sk_buff *skb; | 188 | struct sk_buff *skb; |
188 | struct iwl_cmd_meta meta; | 189 | struct iwl_cmd_meta meta; |
189 | }; | 190 | }; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 39a6ca1f009c..d80604a2bb1a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, | |||
421 | index = SEQ_TO_INDEX(sequence); | 421 | index = SEQ_TO_INDEX(sequence); |
422 | cmd_index = get_cmd_index(&txq->q, index); | 422 | cmd_index = get_cmd_index(&txq->q, index); |
423 | 423 | ||
424 | if (reclaim) | 424 | if (reclaim) { |
425 | cmd = txq->entries[cmd_index].cmd; | 425 | struct iwl_pcie_tx_queue_entry *ent; |
426 | else | 426 | ent = &txq->entries[cmd_index]; |
427 | cmd = ent->copy_cmd; | ||
428 | WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD); | ||
429 | } else { | ||
427 | cmd = NULL; | 430 | cmd = NULL; |
431 | } | ||
428 | 432 | ||
429 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); | 433 | err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); |
430 | 434 | ||
435 | if (reclaim) { | ||
436 | /* The original command isn't needed any more */ | ||
437 | kfree(txq->entries[cmd_index].copy_cmd); | ||
438 | txq->entries[cmd_index].copy_cmd = NULL; | ||
439 | } | ||
440 | |||
431 | /* | 441 | /* |
432 | * After here, we should always check rxcb._page_stolen, | 442 | * After here, we should always check rxcb._page_stolen, |
433 | * if it is true then one of the handlers took the page. | 443 | * if it is true then one of the handlers took the page. |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 939c2f78df58..38f51b04217e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -492,10 +492,11 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) | |||
492 | iwl_tx_queue_unmap(trans, txq_id); | 492 | iwl_tx_queue_unmap(trans, txq_id); |
493 | 493 | ||
494 | /* De-alloc array of command/tx buffers */ | 494 | /* De-alloc array of command/tx buffers */ |
495 | |||
496 | if (txq_id == trans_pcie->cmd_queue) | 495 | if (txq_id == trans_pcie->cmd_queue) |
497 | for (i = 0; i < txq->q.n_window; i++) | 496 | for (i = 0; i < txq->q.n_window; i++) { |
498 | kfree(txq->entries[i].cmd); | 497 | kfree(txq->entries[i].cmd); |
498 | kfree(txq->entries[i].copy_cmd); | ||
499 | } | ||
499 | 500 | ||
500 | /* De-alloc circular buffer of TFDs */ | 501 | /* De-alloc circular buffer of TFDs */ |
501 | if (txq->q.n_bd) { | 502 | if (txq->q.n_bd) { |
@@ -896,6 +897,7 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) | |||
896 | static int iwl_prepare_card_hw(struct iwl_trans *trans) | 897 | static int iwl_prepare_card_hw(struct iwl_trans *trans) |
897 | { | 898 | { |
898 | int ret; | 899 | int ret; |
900 | int t = 0; | ||
899 | 901 | ||
900 | IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); | 902 | IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); |
901 | 903 | ||
@@ -908,17 +910,15 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) | |||
908 | iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, | 910 | iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, |
909 | CSR_HW_IF_CONFIG_REG_PREPARE); | 911 | CSR_HW_IF_CONFIG_REG_PREPARE); |
910 | 912 | ||
911 | ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, | 913 | do { |
912 | ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, | 914 | ret = iwl_set_hw_ready(trans); |
913 | CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); | 915 | if (ret >= 0) |
916 | return 0; | ||
914 | 917 | ||
915 | if (ret < 0) | 918 | usleep_range(200, 1000); |
916 | return ret; | 919 | t += 200; |
920 | } while (t < 150000); | ||
917 | 921 | ||
918 | /* HW should be ready by now, check again. */ | ||
919 | ret = iwl_set_hw_ready(trans); | ||
920 | if (ret >= 0) | ||
921 | return 0; | ||
922 | return ret; | 922 | return ret; |
923 | } | 923 | } |
924 | 924 | ||
@@ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans) | |||
1769 | #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ | 1769 | #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ |
1770 | if (!debugfs_create_file(#name, mode, parent, trans, \ | 1770 | if (!debugfs_create_file(#name, mode, parent, trans, \ |
1771 | &iwl_dbgfs_##name##_ops)) \ | 1771 | &iwl_dbgfs_##name##_ops)) \ |
1772 | return -ENOMEM; \ | 1772 | goto err; \ |
1773 | } while (0) | 1773 | } while (0) |
1774 | 1774 | ||
1775 | /* file operation */ | 1775 | /* file operation */ |
@@ -2033,6 +2033,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | |||
2033 | DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); | 2033 | DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); |
2034 | DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); | 2034 | DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); |
2035 | return 0; | 2035 | return 0; |
2036 | |||
2037 | err: | ||
2038 | IWL_ERR(trans, "failed to create the trans debugfs entry\n"); | ||
2039 | return -ENOMEM; | ||
2036 | } | 2040 | } |
2037 | #else | 2041 | #else |
2038 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, | 2042 | static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 6baf8deef519..392d2bc5e357 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -521,7 +521,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | |||
521 | u16 copy_size, cmd_size; | 521 | u16 copy_size, cmd_size; |
522 | bool had_nocopy = false; | 522 | bool had_nocopy = false; |
523 | int i; | 523 | int i; |
524 | u8 *cmd_dest; | 524 | u32 cmd_pos; |
525 | #ifdef CONFIG_IWLWIFI_DEVICE_TRACING | 525 | #ifdef CONFIG_IWLWIFI_DEVICE_TRACING |
526 | const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; | 526 | const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; |
527 | int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; | 527 | int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; |
@@ -584,15 +584,31 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | |||
584 | INDEX_TO_SEQ(q->write_ptr)); | 584 | INDEX_TO_SEQ(q->write_ptr)); |
585 | 585 | ||
586 | /* and copy the data that needs to be copied */ | 586 | /* and copy the data that needs to be copied */ |
587 | 587 | cmd_pos = offsetof(struct iwl_device_cmd, payload); | |
588 | cmd_dest = out_cmd->payload; | ||
589 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { | 588 | for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { |
590 | if (!cmd->len[i]) | 589 | if (!cmd->len[i]) |
591 | continue; | 590 | continue; |
592 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) | 591 | if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) |
593 | break; | 592 | break; |
594 | memcpy(cmd_dest, cmd->data[i], cmd->len[i]); | 593 | memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]); |
595 | cmd_dest += cmd->len[i]; | 594 | cmd_pos += cmd->len[i]; |
595 | } | ||
596 | |||
597 | WARN_ON_ONCE(txq->entries[idx].copy_cmd); | ||
598 | |||
599 | /* | ||
600 | * since out_cmd will be the source address of the FH, it will write | ||
601 | * the retry count there. So when the user needs to receivce the HCMD | ||
602 | * that corresponds to the response in the response handler, it needs | ||
603 | * to set CMD_WANT_HCMD. | ||
604 | */ | ||
605 | if (cmd->flags & CMD_WANT_HCMD) { | ||
606 | txq->entries[idx].copy_cmd = | ||
607 | kmemdup(out_cmd, cmd_pos, GFP_ATOMIC); | ||
608 | if (unlikely(!txq->entries[idx].copy_cmd)) { | ||
609 | idx = -ENOMEM; | ||
610 | goto out; | ||
611 | } | ||
596 | } | 612 | } |
597 | 613 | ||
598 | IWL_DEBUG_HC(trans, | 614 | IWL_DEBUG_HC(trans, |