xref: /freebsd/sys/contrib/dev/iwlwifi/mvm/binding.c (revision 9af1bba44e1ce9b0296ae56760b564d67ab7a1cf)
1bfcc09ddSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2bfcc09ddSBjoern A. Zeeb /*
3bfcc09ddSBjoern A. Zeeb  * Copyright (C) 2012-2014, 2020 Intel Corporation
4bfcc09ddSBjoern A. Zeeb  * Copyright (C) 2016 Intel Deutschland GmbH
5*9af1bba4SBjoern A. Zeeb  * Copyright (C) 2022 Intel Corporation
6bfcc09ddSBjoern A. Zeeb  */
7bfcc09ddSBjoern A. Zeeb #include <net/mac80211.h>
8bfcc09ddSBjoern A. Zeeb #include "fw-api.h"
9bfcc09ddSBjoern A. Zeeb #include "mvm.h"
10bfcc09ddSBjoern A. Zeeb 
11bfcc09ddSBjoern A. Zeeb struct iwl_mvm_iface_iterator_data {
12bfcc09ddSBjoern A. Zeeb 	struct ieee80211_vif *ignore_vif;
13bfcc09ddSBjoern A. Zeeb 	int idx;
14bfcc09ddSBjoern A. Zeeb 
15bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_phy_ctxt *phyctxt;
16bfcc09ddSBjoern A. Zeeb 
17bfcc09ddSBjoern A. Zeeb 	u16 ids[MAX_MACS_IN_BINDING];
18bfcc09ddSBjoern A. Zeeb 	u16 colors[MAX_MACS_IN_BINDING];
19bfcc09ddSBjoern A. Zeeb };
20bfcc09ddSBjoern A. Zeeb 
iwl_mvm_binding_cmd(struct iwl_mvm * mvm,u32 action,struct iwl_mvm_iface_iterator_data * data)21bfcc09ddSBjoern A. Zeeb static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
22bfcc09ddSBjoern A. Zeeb 			       struct iwl_mvm_iface_iterator_data *data)
23bfcc09ddSBjoern A. Zeeb {
24bfcc09ddSBjoern A. Zeeb 	struct iwl_binding_cmd cmd;
25bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
26bfcc09ddSBjoern A. Zeeb 	int i, ret;
27bfcc09ddSBjoern A. Zeeb 	u32 status;
28bfcc09ddSBjoern A. Zeeb 	int size;
29bfcc09ddSBjoern A. Zeeb 
30bfcc09ddSBjoern A. Zeeb 	memset(&cmd, 0, sizeof(cmd));
31bfcc09ddSBjoern A. Zeeb 
32bfcc09ddSBjoern A. Zeeb 	if (fw_has_capa(&mvm->fw->ucode_capa,
33bfcc09ddSBjoern A. Zeeb 			IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
34bfcc09ddSBjoern A. Zeeb 		size = sizeof(cmd);
35*9af1bba4SBjoern A. Zeeb 		cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm,
36bfcc09ddSBjoern A. Zeeb 							      phyctxt->channel->band));
37bfcc09ddSBjoern A. Zeeb 	} else {
38bfcc09ddSBjoern A. Zeeb 		size = IWL_BINDING_CMD_SIZE_V1;
39bfcc09ddSBjoern A. Zeeb 	}
40bfcc09ddSBjoern A. Zeeb 
41bfcc09ddSBjoern A. Zeeb 	cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
42bfcc09ddSBjoern A. Zeeb 							   phyctxt->color));
43bfcc09ddSBjoern A. Zeeb 	cmd.action = cpu_to_le32(action);
44bfcc09ddSBjoern A. Zeeb 	cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
45bfcc09ddSBjoern A. Zeeb 						  phyctxt->color));
46bfcc09ddSBjoern A. Zeeb 
47bfcc09ddSBjoern A. Zeeb 	for (i = 0; i < MAX_MACS_IN_BINDING; i++)
48bfcc09ddSBjoern A. Zeeb 		cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
49bfcc09ddSBjoern A. Zeeb 	for (i = 0; i < data->idx; i++)
50bfcc09ddSBjoern A. Zeeb 		cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
51bfcc09ddSBjoern A. Zeeb 							      data->colors[i]));
52bfcc09ddSBjoern A. Zeeb 
53bfcc09ddSBjoern A. Zeeb 	status = 0;
54bfcc09ddSBjoern A. Zeeb 	ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
55bfcc09ddSBjoern A. Zeeb 					  size, &cmd, &status);
56bfcc09ddSBjoern A. Zeeb 	if (ret) {
57bfcc09ddSBjoern A. Zeeb 		IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
58bfcc09ddSBjoern A. Zeeb 			action, ret);
59bfcc09ddSBjoern A. Zeeb 		return ret;
60bfcc09ddSBjoern A. Zeeb 	}
61bfcc09ddSBjoern A. Zeeb 
62bfcc09ddSBjoern A. Zeeb 	if (status) {
63bfcc09ddSBjoern A. Zeeb 		IWL_ERR(mvm, "Binding command failed: %u\n", status);
64bfcc09ddSBjoern A. Zeeb 		ret = -EIO;
65bfcc09ddSBjoern A. Zeeb 	}
66bfcc09ddSBjoern A. Zeeb 
67bfcc09ddSBjoern A. Zeeb 	return ret;
68bfcc09ddSBjoern A. Zeeb }
69bfcc09ddSBjoern A. Zeeb 
iwl_mvm_iface_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)70bfcc09ddSBjoern A. Zeeb static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
71bfcc09ddSBjoern A. Zeeb 				   struct ieee80211_vif *vif)
72bfcc09ddSBjoern A. Zeeb {
73bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_iface_iterator_data *data = _data;
74bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
75bfcc09ddSBjoern A. Zeeb 
76bfcc09ddSBjoern A. Zeeb 	if (vif == data->ignore_vif)
77bfcc09ddSBjoern A. Zeeb 		return;
78bfcc09ddSBjoern A. Zeeb 
79*9af1bba4SBjoern A. Zeeb 	if (mvmvif->deflink.phy_ctxt != data->phyctxt)
80bfcc09ddSBjoern A. Zeeb 		return;
81bfcc09ddSBjoern A. Zeeb 
82bfcc09ddSBjoern A. Zeeb 	if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
83bfcc09ddSBjoern A. Zeeb 		return;
84bfcc09ddSBjoern A. Zeeb 
85bfcc09ddSBjoern A. Zeeb 	data->ids[data->idx] = mvmvif->id;
86bfcc09ddSBjoern A. Zeeb 	data->colors[data->idx] = mvmvif->color;
87bfcc09ddSBjoern A. Zeeb 	data->idx++;
88bfcc09ddSBjoern A. Zeeb }
89bfcc09ddSBjoern A. Zeeb 
iwl_mvm_binding_update(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct iwl_mvm_phy_ctxt * phyctxt,bool add)90bfcc09ddSBjoern A. Zeeb static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
91bfcc09ddSBjoern A. Zeeb 				  struct ieee80211_vif *vif,
92bfcc09ddSBjoern A. Zeeb 				  struct iwl_mvm_phy_ctxt *phyctxt,
93bfcc09ddSBjoern A. Zeeb 				  bool add)
94bfcc09ddSBjoern A. Zeeb {
95bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
96bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_iface_iterator_data data = {
97bfcc09ddSBjoern A. Zeeb 		.ignore_vif = vif,
98bfcc09ddSBjoern A. Zeeb 		.phyctxt = phyctxt,
99bfcc09ddSBjoern A. Zeeb 	};
100bfcc09ddSBjoern A. Zeeb 	u32 action = FW_CTXT_ACTION_MODIFY;
101bfcc09ddSBjoern A. Zeeb 
102bfcc09ddSBjoern A. Zeeb 	lockdep_assert_held(&mvm->mutex);
103bfcc09ddSBjoern A. Zeeb 
104bfcc09ddSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
105bfcc09ddSBjoern A. Zeeb 						   IEEE80211_IFACE_ITER_NORMAL,
106bfcc09ddSBjoern A. Zeeb 						   iwl_mvm_iface_iterator,
107bfcc09ddSBjoern A. Zeeb 						   &data);
108bfcc09ddSBjoern A. Zeeb 
109bfcc09ddSBjoern A. Zeeb 	/*
110bfcc09ddSBjoern A. Zeeb 	 * If there are no other interfaces yet we
111bfcc09ddSBjoern A. Zeeb 	 * need to create a new binding.
112bfcc09ddSBjoern A. Zeeb 	 */
113bfcc09ddSBjoern A. Zeeb 	if (data.idx == 0) {
114bfcc09ddSBjoern A. Zeeb 		if (add)
115bfcc09ddSBjoern A. Zeeb 			action = FW_CTXT_ACTION_ADD;
116bfcc09ddSBjoern A. Zeeb 		else
117bfcc09ddSBjoern A. Zeeb 			action = FW_CTXT_ACTION_REMOVE;
118bfcc09ddSBjoern A. Zeeb 	}
119bfcc09ddSBjoern A. Zeeb 
120bfcc09ddSBjoern A. Zeeb 	if (add) {
121bfcc09ddSBjoern A. Zeeb 		if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
122bfcc09ddSBjoern A. Zeeb 			return -EINVAL;
123bfcc09ddSBjoern A. Zeeb 
124bfcc09ddSBjoern A. Zeeb 		data.ids[data.idx] = mvmvif->id;
125bfcc09ddSBjoern A. Zeeb 		data.colors[data.idx] = mvmvif->color;
126bfcc09ddSBjoern A. Zeeb 		data.idx++;
127bfcc09ddSBjoern A. Zeeb 	}
128bfcc09ddSBjoern A. Zeeb 
129bfcc09ddSBjoern A. Zeeb 	return iwl_mvm_binding_cmd(mvm, action, &data);
130bfcc09ddSBjoern A. Zeeb }
131bfcc09ddSBjoern A. Zeeb 
iwl_mvm_binding_add_vif(struct iwl_mvm * mvm,struct ieee80211_vif * vif)132bfcc09ddSBjoern A. Zeeb int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
133bfcc09ddSBjoern A. Zeeb {
134bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
135bfcc09ddSBjoern A. Zeeb 
136*9af1bba4SBjoern A. Zeeb 	if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
137bfcc09ddSBjoern A. Zeeb 		return -EINVAL;
138bfcc09ddSBjoern A. Zeeb 
139bfcc09ddSBjoern A. Zeeb 	/*
140bfcc09ddSBjoern A. Zeeb 	 * Update SF - Disable if needed. if this fails, SF might still be on
141bfcc09ddSBjoern A. Zeeb 	 * while many macs are bound, which is forbidden - so fail the binding.
142bfcc09ddSBjoern A. Zeeb 	 */
143bfcc09ddSBjoern A. Zeeb 	if (iwl_mvm_sf_update(mvm, vif, false))
144bfcc09ddSBjoern A. Zeeb 		return -EINVAL;
145bfcc09ddSBjoern A. Zeeb 
146*9af1bba4SBjoern A. Zeeb 	return iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
147*9af1bba4SBjoern A. Zeeb 				      true);
148bfcc09ddSBjoern A. Zeeb }
149bfcc09ddSBjoern A. Zeeb 
iwl_mvm_binding_remove_vif(struct iwl_mvm * mvm,struct ieee80211_vif * vif)150bfcc09ddSBjoern A. Zeeb int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
151bfcc09ddSBjoern A. Zeeb {
152bfcc09ddSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
153bfcc09ddSBjoern A. Zeeb 	int ret;
154bfcc09ddSBjoern A. Zeeb 
155*9af1bba4SBjoern A. Zeeb 	if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
156bfcc09ddSBjoern A. Zeeb 		return -EINVAL;
157bfcc09ddSBjoern A. Zeeb 
158*9af1bba4SBjoern A. Zeeb 	ret = iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
159*9af1bba4SBjoern A. Zeeb 				     false);
160bfcc09ddSBjoern A. Zeeb 
161bfcc09ddSBjoern A. Zeeb 	if (!ret)
162bfcc09ddSBjoern A. Zeeb 		if (iwl_mvm_sf_update(mvm, vif, true))
163bfcc09ddSBjoern A. Zeeb 			IWL_ERR(mvm, "Failed to update SF state\n");
164bfcc09ddSBjoern A. Zeeb 
165bfcc09ddSBjoern A. Zeeb 	return ret;
166bfcc09ddSBjoern A. Zeeb }
167*9af1bba4SBjoern A. Zeeb 
iwl_mvm_get_lmac_id(struct iwl_mvm * mvm,enum nl80211_band band)168*9af1bba4SBjoern A. Zeeb u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band)
169*9af1bba4SBjoern A. Zeeb {
170*9af1bba4SBjoern A. Zeeb 	if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) ||
171*9af1bba4SBjoern A. Zeeb 	    band == NL80211_BAND_2GHZ)
172*9af1bba4SBjoern A. Zeeb 		return IWL_LMAC_24G_INDEX;
173*9af1bba4SBjoern A. Zeeb 	return IWL_LMAC_5G_INDEX;
174*9af1bba4SBjoern A. Zeeb }
175