@@ -859,8 +859,6 @@ static void ath12k_core_device_cleanup(struct ath12k_base *ab)
ath12k_hif_irq_disable(ab);
ath12k_core_pdev_destroy(ab);
- ath12k_mac_unregister(ab);
- ath12k_mac_destroy(ab);
mutex_unlock(&ab->core_lock);
}
@@ -878,15 +876,38 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
continue;
ath12k_core_device_cleanup(ab);
}
+
+ clear_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+ ath12k_mac_unregister(ag);
+ ath12k_mac_destroy(ag);
}
static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
{
struct ath12k_base *ab;
- int ret, i;
+ int ret, is_registered, i;
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;
+
+ set_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
+
+core_pdev_create:
for (i = 0; i < ag->num_devices; i++) {
ab = ag->ab[i];
if (!ab)
@@ -894,29 +915,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.
- */
- if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
- 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);
@@ -939,7 +937,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;
}
@@ -62,6 +62,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
@@ -202,6 +203,10 @@ enum ath12k_scan_state {
ATH12K_SCAN_ABORTING,
};
+enum ath12k_hw_group_flags {
+ ATH12K_GROUP_FLAG_REGISTERED,
+};
+
enum ath12k_dev_flags {
ATH12K_CAC_RUNNING,
ATH12K_FLAG_CRASH_FLUSH,
@@ -763,6 +768,15 @@ struct ath12k_hw_group {
* lock would be helpful
*/
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[ATH12K_GROUP_MAX_RADIO];
+ u8 num_hw;
};
/**
@@ -839,15 +853,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;
@@ -1102,18 +1107,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
@@ -983,21 +983,14 @@ void ath12k_dp_pdev_free(struct ath12k_base *ab)
ath12k_dp_rx_pdev_free(ab, i);
}
-void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab)
+void ath12k_dp_pdev_pre_alloc(struct ath12k *ar)
{
- struct ath12k *ar;
- struct ath12k_pdev_dp *dp;
- int i;
+ struct ath12k_pdev_dp *dp = &ar->dp;
- for (i = 0; i < ab->num_radios; i++) {
- ar = ab->pdevs[i].ar;
- dp = &ar->dp;
- dp->mac_id = i;
- atomic_set(&dp->num_tx_pending, 0);
- init_waitqueue_head(&dp->tx_empty_waitq);
-
- /* TODO: Add any RXDMA setup required per pdev */
- }
+ dp->mac_id = ar->pdev_idx;
+ atomic_set(&dp->num_tx_pending, 0);
+ init_waitqueue_head(&dp->tx_empty_waitq);
+ /* TODO: Add any RXDMA setup required per pdev */
}
bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab)
@@ -1816,7 +1816,7 @@ void ath12k_dp_free(struct ath12k_base *ab);
int ath12k_dp_alloc(struct ath12k_base *ab);
void ath12k_dp_cc_config(struct ath12k_base *ab);
int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
-void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab);
+void ath12k_dp_pdev_pre_alloc(struct ath12k *ar);
void ath12k_dp_pdev_free(struct ath12k_base *ab);
int ath12k_dp_tx_htt_srng_setup(struct ath12k_base *ab, u32 ring_id,
int mac_id, enum hal_ring_type ring_type);
@@ -9332,19 +9332,13 @@ static void ath12k_mac_setup(struct ath12k *ar)
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
}
-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);
@@ -9368,8 +9362,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;
@@ -9388,12 +9383,13 @@ static void ath12k_mac_hw_destroy(struct ath12k_hw *ah)
ieee80211_free_hw(ah->hw);
}
-static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
+static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
struct ath12k_pdev_map *pdev_map,
u8 num_pdev_map)
{
struct ieee80211_hw *hw;
struct ath12k *ar;
+ struct ath12k_base *ab;
struct ath12k_pdev *pdev;
struct ath12k_hw *ah;
int i;
@@ -9424,23 +9420,30 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
pdev->ar = ar;
ath12k_mac_setup(ar);
+ ath12k_dp_pdev_pre_alloc(ar);
}
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_base *ab = ag->ab[0];
+ int i, j;
struct ath12k_hw *ah;
- int i;
- 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 (j = 0; j < ab->num_radios; j++) {
+ pdev = &ab->pdevs[j];
+ if (!pdev->ar)
+ continue;
+ pdev->ar = NULL;
+ }
}
for (i = 0; i < ath12k_get_num_hw(ab); i++) {
@@ -9453,26 +9456,60 @@ void ath12k_mac_destroy(struct ath12k_base *ab)
}
}
-int ath12k_mac_allocate(struct ath12k_base *ab)
+static void ath12k_mac_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;
+}
+
+int ath12k_mac_allocate(struct ath12k_hw_group *ag)
{
struct ath12k_hw *ah;
- struct ath12k_pdev_map pdev_map[MAX_RADIOS];
+ struct ath12k_base *ab;
+ struct ath12k_pdev_map pdev_map[ATH12K_GROUP_MAX_RADIO];
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;
- for (i = 0; i < ath12k_get_num_hw(ab); i++) {
+ 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++) {
for (j = 0; j < radio_per_hw; j++) {
+ ab = ag->ab[device_id];
pdev_map[j].ab = ab;
- pdev_map[j].pdev_idx = (i * radio_per_hw) + j;
+ pdev_map[j].pdev_idx = mac_id;
+ mac_id++;
+
+ /* If mac_id falls beyond the current device MACs then
+ * move to next device
+ */
+ if (mac_id >= ab->num_radios) {
+ mac_id = 0;
+ device_id++;
+ ath12k_mac_set_device_defaults(ab);
+ }
}
- ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw);
+ ah = ath12k_mac_hw_allocate(ag, pdev_map, radio_per_hw);
if (!ah) {
ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n",
i);
@@ -9480,11 +9517,10 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
goto err;
}
- ath12k_ab_set_ah(ab, i, ah);
+ ag->ah[i] = ah;
+ ag->num_hw++;
}
- ath12k_dp_pdev_pre_alloc(ab);
-
return 0;
err:
@@ -14,6 +14,7 @@
struct ath12k;
struct ath12k_base;
struct ath12k_hw;
+struct ath12k_hw_group;
struct ath12k_pdev_map;
struct ath12k_generic_iter {
@@ -51,10 +52,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,