|
@@ -26407,6 +26407,173 @@ wlan_hdd_cfg80211_del_intf_link(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_TID_LINK_MAP_SUPPORT)
|
|
|
+#define MAX_T2LM_INFO 2
|
|
|
+
|
|
|
+static void wlan_hdd_print_t2lm_info(struct cfg80211_mlo_tid_map *map)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ hdd_debug("T2LM info send to userspace");
|
|
|
+ hdd_debug("default mapping: %d", map->default_map);
|
|
|
+ for (i = 0; i < T2LM_MAX_NUM_TIDS; i++)
|
|
|
+ hdd_debug("TID[%d]: Downlink: %d Uplink: %d",
|
|
|
+ i, map->t2lmap[i].downlink, map->t2lmap[i].uplink);
|
|
|
+}
|
|
|
+
|
|
|
+static void wlan_hdd_fill_bidir_t2lm(struct wlan_t2lm_info *t2lm,
|
|
|
+ struct tid_link_map *t2lmap)
|
|
|
+{
|
|
|
+ uint8_t tid;
|
|
|
+
|
|
|
+ for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) {
|
|
|
+ t2lmap[tid].downlink = t2lm->ieee_link_map_tid[tid];
|
|
|
+ t2lmap[tid].uplink = t2lm->ieee_link_map_tid[tid];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void wlan_hdd_fill_dldir_t2lm(struct wlan_t2lm_info *t2lm,
|
|
|
+ struct tid_link_map *t2lmap)
|
|
|
+{
|
|
|
+ uint8_t tid;
|
|
|
+
|
|
|
+ for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++)
|
|
|
+ t2lmap[tid].downlink = t2lm->ieee_link_map_tid[tid];
|
|
|
+}
|
|
|
+
|
|
|
+static void wlan_hdd_fill_uldir_t2lm(struct wlan_t2lm_info *t2lm,
|
|
|
+ struct tid_link_map *t2lmap)
|
|
|
+{
|
|
|
+ uint8_t tid;
|
|
|
+
|
|
|
+ for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++)
|
|
|
+ t2lmap[tid].uplink = t2lm->ieee_link_map_tid[tid];
|
|
|
+}
|
|
|
+
|
|
|
+static void wlan_hdd_fill_map(struct wlan_t2lm_info *t2lm,
|
|
|
+ struct cfg80211_mlo_tid_map *map, bool *found)
|
|
|
+{
|
|
|
+ if (t2lm->direction == WLAN_T2LM_INVALID_DIRECTION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ map->default_map = t2lm->default_link_mapping;
|
|
|
+
|
|
|
+ switch (t2lm->direction) {
|
|
|
+ case WLAN_T2LM_BIDI_DIRECTION:
|
|
|
+ wlan_hdd_fill_bidir_t2lm(t2lm, map->t2lmap);
|
|
|
+ *found = true;
|
|
|
+ break;
|
|
|
+ case WLAN_T2LM_DL_DIRECTION:
|
|
|
+ wlan_hdd_fill_dldir_t2lm(t2lm, map->t2lmap);
|
|
|
+ *found = true;
|
|
|
+ break;
|
|
|
+ case WLAN_T2LM_UL_DIRECTION:
|
|
|
+ wlan_hdd_fill_uldir_t2lm(t2lm, map->t2lmap);
|
|
|
+ *found = true;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int wlan_hdd_fill_t2lm_response(struct wlan_t2lm_info *t2lm,
|
|
|
+ struct cfg80211_mlo_tid_map *map)
|
|
|
+{
|
|
|
+ uint8_t i;
|
|
|
+ bool found = false;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_T2LM_INFO; i++)
|
|
|
+ wlan_hdd_fill_map(&t2lm[i], map, &found);
|
|
|
+
|
|
|
+ if (!found) {
|
|
|
+ hdd_err("T2LM info not found");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ wlan_hdd_print_t2lm_info(map);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+__wlan_hdd_cfg80211_get_t2lm_mapping_status(struct wiphy *wiphy,
|
|
|
+ struct net_device *net_dev,
|
|
|
+ struct cfg80211_mlo_tid_map *map)
|
|
|
+{
|
|
|
+ struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
|
|
|
+ struct wlan_objmgr_vdev *vdev;
|
|
|
+ struct wlan_t2lm_info *t2lm = NULL;
|
|
|
+ int ret, i;
|
|
|
+
|
|
|
+ hdd_enter();
|
|
|
+
|
|
|
+ if (hdd_validate_adapter(adapter))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_ID);
|
|
|
+ if (!vdev) {
|
|
|
+ hdd_err("Vdev is null return");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!wlan_cm_is_vdev_connected(vdev)) {
|
|
|
+ hdd_err("Not associated!, vdev %d", wlan_vdev_get_id(vdev));
|
|
|
+ ret = -EAGAIN;
|
|
|
+ goto vdev_release;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) {
|
|
|
+ hdd_err("failed due to non-ML connection");
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto vdev_release;
|
|
|
+ }
|
|
|
+
|
|
|
+ t2lm = qdf_mem_malloc(sizeof(*t2lm) * MAX_T2LM_INFO);
|
|
|
+ if (!t2lm) {
|
|
|
+ hdd_err("mem alloc failed for t2lm");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto vdev_release;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_T2LM_INFO; i++)
|
|
|
+ t2lm[i].direction = WLAN_T2LM_INVALID_DIRECTION;
|
|
|
+
|
|
|
+ ret = wlan_get_t2lm_mapping_status(vdev, t2lm);
|
|
|
+ if (ret != 0)
|
|
|
+ goto t2lm_free;
|
|
|
+
|
|
|
+ ret = wlan_hdd_fill_t2lm_response(t2lm, map);
|
|
|
+
|
|
|
+t2lm_free:
|
|
|
+ qdf_mem_free(t2lm);
|
|
|
+vdev_release:
|
|
|
+ hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
|
|
|
+
|
|
|
+ hdd_exit();
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+wlan_hdd_cfg80211_get_t2lm_mapping_status(struct wiphy *wiphy,
|
|
|
+ struct net_device *net_dev,
|
|
|
+ struct cfg80211_mlo_tid_map *map)
|
|
|
+{
|
|
|
+ int errno;
|
|
|
+ struct osif_vdev_sync *vdev_sync;
|
|
|
+
|
|
|
+ errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
|
|
|
+ if (errno)
|
|
|
+ return errno;
|
|
|
+
|
|
|
+ errno = __wlan_hdd_cfg80211_get_t2lm_mapping_status(wiphy, net_dev, map);
|
|
|
+
|
|
|
+ osif_vdev_sync_op_stop(vdev_sync);
|
|
|
+
|
|
|
+ return errno;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
|
|
|
.add_virtual_intf = wlan_hdd_add_virtual_intf,
|
|
|
.del_virtual_intf = wlan_hdd_del_virtual_intf,
|
|
@@ -26508,4 +26675,7 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
|
|
|
.add_intf_link = wlan_hdd_cfg80211_add_intf_link,
|
|
|
.del_intf_link = wlan_hdd_cfg80211_del_intf_link,
|
|
|
#endif
|
|
|
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_TID_LINK_MAP_SUPPORT)
|
|
|
+ .get_link_tid_map_status = wlan_hdd_cfg80211_get_t2lm_mapping_status,
|
|
|
+#endif
|
|
|
};
|