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 9 static 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 53 static 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 86 void 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 107 bool 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 124 static 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 137 void 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 144 void 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 176 static 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 184 void 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 193 enum 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 217 int 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 236 void 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 269 out: 270 clear_bit(drop, hal->entity_map); 271 rtw89_set_channel(rtwdev); 272 } 273 274 void 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 287 int 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 297 void 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