@@ -1403,6 +1403,7 @@ ath12k_core_hw_group_alloc(u8 id, u8 max_devices)
ag->num_devices = max_devices;
list_add(&ag->list, &ath12k_hw_group_list);
mutex_init(&ag->mutex_lock);
+ ag->mlo_capable = false;
return ag;
}
@@ -1417,23 +1418,94 @@ static void ath12k_core_hw_group_free(struct ath12k_hw_group *ag)
mutex_unlock(&ath12k_ag_list_lock);
}
+/* This function needs to be used only when dt has multi chip grouping information */
+static struct ath12k_hw_group *ath12k_core_hw_group_find_by_id(u8 group_id)
+{
+ struct ath12k_hw_group *ag;
+
+ /* group ids will be unique only for multi chip group */
+ list_for_each_entry(ag, &ath12k_hw_group_list, list) {
+ if (group_id == ag->id && ag->num_devices > 1)
+ return ag;
+ }
+
+ return NULL;
+}
+
static struct ath12k_hw_group *ath12k_core_assign_hw_group(struct ath12k_base *ab)
{
struct ath12k_hw_group *ag;
- u32 group_id = ATH12K_INVALID_GROUP_ID;
+ u32 group_id = ATH12K_INVALID_GROUP_ID, num_devices;
+ struct device *dev = ab->dev;
+ struct device_node *mlo;
lockdep_assert_held(&ath12k_ag_list_lock);
- /* The grouping of multiple devices will be done based on device tree file.
- * TODO: device tree file parsing to know about the devices involved in group.
- *
- * The platforms that do not have any valid group information would have each
- * device to be part of its own invalid group.
+ /* The grouping of multiple devices will be done based on device
+ * tree file.
*
- * Currently, we are not parsing any device tree information and hence, grouping
- * of multiple devices is not involved. Thus, single device is added to device
- * group.
+ * The platforms that do not have any valid group information would
+ * have each device to be part of its own invalid group.
*/
+ mlo = of_get_child_by_name(dev->of_node, "wsi");
+ if (!mlo) {
+ goto invalid_group;
+ } else {
+ if (of_property_read_u32(mlo, "qcom,wsi-group-id", &group_id)) {
+ ath12k_err(ab, "wsi-group-id not found\n");
+ goto invalid_group;
+ }
+ }
+
+ if (of_property_read_u32(mlo, "qcom,wsi-num-devices", &num_devices)) {
+ ath12k_err(ab, "wsi-num-devices not found\n");
+ group_id = ATH12K_INVALID_GROUP_ID;
+ goto invalid_group;
+ }
+
+ if (num_devices > ATH12K_MAX_SOCS) {
+ ath12k_warn(ab, "num_devices advertised %d is more than limit %d\n",
+ num_devices, ATH12K_MAX_SOCS);
+ group_id = ATH12K_INVALID_GROUP_ID;
+ goto invalid_group;
+ }
+
+ if (of_property_read_u32(mlo, "qcom,wsi-index", &ab->wsi_index)) {
+ ath12k_err(ab, "qcom,wsi-index not found\n");
+ group_id = ATH12K_INVALID_GROUP_ID;
+ goto invalid_group;
+ }
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "WSI info: group-id: %d, num-devices: %d, index: %d",
+ group_id, num_devices, ab->wsi_index);
+
+ /* Currently only one group of multiple devices are supported,
+ * since we use group id ATH12K_INVALID_GROUP_ID for single
+ * device group which didn't have dt entry, there could be many
+ * groups with same group id, i.e ATH12K_INVALID_GROUP_ID. So
+ * default group id of ATH12K_INVALID_GROUP_ID combined with
+ * num devices in ath12k_hw_group determines if the group is
+ * multi device or single device group
+ */
+ ag = ath12k_core_hw_group_find_by_id(group_id);
+ if (!ag) {
+ ag = ath12k_core_hw_group_alloc(group_id, num_devices);
+ if (!ag) {
+ ath12k_warn(ab, "unable to create new hw group\n");
+ return NULL;
+ }
+ goto exit;
+ } else if (test_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags)) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "group id %d in unregister state\n",
+ ag->id);
+ group_id = ATH12K_INVALID_GROUP_ID;
+ goto invalid_group;
+ } else {
+ goto exit;
+ }
+
+invalid_group:
ag = ath12k_core_hw_group_alloc(group_id, 1);
if (!ag) {
ath12k_warn(ab, "unable to create new hw group\n");
@@ -1441,10 +1513,16 @@ static struct ath12k_hw_group *ath12k_core_assign_hw_group(struct ath12k_base *a
}
ath12k_dbg(ab, ATH12K_DBG_BOOT, "Single device is added to hardware group\n");
+exit:
+ if (ag->num_probed >= ag->num_devices) {
+ ath12k_warn(ab, "unable to add new device to group, max limit reached\n");
+ group_id = ATH12K_INVALID_GROUP_ID;
+ goto invalid_group;
+ }
+
ab->device_id = ag->num_probed++;
ag->ab[ab->device_id] = ab;
ab->ag = ag;
- ag->mlo_capable = false;
return ag;
}
@@ -1511,6 +1589,14 @@ static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
return;
mutex_lock(&ag->mutex_lock);
+
+ if (test_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags)) {
+ mutex_unlock(&ag->mutex_lock);
+ return;
+ }
+
+ set_bit(ATH12K_GROUP_FLAG_UNREGISTER, &ag->flags);
+
ath12k_core_hw_group_stop(ag);
for (i = 0; i < ag->num_devices; i++) {
@@ -211,6 +211,7 @@ enum ath12k_scan_state {
enum ath12k_hw_group_flags {
ATH12K_GROUP_FLAG_REGISTERED,
+ ATH12K_GROUP_FLAG_UNREGISTER,
};
enum ath12k_dev_flags {
@@ -1026,6 +1027,7 @@ struct ath12k_base {
struct notifier_block panic_nb;
struct ath12k_hw_group *ag;
+ u32 wsi_index;
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));