1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2/* Copyright(c) 2020-2022  Realtek Corporation
3 */
4
5#include "chan.h"
6#include "debug.h"
7#include "util.h"
8
9static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
10						 u8 center_chan)
11{
12	switch (band) {
13	default:
14	case RTW89_BAND_2G:
15		switch (center_chan) {
16		default:
17		case 1 ... 14:
18			return RTW89_CH_2G;
19		}
20	case RTW89_BAND_5G:
21		switch (center_chan) {
22		default:
23		case 36 ... 64:
24			return RTW89_CH_5G_BAND_1;
25		case 100 ... 144:
26			return RTW89_CH_5G_BAND_3;
27		case 149 ... 177:
28			return RTW89_CH_5G_BAND_4;
29		}
30	case RTW89_BAND_6G:
31		switch (center_chan) {
32		default:
33		case 1 ... 29:
34			return RTW89_CH_6G_BAND_IDX0;
35		case 33 ... 61:
36			return RTW89_CH_6G_BAND_IDX1;
37		case 65 ... 93:
38			return RTW89_CH_6G_BAND_IDX2;
39		case 97 ... 125:
40			return RTW89_CH_6G_BAND_IDX3;
41		case 129 ... 157:
42			return RTW89_CH_6G_BAND_IDX4;
43		case 161 ... 189:
44			return RTW89_CH_6G_BAND_IDX5;
45		case 193 ... 221:
46			return RTW89_CH_6G_BAND_IDX6;
47		case 225 ... 253:
48			return RTW89_CH_6G_BAND_IDX7;
49		}
50	}
51}
52
53static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
54						       u32 center_freq,
55						       u32 primary_freq)
56{
57	u8 primary_chan_idx;
58	u32 offset;
59
60	switch (bw) {
61	default:
62	case RTW89_CHANNEL_WIDTH_20:
63		primary_chan_idx = RTW89_SC_DONT_CARE;
64		break;
65	case RTW89_CHANNEL_WIDTH_40:
66		if (primary_freq > center_freq)
67			primary_chan_idx = RTW89_SC_20_UPPER;
68		else
69			primary_chan_idx = RTW89_SC_20_LOWER;
70		break;
71	case RTW89_CHANNEL_WIDTH_80:
72	case RTW89_CHANNEL_WIDTH_160:
73		if (primary_freq > center_freq) {
74			offset = (primary_freq - center_freq - 10) / 20;
75			primary_chan_idx = RTW89_SC_20_UPPER + offset * 2;
76		} else {
77			offset = (center_freq - primary_freq - 10) / 20;
78			primary_chan_idx = RTW89_SC_20_LOWER + offset * 2;
79		}
80		break;
81	}
82
83	return primary_chan_idx;
84}
85
86void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
87		       enum rtw89_band band, enum rtw89_bandwidth bandwidth)
88{
89	enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
90	u32 center_freq, primary_freq;
91
92	memset(chan, 0, sizeof(*chan));
93	chan->channel = center_chan;
94	chan->primary_channel = primary_chan;
95	chan->band_type = band;
96	chan->band_width = bandwidth;
97
98	center_freq = ieee80211_channel_to_frequency(center_chan, nl_band);
99	primary_freq = ieee80211_channel_to_frequency(primary_chan, nl_band);
100
101	chan->freq = center_freq;
102	chan->subband_type = rtw89_get_subband_type(band, center_chan);
103	chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq,
104						      primary_freq);
105}
106
107bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
108			      enum rtw89_sub_entity_idx idx,
109			      const struct rtw89_chan *new)
110{
111	struct rtw89_hal *hal = &rtwdev->hal;
112	struct rtw89_chan *chan = &hal->sub[idx].chan;
113	struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd;
114	bool band_changed;
115
116	rcd->prev_primary_channel = chan->primary_channel;
117	rcd->prev_band_type = chan->band_type;
118	band_changed = new->band_type != chan->band_type;
119
120	*chan = *new;
121	return band_changed;
122}
123
124static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
125					  enum rtw89_sub_entity_idx idx,
126					  const struct cfg80211_chan_def *chandef,
127					  bool from_stack)
128{
129	struct rtw89_hal *hal = &rtwdev->hal;
130
131	hal->sub[idx].chandef = *chandef;
132
133	if (from_stack)
134		set_bit(idx, hal->entity_map);
135}
136
137void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
138				 enum rtw89_sub_entity_idx idx,
139				 const struct cfg80211_chan_def *chandef)
140{
141	__rtw89_config_entity_chandef(rtwdev, idx, chandef, true);
142}
143
144void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
145			      enum rtw89_sub_entity_idx idx,
146			      const struct cfg80211_chan_def *chandef)
147{
148	struct rtw89_hal *hal = &rtwdev->hal;
149	enum rtw89_sub_entity_idx cur;
150
151	if (chandef) {
152		cur = atomic_cmpxchg(&hal->roc_entity_idx,
153				     RTW89_SUB_ENTITY_IDLE, idx);
154		if (cur != RTW89_SUB_ENTITY_IDLE) {
155			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
156				    "ROC still processing on entity %d\n", idx);
157			return;
158		}
159
160		hal->roc_chandef = *chandef;
161	} else {
162		cur = atomic_cmpxchg(&hal->roc_entity_idx, idx,
163				     RTW89_SUB_ENTITY_IDLE);
164		if (cur == idx)
165			return;
166
167		if (cur == RTW89_SUB_ENTITY_IDLE)
168			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
169				    "ROC already finished on entity %d\n", idx);
170		else
171			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
172				    "ROC is processing on entity %d\n", cur);
173	}
174}
175
176static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
177{
178	struct cfg80211_chan_def chandef = {0};
179
180	rtw89_get_default_chandef(&chandef);
181	__rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, &chandef, false);
182}
183
184void rtw89_entity_init(struct rtw89_dev *rtwdev)
185{
186	struct rtw89_hal *hal = &rtwdev->hal;
187
188	bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
189	atomic_set(&hal->roc_entity_idx, RTW89_SUB_ENTITY_IDLE);
190	rtw89_config_default_chandef(rtwdev);
191}
192
193enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
194{
195	struct rtw89_hal *hal = &rtwdev->hal;
196	enum rtw89_entity_mode mode;
197	u8 weight;
198
199	weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
200	switch (weight) {
201	default:
202		rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight);
203		bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
204		fallthrough;
205	case 0:
206		rtw89_config_default_chandef(rtwdev);
207		fallthrough;
208	case 1:
209		mode = RTW89_ENTITY_MODE_SCC;
210		break;
211	}
212
213	rtw89_set_entity_mode(rtwdev, mode);
214	return mode;
215}
216
217int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
218			  struct ieee80211_chanctx_conf *ctx)
219{
220	struct rtw89_hal *hal = &rtwdev->hal;
221	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
222	const struct rtw89_chip_info *chip = rtwdev->chip;
223	u8 idx;
224
225	idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
226	if (idx >= chip->support_chanctx_num)
227		return -ENOENT;
228
229	rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
230	rtw89_set_channel(rtwdev);
231	cfg->idx = idx;
232	hal->sub[idx].cfg = cfg;
233	return 0;
234}
235
236void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
237			      struct ieee80211_chanctx_conf *ctx)
238{
239	struct rtw89_hal *hal = &rtwdev->hal;
240	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
241	struct rtw89_vif *rtwvif;
242	u8 drop, roll;
243
244	drop = cfg->idx;
245	if (drop != RTW89_SUB_ENTITY_0)
246		goto out;
247
248	roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1);
249
250	/* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
251	if (roll == NUM_OF_RTW89_SUB_ENTITY)
252		goto out;
253
254	/* RTW89_SUB_ENTITY_0 is going to release, and another exists.
255	 * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
256	 */
257	hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0;
258	hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll];
259
260	rtw89_for_each_rtwvif(rtwdev, rtwvif) {
261		if (rtwvif->sub_entity_idx == roll)
262			rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
263	}
264
265	atomic_cmpxchg(&hal->roc_entity_idx, roll, RTW89_SUB_ENTITY_0);
266
267	drop = roll;
268
269out:
270	clear_bit(drop, hal->entity_map);
271	rtw89_set_channel(rtwdev);
272}
273
274void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
275			      struct ieee80211_chanctx_conf *ctx,
276			      u32 changed)
277{
278	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
279	u8 idx = cfg->idx;
280
281	if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
282		rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
283		rtw89_set_channel(rtwdev);
284	}
285}
286
287int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
288				 struct rtw89_vif *rtwvif,
289				 struct ieee80211_chanctx_conf *ctx)
290{
291	struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
292
293	rtwvif->sub_entity_idx = cfg->idx;
294	return 0;
295}
296
297void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
298				    struct rtw89_vif *rtwvif,
299				    struct ieee80211_chanctx_conf *ctx)
300{
301	rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
302}
303