@@ -833,11 +833,6 @@ static void ath12k_core_device_cleanup(struct ath12k_base *ab)
if (test_bit(ATH12K_FLAG_PDEV_CREATED, &ab->dev_flags))
ath12k_core_pdev_destroy(ab);
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
- ath12k_mac_unregister(ab);
- ath12k_mac_destroy(ab);
- }
-
mutex_unlock(&ab->core_lock);
}
@@ -854,6 +849,8 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
continue;
ath12k_core_device_cleanup(ab);
}
+ ath12k_mac_unregister(ag);
+ ath12k_mac_destroy(ag);
}
static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
@@ -864,6 +861,23 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
lockdep_assert_held(&ag->mutex_lock);
+ /* Check if already registered or not, since same flow
+ * execute for HW restart case.
+ */
+ is_registered = test_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+
+ if (is_registered)
+ goto core_pdev_create;
+
+ ret = ath12k_mac_allocate(ag);
+ if (WARN_ON(ret))
+ return ret;
+
+ ret = ath12k_mac_register(ag);
+ if (WARN_ON(ret))
+ goto err_mac_alloc;
+
+core_pdev_create:
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
@@ -871,31 +885,6 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
mutex_lock(&ab->core_lock);
- /* Check if already registered or not, since same flow
- * execute for HW restart case.
- */
- is_registered = test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
-
- if (is_registered)
- goto core_pdev_create;
-
- ret = ath12k_mac_allocate(ab);
- if (ret) {
- ath12k_err(ab, "failed to create new hw device with mac80211 :%d\n",
- ret);
- mutex_unlock(&ab->core_lock);
- return ret;
- }
-
- ret = ath12k_mac_register(ab);
- if (ret) {
- ath12k_err(ab, "failed to register radio with mac80211: %d\n",
- ret);
- mutex_unlock(&ab->core_lock);
- goto err;
- }
-
-core_pdev_create:
ret = ath12k_core_pdev_create(ab);
if (ret) {
ath12k_err(ab, "failed to create pdev core %d\n", ret);
@@ -922,7 +911,10 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
err:
ath12k_core_hw_group_stop(ag);
+ return ret;
+err_mac_alloc:
+ ath12k_mac_destroy(ag);
return ret;
}
@@ -60,6 +60,7 @@
#define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ)
#define ATH12K_MAX_SOCS 3
+#define ATH12K_GROUP_MAX_RADIO (ATH12K_MAX_SOCS * MAX_RADIOS)
#define ATH12K_INVALID_GROUP_ID 0xFF
#define ATH12K_INVALID_DEVICE_ID 0xFF
@@ -755,6 +756,15 @@ struct ath12k_hw_group {
struct ath12k_base *ab[ATH12K_MAX_SOCS];
/* To synchronize group create, assign, start, stop */
struct mutex mutex_lock;
+
+ /* Holds information of wiphy (hw) registration.
+ *
+ * In Multi/Single Link Operation case, all pdevs are registered as
+ * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is
+ * registered as separate wiphys.
+ */
+ struct ath12k_hw *ah[MAX_RADIOS];
+ u8 num_hw;
};
/**
@@ -826,15 +836,6 @@ struct ath12k_base {
struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS];
- /* Holds information of wiphy (hw) registration.
- *
- * In Multi/Single Link Operation case, all pdevs are registered as
- * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is
- * registered as separate wiphys.
- */
- struct ath12k_hw *ah[MAX_RADIOS];
- u8 num_hw;
-
struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
unsigned long long free_vdev_map;
unsigned long long free_vdev_stats_id_map;
@@ -1090,18 +1091,18 @@ static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar)
static inline struct ath12k_hw *ath12k_ab_to_ah(struct ath12k_base *ab, int idx)
{
- return ab->ah[idx];
+ return ab->ag->ah[idx];
}
static inline void ath12k_ab_set_ah(struct ath12k_base *ab, int idx,
struct ath12k_hw *ah)
{
- ab->ah[idx] = ah;
+ ab->ag->ah[idx] = ah;
}
static inline int ath12k_get_num_hw(struct ath12k_base *ab)
{
- return ab->num_hw;
+ return ab->ag->num_hw;
}
static inline
@@ -8872,19 +8872,13 @@ static void ath12k_mac_setup(struct ath12k *ar)
clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
}
-int ath12k_mac_register(struct ath12k_base *ab)
+int ath12k_mac_register(struct ath12k_hw_group *ag)
{
+ struct ath12k_base *ab = ag->ab[0];
struct ath12k_hw *ah;
int i;
int ret;
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- return 0;
-
- /* Initialize channel counters frequency value in hertz */
- ab->cc_freq_hz = 320000;
- ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
-
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
ah = ath12k_ab_to_ah(ab, i);
@@ -8908,8 +8902,9 @@ int ath12k_mac_register(struct ath12k_base *ab)
return ret;
}
-void ath12k_mac_unregister(struct ath12k_base *ab)
+void ath12k_mac_unregister(struct ath12k_hw_group *ag)
{
+ struct ath12k_base *ab = ag->ab[0];
struct ath12k_hw *ah;
int i;
@@ -8970,18 +8965,24 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
return ah;
}
-void ath12k_mac_destroy(struct ath12k_base *ab)
+void ath12k_mac_destroy(struct ath12k_hw_group *ag)
{
struct ath12k_pdev *pdev;
- struct ath12k_hw *ah;
+ struct ath12k_base *ab = ag->ab[0];
int i;
+ struct ath12k_hw *ah;
- for (i = 0; i < ab->num_radios; i++) {
- pdev = &ab->pdevs[i];
- if (!pdev->ar)
+ for (i = 0; i < ag->num_devices; i++) {
+ ab = ag->ab[i];
+ if (!ab)
continue;
- pdev->ar = NULL;
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ if (!pdev->ar)
+ continue;
+ pdev->ar = NULL;
+ }
}
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
@@ -8994,20 +8995,46 @@ void ath12k_mac_destroy(struct ath12k_base *ab)
}
}
-int ath12k_mac_allocate(struct ath12k_base *ab)
+static void ath12k_set_device_defaults(struct ath12k_base *ab)
+{
+ /* Initialize channel counters frequency value in hertz */
+ ab->cc_freq_hz = 320000;
+ ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
+ ath12k_dp_pdev_pre_alloc(ab);
+}
+
+int ath12k_mac_allocate(struct ath12k_hw_group *ag)
{
struct ath12k_hw *ah;
+ struct ath12k_base *ab;
struct ath12k_pdev_map pdev_map[MAX_RADIOS];
int ret, i, j;
u8 radio_per_hw;
+ int mac_id, device_id;
+ int total_radio, num_hw;
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- return 0;
+ total_radio = 0;
+ for (i = 0; i < ag->num_devices; i++)
+ total_radio += ag->ab[i]->num_radios;
- ab->num_hw = ab->num_radios;
+ /* All pdev get combined and register as single wiphy based on
+ * hardware group which participate in multi-link operation else
+ * each pdev get register separately.
+ *
+ * Currently, registering as single pdevs.
+ */
radio_per_hw = 1;
+ num_hw = total_radio / radio_per_hw;
+
+ if (WARN_ON(num_hw >= ATH12K_GROUP_MAX_RADIO))
+ return -ENOSPC;
+
+ ag->num_hw = 0;
+ device_id = 0;
+ mac_id = 0;
+ for (i = 0; i < num_hw; i++) {
+ ab = ag->ab[device_id];
- for (i = 0; i < ath12k_get_num_hw(ab); i++) {
for (j = 0; j < radio_per_hw; j++) {
pdev_map[j].ab = ab;
pdev_map[j].pdev_idx = (i * radio_per_hw) + j;
@@ -9021,11 +9048,19 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
goto err;
}
- ath12k_ab_set_ah(ab, i, ah);
+ mac_id++;
+ /* If mac_id falls beyond the current device MACs then
+ * move to next device
+ */
+ if (mac_id >= ab->num_radios) {
+ device_id++;
+ mac_id = 0;
+ ath12k_set_device_defaults(ab);
+ }
+ ag->ah[i] = ah;
+ ag->num_hw++;
}
- ath12k_dp_pdev_pre_alloc(ab);
-
return 0;
err:
@@ -13,6 +13,7 @@
struct ath12k;
struct ath12k_base;
struct ath12k_hw;
+struct ath12k_hw_group;
struct ath12k_pdev_map;
struct ath12k_generic_iter {
@@ -50,10 +51,10 @@ enum ath12k_supported_bw {
extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
-void ath12k_mac_destroy(struct ath12k_base *ab);
-void ath12k_mac_unregister(struct ath12k_base *ab);
-int ath12k_mac_register(struct ath12k_base *ab);
-int ath12k_mac_allocate(struct ath12k_base *ab);
+void ath12k_mac_destroy(struct ath12k_hw_group *ag);
+void ath12k_mac_unregister(struct ath12k_hw_group *ag);
+int ath12k_mac_register(struct ath12k_hw_group *ag);
+int ath12k_mac_allocate(struct ath12k_hw_group *ag);
int ath12k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx,
u16 *rate);
u8 ath12k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,