Commit 6de3f7e9 authored by John W. Linville's avatar John W. Linville
parents 33dd7699 40503f7b
...@@ -487,16 +487,13 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) ...@@ -487,16 +487,13 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir);
void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else #else
static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) static inline int iwl_dbgfs_register(struct iwl_priv *priv,
struct dentry *dbgfs_dir)
{ {
return 0; return 0;
} }
static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
{
}
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
......
...@@ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); ...@@ -2349,24 +2349,19 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
* Create the debugfs files and directories * Create the debugfs files and directories
* *
*/ */
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
{ {
struct dentry *phyd = priv->hw->wiphy->debugfsdir; struct dentry *dir_data, *dir_rf, *dir_debug;
struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
dir_drv = debugfs_create_dir(name, phyd); priv->debugfs_dir = dbgfs_dir;
if (!dir_drv)
return -ENOMEM;
priv->debugfs_dir = dir_drv;
dir_data = debugfs_create_dir("data", dir_drv); dir_data = debugfs_create_dir("data", dbgfs_dir);
if (!dir_data) if (!dir_data)
goto err; goto err;
dir_rf = debugfs_create_dir("rf", dir_drv); dir_rf = debugfs_create_dir("rf", dbgfs_dir);
if (!dir_rf) if (!dir_rf)
goto err; goto err;
dir_debug = debugfs_create_dir("debug", dir_drv); dir_debug = debugfs_create_dir("debug", dbgfs_dir);
if (!dir_debug) if (!dir_debug)
goto err; goto err;
...@@ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) ...@@ -2412,25 +2407,30 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
/* Calibrations disabled/enabled status*/ /* Calibrations disabled/enabled status*/
DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
if (iwl_trans_dbgfs_register(priv->trans, dir_debug)) /*
* Create a symlink with mac80211. This is not very robust, as it does
* not remove the symlink created. The implicit assumption is that
* when the opmode exits, mac80211 will also exit, and will remove
* this symlink as part of its cleanup.
*/
if (priv->mac80211_registered) {
char buf[100];
struct dentry *mac80211_dir, *dev_dir, *root_dir;
dev_dir = dbgfs_dir->d_parent;
root_dir = dev_dir->d_parent;
mac80211_dir = priv->hw->wiphy->debugfsdir;
snprintf(buf, 100, "../../%s/%s", root_dir->d_name.name,
dev_dir->d_name.name);
if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf))
goto err; goto err;
}
return 0; return 0;
err: err:
IWL_ERR(priv, "Can't create the debugfs directory\n"); IWL_ERR(priv, "failed to create the dvm debugfs entries\n");
iwl_dbgfs_unregister(priv);
return -ENOMEM; return -ENOMEM;
} }
/**
* Remove the debugfs files and directories
*
*/
void iwl_dbgfs_unregister(struct iwl_priv *priv)
{
if (!priv->debugfs_dir)
return;
debugfs_remove_recursive(priv->debugfs_dir);
priv->debugfs_dir = NULL;
}
...@@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, ...@@ -195,7 +195,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ARRAY_SIZE(iwlagn_iface_combinations_dualmode); ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
} }
hw->wiphy->max_remain_on_channel_duration = 1000; hw->wiphy->max_remain_on_channel_duration = 500;
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_DISABLE_BEACON_HINTS |
......
...@@ -862,6 +862,7 @@ void iwl_down(struct iwl_priv *priv) ...@@ -862,6 +862,7 @@ void iwl_down(struct iwl_priv *priv)
* No race since we hold the mutex here and a new one * No race since we hold the mutex here and a new one
* can't come in at this time. * can't come in at this time.
*/ */
if (priv->ucode_loaded && priv->cur_ucode != IWL_UCODE_INIT)
ieee80211_remain_on_channel_expired(priv->hw); ieee80211_remain_on_channel_expired(priv->hw);
exit_pending = exit_pending =
...@@ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data) ...@@ -994,7 +995,11 @@ static void iwl_bg_restart(struct work_struct *data)
iwlagn_prepare_restart(priv); iwlagn_prepare_restart(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
iwl_cancel_deferred_work(priv); iwl_cancel_deferred_work(priv);
if (priv->mac80211_registered)
ieee80211_restart_hw(priv->hw); ieee80211_restart_hw(priv->hw);
else
IWL_ERR(priv,
"Cannot request restart before registrating with mac80211");
} else { } else {
WARN_ON(1); WARN_ON(1);
} }
...@@ -1222,7 +1227,8 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) ...@@ -1222,7 +1227,8 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
const struct iwl_cfg *cfg, const struct iwl_cfg *cfg,
const struct iwl_fw *fw) const struct iwl_fw *fw,
struct dentry *dbgfs_dir)
{ {
struct iwl_priv *priv; struct iwl_priv *priv;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
...@@ -1466,13 +1472,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ...@@ -1466,13 +1472,17 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
goto out_destroy_workqueue; goto out_destroy_workqueue;
if (iwl_dbgfs_register(priv, DRV_NAME)) if (iwl_dbgfs_register(priv, dbgfs_dir))
IWL_ERR(priv, goto out_mac80211_unregister;
"failed to create debugfs files. Ignoring error\n");
return op_mode; return op_mode;
out_mac80211_unregister:
iwlagn_mac_unregister(priv);
out_destroy_workqueue: out_destroy_workqueue:
iwl_tt_exit(priv);
iwl_testmode_free(priv);
iwl_cancel_deferred_work(priv);
destroy_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue);
priv->workqueue = NULL; priv->workqueue = NULL;
iwl_uninit_drv(priv); iwl_uninit_drv(priv);
...@@ -1493,8 +1503,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) ...@@ -1493,8 +1503,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
iwl_dbgfs_unregister(priv);
iwl_testmode_free(priv); iwl_testmode_free(priv);
iwlagn_mac_unregister(priv); iwlagn_mac_unregister(priv);
......
...@@ -150,7 +150,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, ...@@ -150,7 +150,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
if (!(flags & CMD_ASYNC)) { if (!(flags & CMD_ASYNC)) {
cmd.flags |= CMD_WANT_SKB; cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD;
might_sleep(); might_sleep();
} }
......
...@@ -101,6 +101,10 @@ MODULE_VERSION(DRV_VERSION); ...@@ -101,6 +101,10 @@ MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_IWLWIFI_DEBUGFS
static struct dentry *iwl_dbgfs_root;
#endif
/** /**
* struct iwl_drv - drv common data * struct iwl_drv - drv common data
* @list: list of drv structures using this opmode * @list: list of drv structures using this opmode
...@@ -126,6 +130,12 @@ struct iwl_drv { ...@@ -126,6 +130,12 @@ struct iwl_drv {
char firmware_name[25]; /* name of firmware file to load */ char firmware_name[25]; /* name of firmware file to load */
struct completion request_firmware_complete; struct completion request_firmware_complete;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *dbgfs_drv;
struct dentry *dbgfs_trans;
struct dentry *dbgfs_op_mode;
#endif
}; };
#define DVM_OP_MODE 0 #define DVM_OP_MODE 0
...@@ -194,7 +204,8 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, ...@@ -194,7 +204,8 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc,
return 0; return 0;
} }
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); static void iwl_req_fw_callback(const struct firmware *ucode_raw,
void *context);
#define UCODE_EXPERIMENTAL_INDEX 100 #define UCODE_EXPERIMENTAL_INDEX 100
#define UCODE_EXPERIMENTAL_TAG "exp" #define UCODE_EXPERIMENTAL_TAG "exp"
...@@ -231,7 +242,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) ...@@ -231,7 +242,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name,
drv->trans->dev, drv->trans->dev,
GFP_KERNEL, drv, iwl_ucode_callback); GFP_KERNEL, drv, iwl_req_fw_callback);
} }
struct fw_img_parsing { struct fw_img_parsing {
...@@ -759,13 +770,57 @@ static int validate_sec_sizes(struct iwl_drv *drv, ...@@ -759,13 +770,57 @@ static int validate_sec_sizes(struct iwl_drv *drv,
return 0; return 0;
} }
static struct iwl_op_mode *
_iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
{
const struct iwl_op_mode_ops *ops = op->ops;
struct dentry *dbgfs_dir = NULL;
struct iwl_op_mode *op_mode = NULL;
#ifdef CONFIG_IWLWIFI_DEBUGFS
drv->dbgfs_op_mode = debugfs_create_dir(op->name,
drv->dbgfs_drv);
if (!drv->dbgfs_op_mode) {
IWL_ERR(drv,
"failed to create opmode debugfs directory\n");
return op_mode;
}
dbgfs_dir = drv->dbgfs_op_mode;
#endif
op_mode = ops->start(drv->trans, drv->cfg, &drv->fw, dbgfs_dir);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (!op_mode) {
debugfs_remove_recursive(drv->dbgfs_op_mode);
drv->dbgfs_op_mode = NULL;
}
#endif
return op_mode;
}
static void _iwl_op_mode_stop(struct iwl_drv *drv)
{
/* op_mode can be NULL if its start failed */
if (drv->op_mode) {
iwl_op_mode_stop(drv->op_mode);
drv->op_mode = NULL;
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(drv->dbgfs_op_mode);
drv->dbgfs_op_mode = NULL;
#endif
}
}
/** /**
* iwl_ucode_callback - callback when firmware was loaded * iwl_req_fw_callback - callback when firmware was loaded
* *
* If loaded successfully, copies the firmware into buffers * If loaded successfully, copies the firmware into buffers
* for the card to fetch (via DMA). * for the card to fetch (via DMA).
*/ */
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
{ {
struct iwl_drv *drv = context; struct iwl_drv *drv = context;
struct iwl_fw *fw = &drv->fw; struct iwl_fw *fw = &drv->fw;
...@@ -908,8 +963,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) ...@@ -908,8 +963,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
list_add_tail(&drv->list, &op->drv); list_add_tail(&drv->list, &op->drv);
if (op->ops) { if (op->ops) {
const struct iwl_op_mode_ops *ops = op->ops; drv->op_mode = _iwl_op_mode_start(drv, op);
drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
if (!drv->op_mode) { if (!drv->op_mode) {
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
...@@ -969,13 +1023,42 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, ...@@ -969,13 +1023,42 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
init_completion(&drv->request_firmware_complete); init_completion(&drv->request_firmware_complete);
INIT_LIST_HEAD(&drv->list); INIT_LIST_HEAD(&drv->list);
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the device debugfs entries. */
drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev),
iwl_dbgfs_root);
if (!drv->dbgfs_drv) {
IWL_ERR(drv, "failed to create debugfs directory\n");
goto err_free_drv;
}
/* Create transport layer debugfs dir */
drv->trans->dbgfs_dir = debugfs_create_dir("trans", drv->dbgfs_drv);
if (!drv->trans->dbgfs_dir) {
IWL_ERR(drv, "failed to create transport debugfs directory\n");
goto err_free_dbgfs;
}
#endif
ret = iwl_request_firmware(drv, true); ret = iwl_request_firmware(drv, true);
if (ret) { if (ret) {
IWL_ERR(trans, "Couldn't request the fw\n"); IWL_ERR(trans, "Couldn't request the fw\n");
goto err_fw;
}
return drv;
err_fw:
#ifdef CONFIG_IWLWIFI_DEBUGFS
err_free_dbgfs:
debugfs_remove_recursive(drv->dbgfs_drv);
err_free_drv:
#endif
kfree(drv); kfree(drv);
drv = NULL; drv = NULL;
}
return drv; return drv;
} }
...@@ -984,9 +1067,7 @@ void iwl_drv_stop(struct iwl_drv *drv) ...@@ -984,9 +1067,7 @@ void iwl_drv_stop(struct iwl_drv *drv)
{ {
wait_for_completion(&drv->request_firmware_complete); wait_for_completion(&drv->request_firmware_complete);
/* op_mode can be NULL if its start failed */ _iwl_op_mode_stop(drv);
if (drv->op_mode)
iwl_op_mode_stop(drv->op_mode);
iwl_dealloc_ucode(drv); iwl_dealloc_ucode(drv);
...@@ -1000,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv) ...@@ -1000,6 +1081,10 @@ void iwl_drv_stop(struct iwl_drv *drv)
list_del(&drv->list); list_del(&drv->list);
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(drv->dbgfs_drv);
#endif
kfree(drv); kfree(drv);
} }
...@@ -1022,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops) ...@@ -1022,15 +1107,18 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
{ {
int i; int i;
struct iwl_drv *drv; struct iwl_drv *drv;
struct iwlwifi_opmode_table *op;
mutex_lock(&iwlwifi_opmode_table_mtx); mutex_lock(&iwlwifi_opmode_table_mtx);
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) { for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
if (strcmp(iwlwifi_opmode_table[i].name, name)) op = &iwlwifi_opmode_table[i];
if (strcmp(op->name, name))
continue; continue;
iwlwifi_opmode_table[i].ops = ops; op->ops = ops;
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) /* TODO: need to handle exceptional case */
drv->op_mode = ops->start(drv->trans, drv->cfg, list_for_each_entry(drv, &op->drv, list)
&drv->fw); drv->op_mode = _iwl_op_mode_start(drv, op);
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
return 0; return 0;
} }
...@@ -1051,12 +1139,9 @@ void iwl_opmode_deregister(const char *name) ...@@ -1051,12 +1139,9 @@ void iwl_opmode_deregister(const char *name)
iwlwifi_opmode_table[i].ops = NULL; iwlwifi_opmode_table[i].ops = NULL;
/* call the stop routine for all devices */ /* call the stop routine for all devices */
list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) { list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
if (drv->op_mode) { _iwl_op_mode_stop(drv);
iwl_op_mode_stop(drv->op_mode);
drv->op_mode = NULL;
}
}
mutex_unlock(&iwlwifi_opmode_table_mtx); mutex_unlock(&iwlwifi_opmode_table_mtx);
return; return;
} }
...@@ -1076,6 +1161,14 @@ static int __init iwl_drv_init(void) ...@@ -1076,6 +1161,14 @@ static int __init iwl_drv_init(void)
pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
pr_info(DRV_COPYRIGHT "\n"); pr_info(DRV_COPYRIGHT "\n");
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the root of iwlwifi debugfs subsystem. */
iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL);
if (!iwl_dbgfs_root)
return -EFAULT;
#endif
return iwl_pci_register_driver(); return iwl_pci_register_driver();
} }
module_init(iwl_drv_init); module_init(iwl_drv_init);
...@@ -1083,6 +1176,10 @@ module_init(iwl_drv_init); ...@@ -1083,6 +1176,10 @@ module_init(iwl_drv_init);
static void __exit iwl_drv_exit(void) static void __exit iwl_drv_exit(void)
{ {
iwl_pci_unregister_driver(); iwl_pci_unregister_driver();
#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(iwl_dbgfs_root);
#endif
} }
module_exit(iwl_drv_exit); module_exit(iwl_drv_exit);
......
...@@ -90,9 +90,9 @@ ...@@ -90,9 +90,9 @@
* 4) The bus specific component configures the bus * 4) The bus specific component configures the bus
* 5) The bus specific component calls to the drv bus agnostic part * 5) The bus specific component calls to the drv bus agnostic part
* (iwl_drv_start) * (iwl_drv_start)
* 6) iwl_drv_start fetches the fw ASYNC, iwl_ucode_callback * 6) iwl_drv_start fetches the fw ASYNC, iwl_req_fw_callback
* 7) iwl_ucode_callback parses the fw file * 7) iwl_req_fw_callback parses the fw file
* 8) iwl_ucode_callback starts the wifi implementation to matches the fw * 8) iwl_req_fw_callback starts the wifi implementation to matches the fw
*/ */
struct iwl_drv; struct iwl_drv;
......
...@@ -134,7 +134,8 @@ struct iwl_cfg; ...@@ -134,7 +134,8 @@ struct iwl_cfg;
struct iwl_op_mode_ops { struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans, struct iwl_op_mode *(*start)(struct iwl_trans *trans,
const struct iwl_cfg *cfg, const struct iwl_cfg *cfg,
const struct iwl_fw *fw); const struct iwl_fw *fw,
struct dentry *dbgfs_dir);
void (*stop)(struct iwl_op_mode *op_mode); void (*stop)(struct iwl_op_mode *op_mode);
int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);
......
...@@ -184,14 +184,20 @@ struct iwl_rx_packet { ...@@ -184,14 +184,20 @@ struct iwl_rx_packet {
* @CMD_SYNC: The caller will be stalled until the fw responds to the command * @CMD_SYNC: The caller will be stalled until the fw responds to the command
* @CMD_ASYNC: Return right away and don't want for the response * @CMD_ASYNC: Return right away and don't want for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the * @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
* response. * response. The caller needs to call iwl_free_resp when done.
* @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the
* response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be
* copied. The pointer passed to the response handler is in the transport
* ownership and don't need to be freed by the op_mode. This also means
* that the pointer is invalidated after the op_mode's handler returns.
* @CMD_ON_DEMAND: This command is sent by the test mode pipe. * @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/ */
enum CMD_MODE { enum CMD_MODE {
CMD_SYNC = 0, CMD_SYNC = 0,
CMD_ASYNC = BIT(0), CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1), CMD_WANT_SKB = BIT(1),
CMD_ON_DEMAND = BIT(2), CMD_WANT_HCMD = BIT(2),
CMD_ON_DEMAND = BIT(3),
}; };
#define DEF_CMD_PAYLOAD_SIZE 320 #define DEF_CMD_PAYLOAD_SIZE 320
...@@ -460,6 +466,8 @@ struct iwl_trans { ...@@ -460,6 +466,8 @@ struct iwl_trans {
size_t dev_cmd_headroom; size_t dev_cmd_headroom;
char dev_cmd_pool_name[50]; char dev_cmd_pool_name[50];
struct dentry *dbgfs_dir;
/* pointer to trans specific struct */ /* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */ /*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *)); char trans_specific[0] __aligned(sizeof(void *));
......
...@@ -282,8 +282,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -282,8 +282,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!trans_pcie->drv) if (!trans_pcie->drv)
goto out_free_trans; goto out_free_trans;
/* register transport layer debugfs here */
if (iwl_trans_dbgfs_register(iwl_trans, iwl_trans->dbgfs_dir))
goto out_free_drv;
return 0; return 0;
out_free_drv:
iwl_drv_stop(trans_pcie->drv);
out_free_trans: out_free_trans:
iwl_trans_pcie_free(iwl_trans); iwl_trans_pcie_free(iwl_trans);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
......
...@@ -184,6 +184,7 @@ struct iwl_queue { ...@@ -184,6 +184,7 @@ struct iwl_queue {
struct iwl_pcie_tx_queue_entry { struct iwl_pcie_tx_queue_entry {
struct iwl_device_cmd *cmd; struct iwl_device_cmd *cmd;
struct iwl_device_cmd *copy_cmd;
struct sk_buff *skb; struct sk_buff *skb;
struct iwl_cmd_meta meta; struct iwl_cmd_meta meta;
}; };
......
...@@ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, ...@@ -421,13 +421,23 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
index = SEQ_TO_INDEX(sequence); index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index); cmd_index = get_cmd_index(&txq->q, index);
if (reclaim) if (reclaim) {
cmd = txq->entries[cmd_index].cmd; struct iwl_pcie_tx_queue_entry *ent;
else ent = &txq->entries[cmd_index];
cmd = ent->copy_cmd;
WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD);
} else {
cmd = NULL; cmd = NULL;
}
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
if (reclaim) {
/* The original command isn't needed any more */
kfree(txq->entries[cmd_index].copy_cmd);
txq->entries[cmd_index].copy_cmd = NULL;
}
/* /*
* After here, we should always check rxcb._page_stolen, * After here, we should always check rxcb._page_stolen,
* if it is true then one of the handlers took the page. * if it is true then one of the handlers took the page.
......
...@@ -492,10 +492,11 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) ...@@ -492,10 +492,11 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
iwl_tx_queue_unmap(trans, txq_id); iwl_tx_queue_unmap(trans, txq_id);
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
if (txq_id == trans_pcie->cmd_queue) if (txq_id == trans_pcie->cmd_queue)
for (i = 0; i < txq->q.n_window; i++) for (i = 0; i < txq->q.n_window; i++) {
kfree(txq->entries[i].cmd); kfree(txq->entries[i].cmd);
kfree(txq->entries[i].copy_cmd);
}
/* De-alloc circular buffer of TFDs */ /* De-alloc circular buffer of TFDs */
if (txq->q.n_bd) { if (txq->q.n_bd) {
...@@ -896,6 +897,7 @@ static int iwl_set_hw_ready(struct iwl_trans *trans) ...@@ -896,6 +897,7 @@ static int iwl_set_hw_ready(struct iwl_trans *trans)
static int iwl_prepare_card_hw(struct iwl_trans *trans) static int iwl_prepare_card_hw(struct iwl_trans *trans)
{ {
int ret; int ret;
int t = 0;
IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
...@@ -908,17 +910,15 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) ...@@ -908,17 +910,15 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE); CSR_HW_IF_CONFIG_REG_PREPARE);
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, do {
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
if (ret < 0)
return ret;
/* HW should be ready by now, check again. */
ret = iwl_set_hw_ready(trans); ret = iwl_set_hw_ready(trans);
if (ret >= 0) if (ret >= 0)
return 0; return 0;
usleep_range(200, 1000);
t += 200;
} while (t < 150000);
return ret; return ret;
} }
...@@ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans) ...@@ -1769,7 +1769,7 @@ void iwl_dump_csr(struct iwl_trans *trans)
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, trans, \ if (!debugfs_create_file(#name, mode, parent, trans, \
&iwl_dbgfs_##name##_ops)) \ &iwl_dbgfs_##name##_ops)) \
return -ENOMEM; \ goto err; \
} while (0) } while (0)
/* file operation */ /* file operation */
...@@ -2033,6 +2033,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, ...@@ -2033,6 +2033,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
return 0; return 0;
err:
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
return -ENOMEM;
} }
#else #else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
......
...@@ -521,7 +521,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) ...@@ -521,7 +521,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
u16 copy_size, cmd_size; u16 copy_size, cmd_size;
bool had_nocopy = false; bool had_nocopy = false;
int i; int i;
u8 *cmd_dest; u32 cmd_pos;
#ifdef CONFIG_IWLWIFI_DEVICE_TRACING #ifdef CONFIG_IWLWIFI_DEVICE_TRACING
const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {}; const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
int trace_lens[IWL_MAX_CMD_TFDS + 1] = {}; 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,15 +584,31 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
INDEX_TO_SEQ(q->write_ptr)); INDEX_TO_SEQ(q->write_ptr));
/* and copy the data that needs to be copied */ /* and copy the data that needs to be copied */
cmd_pos = offsetof(struct iwl_device_cmd, payload);
cmd_dest = out_cmd->payload;
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i]) if (!cmd->len[i])
continue; continue;
if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
break; break;
memcpy(cmd_dest, cmd->data[i], cmd->len[i]); memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
cmd_dest += cmd->len[i]; cmd_pos += cmd->len[i];
}
WARN_ON_ONCE(txq->entries[idx].copy_cmd);
/*
* since out_cmd will be the source address of the FH, it will write
* the retry count there. So when the user needs to receivce the HCMD
* that corresponds to the response in the response handler, it needs
* to set CMD_WANT_HCMD.
*/
if (cmd->flags & CMD_WANT_HCMD) {
txq->entries[idx].copy_cmd =
kmemdup(out_cmd, cmd_pos, GFP_ATOMIC);
if (unlikely(!txq->entries[idx].copy_cmd)) {
idx = -ENOMEM;
goto out;
}
} }
IWL_DEBUG_HC(trans, IWL_DEBUG_HC(trans,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment