summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/mei/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mei/main.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/main.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index 112cc362e8e7..d9733aaf6f6e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -119,6 +119,7 @@ struct iwl_sap_shared_mem_ctrl_blk {
struct iwl_mei_shared_mem_ptrs {
struct iwl_sap_shared_mem_ctrl_blk *ctrl;
void *q_head[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX];
+ size_t q_size[SAP_DIRECTION_MAX][SAP_QUEUE_IDX_MAX];
};
struct iwl_mei_filters {
@@ -174,7 +175,7 @@ struct iwl_mei {
};
/**
- * iwl_mei_cache - cache for the parameters from iwlwifi
+ * struct iwl_mei_cache - cache for the parameters from iwlwifi
* @ops: Callbacks to iwlwifi.
* @netdev: The netdev that will be used to transmit / receive packets.
* @conn_info: The connection info message triggered by iwlwifi's association.
@@ -190,7 +191,7 @@ struct iwl_mei {
* is cached here so that we can buffer the configuration even if we don't have
* a bind from the mei bus and hence, on iwl_mei structure.
*/
-static struct {
+struct iwl_mei_cache {
const struct iwl_mei_ops *ops;
struct net_device __rcu *netdev;
const struct iwl_sap_notif_connection_info *conn_info;
@@ -200,7 +201,9 @@ static struct {
u8 mac_address[6];
u8 nvm_address[6];
void *priv;
-} iwl_mei_cache = {
+};
+
+static struct iwl_mei_cache iwl_mei_cache = {
.rf_kill = SAP_HW_RFKILL_DEASSERTED | SAP_SW_RFKILL_DEASSERTED
};
@@ -209,7 +212,7 @@ static void iwl_mei_free_shared_mem(struct mei_cl_device *cldev)
struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
if (mei_cldev_dma_unmap(cldev))
- dev_err(&cldev->dev, "Coudln't unmap the shared mem properly\n");
+ dev_err(&cldev->dev, "Couldn't unmap the shared mem properly\n");
memset(&mei->shared_mem, 0, sizeof(mei->shared_mem));
}
@@ -271,6 +274,8 @@ static void iwl_mei_init_shared_mem(struct iwl_mei *mei)
mem->q_head[dir][queue] = q_head;
q_head +=
le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size);
+ mem->q_size[dir][queue] =
+ le32_to_cpu(mem->ctrl->dir[dir].q_ctrl_blk[queue].size);
}
}
@@ -280,11 +285,11 @@ static void iwl_mei_init_shared_mem(struct iwl_mei *mei)
static ssize_t iwl_mei_write_cyclic_buf(struct mei_cl_device *cldev,
struct iwl_sap_q_ctrl_blk *notif_q,
u8 *q_head,
- const struct iwl_sap_hdr *hdr)
+ const struct iwl_sap_hdr *hdr,
+ u32 q_sz)
{
u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr));
u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr));
- u32 q_sz = le32_to_cpu(notif_q->size);
size_t room_in_buf;
size_t tx_sz = sizeof(*hdr) + le16_to_cpu(hdr->len);
@@ -382,6 +387,7 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev,
struct iwl_sap_q_ctrl_blk *notif_q;
struct iwl_sap_dir *dir;
void *q_head;
+ u32 q_sz;
int ret;
lockdep_assert_held(&iwl_mei_mutex);
@@ -404,7 +410,8 @@ static int iwl_mei_send_sap_msg_payload(struct mei_cl_device *cldev,
dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME];
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF];
q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
- ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr);
+ q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_NOTIF];
+ ret = iwl_mei_write_cyclic_buf(q_head, notif_q, q_head, hdr, q_sz);
if (ret < 0)
return ret;
@@ -454,10 +461,10 @@ void iwl_mei_add_data_to_ring(struct sk_buff *skb, bool cb_tx)
dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_HOST_TO_ME];
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA];
q_head = mei->shared_mem.q_head[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA];
+ q_sz = mei->shared_mem.q_size[SAP_DIRECTION_HOST_TO_ME][SAP_QUEUE_IDX_DATA];
rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr));
wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr));
- q_sz = le32_to_cpu(notif_q->size);
hdr_sz = cb_tx ? sizeof(struct iwl_sap_cb_data) :
sizeof(struct iwl_sap_hdr);
tx_sz = skb->len + hdr_sz;
@@ -627,6 +634,8 @@ static void iwl_mei_handle_csme_filters(struct mei_cl_device *cldev,
lockdep_is_held(&iwl_mei_mutex));
new_filters = kzalloc(sizeof(*new_filters), GFP_KERNEL);
+ if (!new_filters)
+ return;
/* Copy the OOB filters */
new_filters->filters = filters->filters;
@@ -1074,11 +1083,11 @@ static void iwl_mei_handle_sap_rx_cmd(struct mei_cl_device *cldev,
static void iwl_mei_handle_sap_rx(struct mei_cl_device *cldev,
struct iwl_sap_q_ctrl_blk *notif_q,
const u8 *q_head,
- struct sk_buff_head *skbs)
+ struct sk_buff_head *skbs,
+ u32 q_sz)
{
u32 rd = le32_to_cpu(READ_ONCE(notif_q->rd_ptr));
u32 wr = le32_to_cpu(READ_ONCE(notif_q->wr_ptr));
- u32 q_sz = le32_to_cpu(notif_q->size);
ssize_t valid_rx_sz;
if (rd > q_sz || wr > q_sz) {
@@ -1110,6 +1119,7 @@ static void iwl_mei_handle_check_shared_area(struct mei_cl_device *cldev)
struct sk_buff_head tx_skbs;
struct iwl_sap_dir *dir;
void *q_head;
+ u32 q_sz;
if (!mei->shared_mem.ctrl)
return;
@@ -1117,22 +1127,24 @@ static void iwl_mei_handle_check_shared_area(struct mei_cl_device *cldev)
dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST];
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_NOTIF];
q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF];
+ q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_NOTIF];
/*
* Do not hold the mutex here, but rather each and every message
* handler takes it.
* This allows message handlers to take it at a certain time.
*/
- iwl_mei_handle_sap_rx(cldev, notif_q, q_head, NULL);
+ iwl_mei_handle_sap_rx(cldev, notif_q, q_head, NULL, q_sz);
mutex_lock(&iwl_mei_mutex);
dir = &mei->shared_mem.ctrl->dir[SAP_DIRECTION_ME_TO_HOST];
notif_q = &dir->q_ctrl_blk[SAP_QUEUE_IDX_DATA];
q_head = mei->shared_mem.q_head[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA];
+ q_sz = mei->shared_mem.q_size[SAP_DIRECTION_ME_TO_HOST][SAP_QUEUE_IDX_DATA];
__skb_queue_head_init(&tx_skbs);
- iwl_mei_handle_sap_rx(cldev, notif_q, q_head, &tx_skbs);
+ iwl_mei_handle_sap_rx(cldev, notif_q, q_head, &tx_skbs, q_sz);
if (skb_queue_empty(&tx_skbs)) {
mutex_unlock(&iwl_mei_mutex);
@@ -1693,6 +1705,7 @@ void iwl_mei_unregister_complete(void)
mei_cldev_get_drvdata(iwl_mei_global_cldev);
iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WIFIDR_DOWN);
+ mei->got_ownership = false;
}
mutex_unlock(&iwl_mei_mutex);
@@ -1754,7 +1767,7 @@ static void iwl_mei_dbgfs_register(struct iwl_mei *mei)
mei->dbgfs_dir, &iwl_mei_status);
debugfs_create_file("send_start_message", S_IWUSR, mei->dbgfs_dir,
mei, &iwl_mei_dbgfs_send_start_message_ops);
- debugfs_create_file("req_ownserhip", S_IWUSR, mei->dbgfs_dir,
+ debugfs_create_file("req_ownership", S_IWUSR, mei->dbgfs_dir,
mei, &iwl_mei_dbgfs_req_ownership_ops);
}
@@ -1771,7 +1784,7 @@ static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) {}
#endif /* CONFIG_DEBUG_FS */
-/**
+/*
* iwl_mei_probe - the probe function called by the mei bus enumeration
*
* This allocates the data needed by iwlmei and sets a pointer to this data
@@ -1799,6 +1812,12 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
mei_cldev_set_drvdata(cldev, mei);
mei->cldev = cldev;
+ /*
+ * The CSME firmware needs to boot the internal WLAN client. Wait here
+ * so that the DMA map request will succeed.
+ */
+ msleep(20);
+
ret = iwl_mei_alloc_shared_mem(cldev);
if (ret)
goto free;