162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2020-2022 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "chan.h" 662306a36Sopenharmony_ci#include "debug.h" 762306a36Sopenharmony_ci#include "fw.h" 862306a36Sopenharmony_ci#include "ps.h" 962306a36Sopenharmony_ci#include "util.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band, 1262306a36Sopenharmony_ci u8 center_chan) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci switch (band) { 1562306a36Sopenharmony_ci default: 1662306a36Sopenharmony_ci case RTW89_BAND_2G: 1762306a36Sopenharmony_ci switch (center_chan) { 1862306a36Sopenharmony_ci default: 1962306a36Sopenharmony_ci case 1 ... 14: 2062306a36Sopenharmony_ci return RTW89_CH_2G; 2162306a36Sopenharmony_ci } 2262306a36Sopenharmony_ci case RTW89_BAND_5G: 2362306a36Sopenharmony_ci switch (center_chan) { 2462306a36Sopenharmony_ci default: 2562306a36Sopenharmony_ci case 36 ... 64: 2662306a36Sopenharmony_ci return RTW89_CH_5G_BAND_1; 2762306a36Sopenharmony_ci case 100 ... 144: 2862306a36Sopenharmony_ci return RTW89_CH_5G_BAND_3; 2962306a36Sopenharmony_ci case 149 ... 177: 3062306a36Sopenharmony_ci return RTW89_CH_5G_BAND_4; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci case RTW89_BAND_6G: 3362306a36Sopenharmony_ci switch (center_chan) { 3462306a36Sopenharmony_ci default: 3562306a36Sopenharmony_ci case 1 ... 29: 3662306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX0; 3762306a36Sopenharmony_ci case 33 ... 61: 3862306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX1; 3962306a36Sopenharmony_ci case 65 ... 93: 4062306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX2; 4162306a36Sopenharmony_ci case 97 ... 125: 4262306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX3; 4362306a36Sopenharmony_ci case 129 ... 157: 4462306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX4; 4562306a36Sopenharmony_ci case 161 ... 189: 4662306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX5; 4762306a36Sopenharmony_ci case 193 ... 221: 4862306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX6; 4962306a36Sopenharmony_ci case 225 ... 253: 5062306a36Sopenharmony_ci return RTW89_CH_6G_BAND_IDX7; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw, 5662306a36Sopenharmony_ci u32 center_freq, 5762306a36Sopenharmony_ci u32 primary_freq) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci u8 primary_chan_idx; 6062306a36Sopenharmony_ci u32 offset; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci switch (bw) { 6362306a36Sopenharmony_ci default: 6462306a36Sopenharmony_ci case RTW89_CHANNEL_WIDTH_20: 6562306a36Sopenharmony_ci primary_chan_idx = RTW89_SC_DONT_CARE; 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci case RTW89_CHANNEL_WIDTH_40: 6862306a36Sopenharmony_ci if (primary_freq > center_freq) 6962306a36Sopenharmony_ci primary_chan_idx = RTW89_SC_20_UPPER; 7062306a36Sopenharmony_ci else 7162306a36Sopenharmony_ci primary_chan_idx = RTW89_SC_20_LOWER; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case RTW89_CHANNEL_WIDTH_80: 7462306a36Sopenharmony_ci case RTW89_CHANNEL_WIDTH_160: 7562306a36Sopenharmony_ci if (primary_freq > center_freq) { 7662306a36Sopenharmony_ci offset = (primary_freq - center_freq - 10) / 20; 7762306a36Sopenharmony_ci primary_chan_idx = RTW89_SC_20_UPPER + offset * 2; 7862306a36Sopenharmony_ci } else { 7962306a36Sopenharmony_ci offset = (center_freq - primary_freq - 10) / 20; 8062306a36Sopenharmony_ci primary_chan_idx = RTW89_SC_20_LOWER + offset * 2; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return primary_chan_idx; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, 8962306a36Sopenharmony_ci enum rtw89_band band, enum rtw89_bandwidth bandwidth) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); 9262306a36Sopenharmony_ci u32 center_freq, primary_freq; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci memset(chan, 0, sizeof(*chan)); 9562306a36Sopenharmony_ci chan->channel = center_chan; 9662306a36Sopenharmony_ci chan->primary_channel = primary_chan; 9762306a36Sopenharmony_ci chan->band_type = band; 9862306a36Sopenharmony_ci chan->band_width = bandwidth; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci center_freq = ieee80211_channel_to_frequency(center_chan, nl_band); 10162306a36Sopenharmony_ci primary_freq = ieee80211_channel_to_frequency(primary_chan, nl_band); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci chan->freq = center_freq; 10462306a36Sopenharmony_ci chan->subband_type = rtw89_get_subband_type(band, center_chan); 10562306a36Sopenharmony_ci chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq, 10662306a36Sopenharmony_ci primary_freq); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cibool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, 11062306a36Sopenharmony_ci enum rtw89_sub_entity_idx idx, 11162306a36Sopenharmony_ci const struct rtw89_chan *new) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 11462306a36Sopenharmony_ci struct rtw89_chan *chan = &hal->sub[idx].chan; 11562306a36Sopenharmony_ci struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd; 11662306a36Sopenharmony_ci bool band_changed; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci rcd->prev_primary_channel = chan->primary_channel; 11962306a36Sopenharmony_ci rcd->prev_band_type = chan->band_type; 12062306a36Sopenharmony_ci band_changed = new->band_type != chan->band_type; 12162306a36Sopenharmony_ci rcd->band_changed = band_changed; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci *chan = *new; 12462306a36Sopenharmony_ci return band_changed; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, 12862306a36Sopenharmony_ci enum rtw89_sub_entity_idx idx, 12962306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef, 13062306a36Sopenharmony_ci bool from_stack) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci hal->sub[idx].chandef = *chandef; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (from_stack) 13762306a36Sopenharmony_ci set_bit(idx, hal->entity_map); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_civoid rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, 14162306a36Sopenharmony_ci enum rtw89_sub_entity_idx idx, 14262306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci __rtw89_config_entity_chandef(rtwdev, idx, chandef, true); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, 14862306a36Sopenharmony_ci enum rtw89_sub_entity_idx idx, 14962306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 15262306a36Sopenharmony_ci enum rtw89_sub_entity_idx cur; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (chandef) { 15562306a36Sopenharmony_ci cur = atomic_cmpxchg(&hal->roc_entity_idx, 15662306a36Sopenharmony_ci RTW89_SUB_ENTITY_IDLE, idx); 15762306a36Sopenharmony_ci if (cur != RTW89_SUB_ENTITY_IDLE) { 15862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 15962306a36Sopenharmony_ci "ROC still processing on entity %d\n", idx); 16062306a36Sopenharmony_ci return; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci hal->roc_chandef = *chandef; 16462306a36Sopenharmony_ci } else { 16562306a36Sopenharmony_ci cur = atomic_cmpxchg(&hal->roc_entity_idx, idx, 16662306a36Sopenharmony_ci RTW89_SUB_ENTITY_IDLE); 16762306a36Sopenharmony_ci if (cur == idx) 16862306a36Sopenharmony_ci return; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (cur == RTW89_SUB_ENTITY_IDLE) 17162306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 17262306a36Sopenharmony_ci "ROC already finished on entity %d\n", idx); 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, 17562306a36Sopenharmony_ci "ROC is processing on entity %d\n", cur); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct cfg80211_chan_def chandef = {0}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci rtw89_get_default_chandef(&chandef); 18462306a36Sopenharmony_ci __rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, &chandef, false); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_civoid rtw89_entity_init(struct rtw89_dev *rtwdev) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); 19262306a36Sopenharmony_ci atomic_set(&hal->roc_entity_idx, RTW89_SUB_ENTITY_IDLE); 19362306a36Sopenharmony_ci rtw89_config_default_chandef(rtwdev); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cienum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 19962306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef; 20062306a36Sopenharmony_ci enum rtw89_entity_mode mode; 20162306a36Sopenharmony_ci struct rtw89_chan chan; 20262306a36Sopenharmony_ci u8 weight; 20362306a36Sopenharmony_ci u8 last; 20462306a36Sopenharmony_ci u8 idx; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); 20762306a36Sopenharmony_ci switch (weight) { 20862306a36Sopenharmony_ci default: 20962306a36Sopenharmony_ci rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight); 21062306a36Sopenharmony_ci bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); 21162306a36Sopenharmony_ci fallthrough; 21262306a36Sopenharmony_ci case 0: 21362306a36Sopenharmony_ci rtw89_config_default_chandef(rtwdev); 21462306a36Sopenharmony_ci fallthrough; 21562306a36Sopenharmony_ci case 1: 21662306a36Sopenharmony_ci last = RTW89_SUB_ENTITY_0; 21762306a36Sopenharmony_ci mode = RTW89_ENTITY_MODE_SCC; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case 2: 22062306a36Sopenharmony_ci last = RTW89_SUB_ENTITY_1; 22162306a36Sopenharmony_ci mode = rtw89_get_entity_mode(rtwdev); 22262306a36Sopenharmony_ci if (mode == RTW89_ENTITY_MODE_MCC) 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mode = RTW89_ENTITY_MODE_MCC_PREPARE; 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci for (idx = 0; idx <= last; idx++) { 23062306a36Sopenharmony_ci chandef = rtw89_chandef_get(rtwdev, idx); 23162306a36Sopenharmony_ci rtw89_get_channel_params(chandef, &chan); 23262306a36Sopenharmony_ci if (chan.channel == 0) { 23362306a36Sopenharmony_ci WARN(1, "Invalid channel on chanctx %d\n", idx); 23462306a36Sopenharmony_ci return RTW89_ENTITY_MODE_INVALID; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci rtw89_assign_entity_chan(rtwdev, idx, &chan); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci rtw89_set_entity_mode(rtwdev, mode); 24162306a36Sopenharmony_ci return mode; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void rtw89_chanctx_notify(struct rtw89_dev *rtwdev, 24562306a36Sopenharmony_ci enum rtw89_chanctx_state state) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 24862306a36Sopenharmony_ci const struct rtw89_chanctx_listener *listener = chip->chanctx_listener; 24962306a36Sopenharmony_ci int i; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!listener) 25262306a36Sopenharmony_ci return; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) { 25562306a36Sopenharmony_ci if (!listener->callbacks[i]) 25662306a36Sopenharmony_ci continue; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_CHAN, 25962306a36Sopenharmony_ci "chanctx notify listener: cb %d, state %d\n", 26062306a36Sopenharmony_ci i, state); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci listener->callbacks[i](rtwdev, state); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int rtw89_mcc_start(struct rtw89_dev *rtwdev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci if (rtwdev->scanning) 26962306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci rtw89_leave_lps(rtwdev); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n"); 27462306a36Sopenharmony_ci rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START); 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void rtw89_mcc_stop(struct rtw89_dev *rtwdev) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n"); 28162306a36Sopenharmony_ci rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_civoid rtw89_chanctx_work(struct work_struct *work) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, 28762306a36Sopenharmony_ci chanctx_work.work); 28862306a36Sopenharmony_ci enum rtw89_entity_mode mode; 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci mode = rtw89_get_entity_mode(rtwdev); 29462306a36Sopenharmony_ci switch (mode) { 29562306a36Sopenharmony_ci case RTW89_ENTITY_MODE_MCC_PREPARE: 29662306a36Sopenharmony_ci rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC); 29762306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ret = rtw89_mcc_start(rtwdev); 30062306a36Sopenharmony_ci if (ret) 30162306a36Sopenharmony_ci rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret); 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci default: 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_civoid rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci enum rtw89_entity_mode mode; 31362306a36Sopenharmony_ci u32 delay; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mode = rtw89_get_entity_mode(rtwdev); 31662306a36Sopenharmony_ci switch (mode) { 31762306a36Sopenharmony_ci default: 31862306a36Sopenharmony_ci return; 31962306a36Sopenharmony_ci case RTW89_ENTITY_MODE_MCC_PREPARE: 32062306a36Sopenharmony_ci delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_CHAN, 32562306a36Sopenharmony_ci "queue chanctx work for mode %d with delay %d us\n", 32662306a36Sopenharmony_ci mode, delay); 32762306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work, 32862306a36Sopenharmony_ci usecs_to_jiffies(delay)); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ciint rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, 33262306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 33562306a36Sopenharmony_ci struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; 33662306a36Sopenharmony_ci const struct rtw89_chip_info *chip = rtwdev->chip; 33762306a36Sopenharmony_ci u8 idx; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci idx = find_first_zero_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY); 34062306a36Sopenharmony_ci if (idx >= chip->support_chanctx_num) 34162306a36Sopenharmony_ci return -ENOENT; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); 34462306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 34562306a36Sopenharmony_ci cfg->idx = idx; 34662306a36Sopenharmony_ci hal->sub[idx].cfg = cfg; 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_civoid rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, 35162306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 35462306a36Sopenharmony_ci struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; 35562306a36Sopenharmony_ci enum rtw89_entity_mode mode; 35662306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 35762306a36Sopenharmony_ci u8 drop, roll; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci drop = cfg->idx; 36062306a36Sopenharmony_ci if (drop != RTW89_SUB_ENTITY_0) 36162306a36Sopenharmony_ci goto out; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */ 36662306a36Sopenharmony_ci if (roll == NUM_OF_RTW89_SUB_ENTITY) 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* RTW89_SUB_ENTITY_0 is going to release, and another exists. 37062306a36Sopenharmony_ci * Make another roll down to RTW89_SUB_ENTITY_0 to replace. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0; 37362306a36Sopenharmony_ci hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll]; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) { 37662306a36Sopenharmony_ci if (rtwvif->sub_entity_idx == roll) 37762306a36Sopenharmony_ci rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci atomic_cmpxchg(&hal->roc_entity_idx, roll, RTW89_SUB_ENTITY_0); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci drop = roll; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciout: 38562306a36Sopenharmony_ci mode = rtw89_get_entity_mode(rtwdev); 38662306a36Sopenharmony_ci switch (mode) { 38762306a36Sopenharmony_ci case RTW89_ENTITY_MODE_MCC: 38862306a36Sopenharmony_ci rtw89_mcc_stop(rtwdev); 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci default: 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci clear_bit(drop, hal->entity_map); 39562306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_civoid rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, 39962306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 40062306a36Sopenharmony_ci u32 changed) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; 40362306a36Sopenharmony_ci u8 idx = cfg->idx; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) { 40662306a36Sopenharmony_ci rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); 40762306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ciint rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, 41262306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 41362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rtwvif->sub_entity_idx = cfg->idx; 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_civoid rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, 42262306a36Sopenharmony_ci struct rtw89_vif *rtwvif, 42362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; 42662306a36Sopenharmony_ci} 427