continue;
}
+ if (WARN_ON(!arvif))
+ continue;
+
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n",
arvif->vdev_id,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
- struct ath12k *ar;
+ struct ath12k *curr_ar, *new_ar, *group_ar;
+ struct ieee80211_vif_chanctx_switch *v;
+ int i, j, count = 0;
lockdep_assert_wiphy(hw->wiphy);
- ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
- if (!ar)
- return -EINVAL;
+ if (n_vifs == 0)
+ return 0;
- /* Switching channels across radio is not allowed */
- if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx))
- return -EINVAL;
+ struct ath12k **ar_map __free(kfree) = kzalloc_objs(*ar_map, n_vifs);
- ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
- "mac chanctx switch n_vifs %d mode %d\n",
- n_vifs, mode);
- ath12k_mac_update_vif_chan(ar, vifs, n_vifs);
+ if (!ar_map)
+ return -ENOMEM;
+
+ for (i = 0; i < n_vifs; i++) {
+ v = &vifs[i];
+
+ if (v->old_ctx->def.chan->band != v->new_ctx->def.chan->band) {
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "mac chanctx switch band change not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ curr_ar = ath12k_get_ar_by_ctx(hw, v->old_ctx);
+ new_ar = ath12k_get_ar_by_ctx(hw, v->new_ctx);
+
+ if (!curr_ar || !new_ar) {
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "unable to determine device for the passed channel ctx\n");
+ ath12k_generic_dbg(ATH12K_DBG_MAC,
+ "Old freq %d MHz (device %s) to new freq %d MHz (device %s)\n",
+ v->old_ctx->def.chan->center_freq,
+ curr_ar ? "valid" : "invalid",
+ v->new_ctx->def.chan->center_freq,
+ new_ar ? "valid" : "invalid");
+ return -EINVAL;
+ }
+ /* Switching a vif between two radios is not allowed */
+ if (curr_ar != new_ar) {
+ ath12k_dbg(curr_ar->ab, ATH12K_DBG_MAC,
+ "mac chanctx switch to another radio not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ar_map[i] = curr_ar;
+ }
+
+ /* Group vifs by radio (ar) and process each group independently. */
+ bool *processed __free(kfree) = kzalloc_objs(*processed, n_vifs);
+
+ if (!processed)
+ return -ENOMEM;
+
+ struct ieee80211_vif_chanctx_switch *group_vifs __free(kfree) =
+ kzalloc_objs(*group_vifs, n_vifs);
+
+ if (!group_vifs)
+ return -ENOMEM;
+
+ for (i = 0; i < n_vifs; i++) {
+ if (processed[i])
+ continue;
+
+ group_ar = ar_map[i];
+
+ count = 0;
+ for (j = 0; j < n_vifs; j++) {
+ if (!processed[j] && ar_map[j] == group_ar) {
+ group_vifs[count++] = vifs[j];
+ processed[j] = true;
+ }
+ }
+
+ ath12k_dbg(group_ar->ab, ATH12K_DBG_MAC,
+ "mac chanctx switch n_vifs %d mode %d\n",
+ count, mode);
+ ath12k_mac_update_vif_chan(group_ar, group_vifs, count);
+ }
return 0;
}
EXPORT_SYMBOL(ath12k_mac_op_switch_vif_chanctx);