aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2015-12-16 11:48:28 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2016-02-27 15:00:10 -0500
commit94bb44813ebe07ff06f869c7612c0c73e04ac4b0 (patch)
tree9914073ae33ec46d9326a6057f2766c687cd2c59 /drivers/net/wireless/intel
parenta571f5f635ef40ff3a5e85acc7f20daa58bcf06a (diff)
iwlwifi: mvm: add RSS queues notification infrastructure
In multi rx queue HW, without execessive locking, there is no sync between the ctrl path (default queue) and the rest of the rx queues. This might cause issues on certain situations. For example, in case a delBA was processed on a default queue but out of order packets still wait for processing on the other queue. The solution is to introduce internal messaging between the CTRL path and the other rx queues. The driver will send a message to the firmware, which will echo it to all the requested queues. The message will be in order inside the queue. This way we can avoid CTRL path and RSS queues races. Add support for this messaging mechanism. As the firmware is agnostic to the data sent, add internal representation of the data as well. Although currently only delBA flow will use it, the internal representation will enable generic use of this infrastructure for future uses. Next patch will utilize this messaging mechanism for the reorder buffer delBA flow. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h52
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c48
5 files changed, 114 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
index df939f51d9b9..eb9b87038e1f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
@@ -391,4 +391,56 @@ struct iwl_rss_config_cmd {
391 u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE]; 391 u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE];
392} __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */ 392} __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */
393 393
394#define IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE 128
395#define IWL_MULTI_QUEUE_SYNC_SENDER_POS 0
396#define IWL_MULTI_QUEUE_SYNC_SENDER_MSK 0xf
397
398/**
399 * struct iwl_rxq_sync_cmd - RXQ notification trigger
400 *
401 * @flags: flags of the notification. bit 0:3 are the sender queue
402 * @rxq_mask: rx queues to send the notification on
403 * @count: number of bytes in payload, should be DWORD aligned
404 * @payload: data to send to rx queues
405 */
406struct iwl_rxq_sync_cmd {
407 __le32 flags;
408 __le32 rxq_mask;
409 __le32 count;
410 u8 payload[];
411} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
412
413/**
414 * struct iwl_rxq_sync_notification - Notification triggered by RXQ
415 * sync command
416 *
417 * @count: number of bytes in payload
418 * @payload: data to send to rx queues
419 */
420struct iwl_rxq_sync_notification {
421 __le32 count;
422 u8 payload[];
423} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
424
425/**
426* Internal message identifier
427*
428* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
429*/
430enum iwl_mvm_rxq_notif_type {
431 IWL_MVM_RXQ_NOTIF_DEL_BA,
432};
433
434/**
435* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
436* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
437*
438* @type: value from &iwl_mvm_rxq_notif_type
439* @data: payload
440*/
441struct iwl_mvm_internal_rxq_notif {
442 u32 type;
443 u8 data[];
444} __packed;
445
394#endif /* __fw_api_rx_h__ */ 446#endif /* __fw_api_rx_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
index e1e11946f7e9..f432ddd4cde3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
@@ -289,6 +289,8 @@ enum iwl_phy_ops_subcmd_ids {
289 289
290enum iwl_data_path_subcmd_ids { 290enum iwl_data_path_subcmd_ids {
291 UPDATE_MU_GROUPS_CMD = 0x1, 291 UPDATE_MU_GROUPS_CMD = 0x1,
292 TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2,
293 RX_QUEUES_NOTIFICATION = 0xFF,
292}; 294};
293 295
294enum iwl_prot_offload_subcmd_ids { 296enum iwl_prot_offload_subcmd_ids {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index fa987bd9da0d..f05d2a1f4467 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1225,6 +1225,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
1225 struct iwl_rx_cmd_buffer *rxb, int queue); 1225 struct iwl_rx_cmd_buffer *rxb, int queue);
1226void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, 1226void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
1227 struct iwl_rx_cmd_buffer *rxb, int queue); 1227 struct iwl_rx_cmd_buffer *rxb, int queue);
1228int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
1229 const u8 *data, u32 count);
1230void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
1231 int queue);
1228void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); 1232void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
1229void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); 1233void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
1230void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, 1234void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 52c73d0c1be5..ac271ffe477b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -404,6 +404,8 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
404 */ 404 */
405static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { 405static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
406 HCMD_NAME(UPDATE_MU_GROUPS_CMD), 406 HCMD_NAME(UPDATE_MU_GROUPS_CMD),
407 HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD),
408 HCMD_NAME(RX_QUEUES_NOTIFICATION),
407}; 409};
408 410
409/* Please keep this array *SORTED* by hex value. 411/* Please keep this array *SORTED* by hex value.
@@ -876,6 +878,9 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
876 iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0); 878 iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
877 else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD) 879 else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
878 iwl_mvm_rx_phy_cmd_mq(mvm, rxb); 880 iwl_mvm_rx_phy_cmd_mq(mvm, rxb);
881 else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP &&
882 pkt->hdr.cmd == RX_QUEUES_NOTIFICATION))
883 iwl_mvm_rx_queue_notif(mvm, rxb, 0);
879 else 884 else
880 iwl_mvm_rx_common(mvm, rxb, pkt); 885 iwl_mvm_rx_common(mvm, rxb, pkt);
881} 886}
@@ -1548,6 +1553,9 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
1548 1553
1549 if (unlikely(pkt->hdr.cmd == FRAME_RELEASE)) 1554 if (unlikely(pkt->hdr.cmd == FRAME_RELEASE))
1550 iwl_mvm_rx_frame_release(mvm, rxb, queue); 1555 iwl_mvm_rx_frame_release(mvm, rxb, queue);
1556 else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION &&
1557 pkt->hdr.group_id == DATA_PATH_GROUP))
1558 iwl_mvm_rx_queue_notif(mvm, rxb, queue);
1551 else 1559 else
1552 iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue); 1560 iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
1553} 1561}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index d89194223af3..590fc6faff04 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -345,6 +345,54 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
345 return false; 345 return false;
346} 346}
347 347
348int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
349 const u8 *data, u32 count)
350{
351 struct iwl_rxq_sync_cmd *cmd;
352 u32 data_size = sizeof(*cmd) + count;
353 int ret;
354
355 /* should be DWORD aligned */
356 if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE))
357 return -EINVAL;
358
359 cmd = kzalloc(data_size, GFP_KERNEL);
360 if (!cmd)
361 return -ENOMEM;
362
363 cmd->rxq_mask = cpu_to_le32(rxq_mask);
364 cmd->count = cpu_to_le32(count);
365 cmd->flags = 0;
366 memcpy(cmd->payload, data, count);
367
368 ret = iwl_mvm_send_cmd_pdu(mvm,
369 WIDE_ID(DATA_PATH_GROUP,
370 TRIGGER_RX_QUEUES_NOTIF_CMD),
371 0, data_size, cmd);
372
373 kfree(cmd);
374 return ret;
375}
376
377void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
378 int queue)
379{
380 struct iwl_rx_packet *pkt = rxb_addr(rxb);
381 struct iwl_rxq_sync_notification *notif;
382 struct iwl_mvm_internal_rxq_notif *internal_notif;
383
384 notif = (void *)pkt->data;
385 internal_notif = (void *)notif->payload;
386
387 switch (internal_notif->type) {
388 case IWL_MVM_RXQ_NOTIF_DEL_BA:
389 /* TODO */
390 break;
391 default:
392 WARN_ONCE(1, "Invalid identifier %d", internal_notif->type);
393 }
394}
395
348void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, 396void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
349 struct iwl_rx_cmd_buffer *rxb, int queue) 397 struct iwl_rx_cmd_buffer *rxb, int queue)
350{ 398{