0001
0002
0003
0004
0005
0006 #include <net/mac80211.h>
0007 #include "fw-api.h"
0008 #include "mvm.h"
0009
0010 struct iwl_mvm_iface_iterator_data {
0011 struct ieee80211_vif *ignore_vif;
0012 int idx;
0013
0014 struct iwl_mvm_phy_ctxt *phyctxt;
0015
0016 u16 ids[MAX_MACS_IN_BINDING];
0017 u16 colors[MAX_MACS_IN_BINDING];
0018 };
0019
0020 static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
0021 struct iwl_mvm_iface_iterator_data *data)
0022 {
0023 struct iwl_binding_cmd cmd;
0024 struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
0025 int i, ret;
0026 u32 status;
0027 int size;
0028
0029 memset(&cmd, 0, sizeof(cmd));
0030
0031 if (fw_has_capa(&mvm->fw->ucode_capa,
0032 IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
0033 size = sizeof(cmd);
0034 cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw,
0035 phyctxt->channel->band));
0036 } else {
0037 size = IWL_BINDING_CMD_SIZE_V1;
0038 }
0039
0040 cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
0041 phyctxt->color));
0042 cmd.action = cpu_to_le32(action);
0043 cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
0044 phyctxt->color));
0045
0046 for (i = 0; i < MAX_MACS_IN_BINDING; i++)
0047 cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
0048 for (i = 0; i < data->idx; i++)
0049 cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
0050 data->colors[i]));
0051
0052 status = 0;
0053 ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
0054 size, &cmd, &status);
0055 if (ret) {
0056 IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
0057 action, ret);
0058 return ret;
0059 }
0060
0061 if (status) {
0062 IWL_ERR(mvm, "Binding command failed: %u\n", status);
0063 ret = -EIO;
0064 }
0065
0066 return ret;
0067 }
0068
0069 static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
0070 struct ieee80211_vif *vif)
0071 {
0072 struct iwl_mvm_iface_iterator_data *data = _data;
0073 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0074
0075 if (vif == data->ignore_vif)
0076 return;
0077
0078 if (mvmvif->phy_ctxt != data->phyctxt)
0079 return;
0080
0081 if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
0082 return;
0083
0084 data->ids[data->idx] = mvmvif->id;
0085 data->colors[data->idx] = mvmvif->color;
0086 data->idx++;
0087 }
0088
0089 static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
0090 struct ieee80211_vif *vif,
0091 struct iwl_mvm_phy_ctxt *phyctxt,
0092 bool add)
0093 {
0094 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0095 struct iwl_mvm_iface_iterator_data data = {
0096 .ignore_vif = vif,
0097 .phyctxt = phyctxt,
0098 };
0099 u32 action = FW_CTXT_ACTION_MODIFY;
0100
0101 lockdep_assert_held(&mvm->mutex);
0102
0103 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0104 IEEE80211_IFACE_ITER_NORMAL,
0105 iwl_mvm_iface_iterator,
0106 &data);
0107
0108
0109
0110
0111
0112 if (data.idx == 0) {
0113 if (add)
0114 action = FW_CTXT_ACTION_ADD;
0115 else
0116 action = FW_CTXT_ACTION_REMOVE;
0117 }
0118
0119 if (add) {
0120 if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
0121 return -EINVAL;
0122
0123 data.ids[data.idx] = mvmvif->id;
0124 data.colors[data.idx] = mvmvif->color;
0125 data.idx++;
0126 }
0127
0128 return iwl_mvm_binding_cmd(mvm, action, &data);
0129 }
0130
0131 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0132 {
0133 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0134
0135 if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
0136 return -EINVAL;
0137
0138
0139
0140
0141
0142 if (iwl_mvm_sf_update(mvm, vif, false))
0143 return -EINVAL;
0144
0145 return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
0146 }
0147
0148 int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0149 {
0150 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0151 int ret;
0152
0153 if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
0154 return -EINVAL;
0155
0156 ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
0157
0158 if (!ret)
0159 if (iwl_mvm_sf_update(mvm, vif, true))
0160 IWL_ERR(mvm, "Failed to update SF state\n");
0161
0162 return ret;
0163 }