aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAvri Altman <avri.altman@intel.com>2014-07-30 04:41:01 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-09-16 05:57:50 -0400
commit3edf8ff6179dc470d53f3b88d4a778e241a73654 (patch)
tree79d47945de1c95ac543ae340db2920bbd3c2c6f3 /drivers/net
parent73897bd1d949d34b7a38a2cd14302d91f68ef12d (diff)
iwlwifi: mvm: prepare for scheduler config command
The scheduler is a HW sub-block that directs the work of the Flow Handler by issuing requests for frame transfers, specifying source and destination. Its primary function is to allocate flows into the TX FIFOs based upon a pre-determined mapping. The driver has some responsibilities to the scheduler, namely initialising and maintaining the hardware registers. This is currently done by directly accessing them, which can cause races with the firmware also accessing the registers. To address this problem, change the driver to no longer directly access the registers but go through the firmware for this if the firmware has support for DQA and thus the new command. Signed-off-by: Avri Altman <avri.altman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h60
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h38
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c46
8 files changed, 165 insertions, 19 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index e33754682e60..4f6e66892acc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -153,6 +153,8 @@ enum iwl_ucode_tlv_api {
153 * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in 153 * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in
154 * probe requests. 154 * probe requests.
155 * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests 155 * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
156 * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
157 * which also implies support for the scheduler configuration command
156 */ 158 */
157enum iwl_ucode_tlv_capa { 159enum iwl_ucode_tlv_capa {
158 IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), 160 IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
@@ -160,6 +162,7 @@ enum iwl_ucode_tlv_capa {
160 IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), 162 IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9),
161 IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), 163 IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10),
162 IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), 164 IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11),
165 IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12),
163}; 166};
164 167
165/* The default calibrate table size if not specified by firmware file */ 168/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index a2c662808a88..667a92274c87 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -116,6 +116,9 @@ enum {
116 TXPATH_FLUSH = 0x1e, 116 TXPATH_FLUSH = 0x1e,
117 MGMT_MCAST_KEY = 0x1f, 117 MGMT_MCAST_KEY = 0x1f,
118 118
119 /* scheduler config */
120 SCD_QUEUE_CFG = 0x1d,
121
119 /* global key */ 122 /* global key */
120 WEP_KEY = 0x20, 123 WEP_KEY = 0x20,
121 124
@@ -1650,4 +1653,61 @@ struct iwl_dts_measurement_notif {
1650 __le32 voltage; 1653 __le32 voltage;
1651} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ 1654} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
1652 1655
1656/**
1657 * enum iwl_scd_control - scheduler config command control flags
1658 * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue
1659 * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW
1660 */
1661enum iwl_scd_control {
1662 IWL_SCD_CONTROL_RM_TID = BIT(4),
1663 IWL_SCD_CONTROL_SET_SSN = BIT(5),
1664};
1665
1666/**
1667 * enum iwl_scd_flags - scheduler config command flags
1668 * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue
1669 * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue
1670 * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled
1671 */
1672enum iwl_scd_flags {
1673 IWL_SCD_FLAGS_SHARE_TID = BIT(0),
1674 IWL_SCD_FLAGS_SHARE_RA = BIT(1),
1675 IWL_SCD_FLAGS_DQA_ENABLED = BIT(2),
1676};
1677
1678#define IWL_SCDQ_INVALID_STA 0xff
1679
1680/**
1681 * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
1682 * @token: dialog token addba - unused legacy
1683 * @sta_id: station id 4-bit
1684 * @tid: TID 0..7
1685 * @scd_queue: TFD queue num 0 .. 31
1686 * @enable: 1 queue enable, 0 queue disable
1687 * @aggregate: 1 aggregated queue, 0 otherwise
1688 * @tx_fifo: tx fifo num 0..7
1689 * @window: up to 64
1690 * @ssn: starting seq num 12-bit
1691 * @control: command control flags
1692 * @flags: flags - see &enum iwl_scd_flags
1693 *
1694 * Note that every time the command is sent, all parameters must
1695 * be filled with the exception of
1696 * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN
1697 * - the window, which is only relevant when starting aggregation
1698 */
1699struct iwl_scd_txq_cfg_cmd {
1700 u8 token;
1701 u8 sta_id;
1702 u8 tid;
1703 u8 scd_queue;
1704 u8 enable;
1705 u8 aggregate;
1706 u8 tx_fifo;
1707 u8 window;
1708 __le16 ssn;
1709 u8 control;
1710 u8 flags;
1711} __packed;
1712
1653#endif /* __fw_api_h__ */ 1713#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 834267145929..0c5c0b0e23f5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -427,17 +427,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
427 427
428 switch (vif->type) { 428 switch (vif->type) {
429 case NL80211_IFTYPE_P2P_DEVICE: 429 case NL80211_IFTYPE_P2P_DEVICE:
430 iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, 430 iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
431 IWL_MVM_TX_FIFO_VO); 431 IWL_MVM_TX_FIFO_VO);
432 break; 432 break;
433 case NL80211_IFTYPE_AP: 433 case NL80211_IFTYPE_AP:
434 iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, 434 iwl_mvm_enable_ac_txq(mvm, vif->cab_queue,
435 IWL_MVM_TX_FIFO_MCAST); 435 IWL_MVM_TX_FIFO_MCAST);
436 /* fall through */ 436 /* fall through */
437 default: 437 default:
438 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 438 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
439 iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac], 439 iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
440 iwl_mvm_ac_to_tx_fifo[ac]); 440 iwl_mvm_ac_to_tx_fifo[ac]);
441 break; 441 break;
442 } 442 }
443 443
@@ -452,16 +452,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
452 452
453 switch (vif->type) { 453 switch (vif->type) {
454 case NL80211_IFTYPE_P2P_DEVICE: 454 case NL80211_IFTYPE_P2P_DEVICE:
455 iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE, 455 iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE);
456 true);
457 break; 456 break;
458 case NL80211_IFTYPE_AP: 457 case NL80211_IFTYPE_AP:
459 iwl_trans_txq_disable(mvm->trans, vif->cab_queue, true); 458 iwl_mvm_disable_txq(mvm, vif->cab_queue);
460 /* fall through */ 459 /* fall through */
461 default: 460 default:
462 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 461 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
463 iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac], 462 iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]);
464 true);
465 } 463 }
466} 464}
467 465
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 552995810f9e..8eacebb90f23 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -779,6 +779,11 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
779 (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); 779 (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
780} 780}
781 781
782static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
783{
784 return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT;
785}
786
782extern const u8 iwl_mvm_ac_to_tx_fifo[]; 787extern const u8 iwl_mvm_ac_to_tx_fifo[];
783 788
784struct iwl_rate_info { 789struct iwl_rate_info {
@@ -1141,6 +1146,39 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
1141 return mvmvif->low_latency; 1146 return mvmvif->low_latency;
1142} 1147}
1143 1148
1149/* hw scheduler queue config */
1150void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
1151 const struct iwl_trans_txq_scd_cfg *cfg);
1152void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue);
1153
1154static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
1155 u8 fifo)
1156{
1157 struct iwl_trans_txq_scd_cfg cfg = {
1158 .fifo = fifo,
1159 .tid = IWL_MAX_TID_COUNT,
1160 .aggregate = false,
1161 .frame_limit = IWL_FRAME_LIMIT,
1162 };
1163
1164 iwl_mvm_enable_txq(mvm, queue, 0, &cfg);
1165}
1166
1167static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
1168 int fifo, int sta_id, int tid,
1169 int frame_limit, u16 ssn)
1170{
1171 struct iwl_trans_txq_scd_cfg cfg = {
1172 .fifo = fifo,
1173 .sta_id = sta_id,
1174 .tid = tid,
1175 .frame_limit = frame_limit,
1176 .aggregate = true,
1177 };
1178
1179 iwl_mvm_enable_txq(mvm, queue, ssn, &cfg);
1180}
1181
1144/* Assoc status */ 1182/* Assoc status */
1145bool iwl_mvm_is_idle(struct iwl_mvm *mvm); 1183bool iwl_mvm_is_idle(struct iwl_mvm *mvm);
1146 1184
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index f887779717d5..9bf9de7927b9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -342,6 +342,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
342 CMD(BT_COEX_UPDATE_REDUCED_TXP), 342 CMD(BT_COEX_UPDATE_REDUCED_TXP),
343 CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), 343 CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
344 CMD(ANTENNA_COUPLING_NOTIFICATION), 344 CMD(ANTENNA_COUPLING_NOTIFICATION),
345 CMD(SCD_QUEUE_CFG),
345}; 346};
346#undef CMD 347#undef CMD
347 348
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 666f16b4bed9..bccd7870626c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -535,8 +535,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
535 lockdep_assert_held(&mvm->mutex); 535 lockdep_assert_held(&mvm->mutex);
536 536
537 /* Map Aux queue to fifo - needs to happen before adding Aux station */ 537 /* Map Aux queue to fifo - needs to happen before adding Aux station */
538 iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue, 538 iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue,
539 IWL_MVM_TX_FIFO_MCAST); 539 IWL_MVM_TX_FIFO_MCAST);
540 540
541 /* Allocate aux station and assign to it the aux queue */ 541 /* Allocate aux station and assign to it the aux queue */
542 ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), 542 ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
@@ -887,8 +887,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
887 if (ret) 887 if (ret)
888 return -EIO; 888 return -EIO;
889 889
890 iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid, 890 iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
891 buf_size, ssn); 891 buf_size, ssn);
892 892
893 /* 893 /*
894 * Even though in theory the peer could have different 894 * Even though in theory the peer could have different
@@ -956,7 +956,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
956 956
957 iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); 957 iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
958 958
959 iwl_trans_txq_disable(mvm->trans, txq_id, true); 959 iwl_mvm_disable_txq(mvm, txq_id);
960 return 0; 960 return 0;
961 case IWL_AGG_STARTING: 961 case IWL_AGG_STARTING:
962 case IWL_EMPTYING_HW_QUEUE_ADDBA: 962 case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1013,7 +1013,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1013 1013
1014 iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); 1014 iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
1015 1015
1016 iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); 1016 iwl_mvm_disable_txq(mvm, tid_data->txq_id);
1017 } 1017 }
1018 1018
1019 mvm->queue_to_mac80211[tid_data->txq_id] = 1019 mvm->queue_to_mac80211[tid_data->txq_id] =
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index d84f3ca75f63..66e1a3ddc75b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -493,11 +493,11 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
493 IWL_DEBUG_TX_QUEUES(mvm, 493 IWL_DEBUG_TX_QUEUES(mvm,
494 "Can continue DELBA flow ssn = next_recl = %d\n", 494 "Can continue DELBA flow ssn = next_recl = %d\n",
495 tid_data->next_reclaimed); 495 tid_data->next_reclaimed);
496 iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); 496 iwl_mvm_disable_txq(mvm, tid_data->txq_id);
497 tid_data->state = IWL_AGG_OFF; 497 tid_data->state = IWL_AGG_OFF;
498 /* 498 /*
499 * we can't hold the mutex - but since we are after a sequence 499 * we can't hold the mutex - but since we are after a sequence
500 * point (call to iwl_trans_txq_disable), so we don't even need 500 * point (call to iwl_mvm_disable_txq(), so we don't even need
501 * a memory barrier. 501 * a memory barrier.
502 */ 502 */
503 mvm->queue_to_mac80211[tid_data->txq_id] = 503 mvm->queue_to_mac80211[tid_data->txq_id] =
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 1958f298ac8b..8021f6eec27f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -530,6 +530,52 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
530 iwl_mvm_dump_umac_error_log(mvm); 530 iwl_mvm_dump_umac_error_log(mvm);
531} 531}
532 532
533void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
534 const struct iwl_trans_txq_scd_cfg *cfg)
535{
536 if (iwl_mvm_is_dqa_supported(mvm)) {
537 struct iwl_scd_txq_cfg_cmd cmd = {
538 .scd_queue = queue,
539 .enable = 1,
540 .window = cfg->frame_limit,
541 .sta_id = cfg->sta_id,
542 .ssn = cpu_to_le16(ssn),
543 .tx_fifo = cfg->fifo,
544 .aggregate = cfg->aggregate,
545 .flags = IWL_SCD_FLAGS_DQA_ENABLED,
546 .tid = cfg->tid,
547 .control = IWL_SCD_CONTROL_SET_SSN,
548 };
549 int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0,
550 sizeof(cmd), &cmd);
551 if (ret)
552 IWL_ERR(mvm,
553 "Failed to configure queue %d on FIFO %d\n",
554 queue, cfg->fifo);
555 }
556
557 iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
558 iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg);
559}
560
561void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue)
562{
563 iwl_trans_txq_disable(mvm->trans, queue,
564 !iwl_mvm_is_dqa_supported(mvm));
565
566 if (iwl_mvm_is_dqa_supported(mvm)) {
567 struct iwl_scd_txq_cfg_cmd cmd = {
568 .scd_queue = queue,
569 .enable = 0,
570 };
571 int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC,
572 sizeof(cmd), &cmd);
573 if (ret)
574 IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
575 queue, ret);
576 }
577}
578
533/** 579/**
534 * iwl_mvm_send_lq_cmd() - Send link quality command 580 * iwl_mvm_send_lq_cmd() - Send link quality command
535 * @init: This command is sent as part of station initialization right 581 * @init: This command is sent as part of station initialization right