diff options
author | Ilan Peer <ilan.peer@intel.com> | 2013-03-21 10:23:52 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-05-13 18:15:18 +0200 |
commit | fe0f2de30cc3417794517afe45f57e851b3188ae (patch) | |
tree | edea6958b2345e6fdc681cf9a867c72980d7fa78 /drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |
parent | c571573a027bb65ac415141f919df3c0fa0fedb4 (diff) | |
download | op-kernel-dev-fe0f2de30cc3417794517afe45f57e851b3188ae.zip op-kernel-dev-fe0f2de30cc3417794517afe45f57e851b3188ae.tar.gz |
iwlwifi: mvm: Loosen the channel context/phy context coupling
In current implementation, the phy context is tightly coupled
with the channel context. This complicates the possibility of
using the same phy context for both netdev interfaces and the P2P
Device interface. To loosen this coupling:
1. Manage all the phy contexts in the mvm op mode, and only save
the phy context id in the chanctx memory.
2. Reference count the phy contexts and free them only when they
are not longer used (both by mac80211 and P2P Device).
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | 73 |
1 files changed, 34 insertions, 39 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index a28a1d1..f80e721 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -195,21 +195,6 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, return ret; } - -struct phy_ctx_used_data { - unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)]; -}; - -static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *ctx, - void *_data) -{ - struct phy_ctx_used_data *data = _data; - struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; - - __set_bit(phy_ctxt->id, data->used); -} - /* * Send a command to add a PHY context based on the current HW configuration. */ @@ -217,34 +202,31 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { - struct phy_ctx_used_data data = { - .used = { }, - }; - - /* - * If this is a regular PHY context (not the ROC one) - * skip the ROC PHY context's ID. - */ - if (ctxt != &mvm->phy_ctxt_roc) - __set_bit(mvm->phy_ctxt_roc.id, data.used); + int ret; + WARN_ON(ctxt->ref); lockdep_assert_held(&mvm->mutex); - ctxt->color++; - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - ieee80211_iter_chan_contexts_atomic( - mvm->hw, iwl_mvm_phy_ctx_used_iter, &data); + ctxt->channel = chandef->chan; + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + chains_static, chains_dynamic, + FW_CTXT_ACTION_ADD, 0); - ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX); - if (WARN_ONCE(ctxt->id == NUM_PHY_CTX, - "Failed to init PHY context - no free ID!\n")) - return -EIO; - } + if (!ret) + ctxt->ref = 1; + return ret; +} - ctxt->channel = chandef->chan; - return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, - chains_static, chains_dynamic, - FW_CTXT_ACTION_ADD, 0); +/* + * Update the number of references to the given PHY context. This is valid only + * in case the PHY context was already created, i.e., its reference count > 0. + */ +void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) +{ + WARN_ON(!ctxt->ref); + lockdep_assert_held(&mvm->mutex); + + ctxt->ref++; } /* @@ -269,7 +251,8 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, * Once the command is sent, regardless of success or failure, the context is * marked as invalid */ -void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) +static void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt) { struct iwl_phy_context_cmd cmd; int ret; @@ -280,7 +263,19 @@ void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, sizeof(struct iwl_phy_context_cmd), &cmd); + ctxt->channel = NULL; if (ret) IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n", ctxt->id); } + +void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) +{ + lockdep_assert_held(&mvm->mutex); + + ctxt->ref--; + if (ctxt->ref != 0) + return; + + return iwl_mvm_phy_ctxt_remove(mvm, ctxt); +} |