Currently, TX power is reported on interface/wdev level as
part of NL80211_CMD_GET_INTERFACE. With MLO, Multiple links
can be part of an interface/wdev and hence its necessary to
report the TX power of each link.
Add support to send tx power for all valid links of an MLD as
part of NL80211_CMD_GET_INTERFACE request.
As far as userspace is concerned, there is no behavioral change
for Non-ML Interfaces. For ML interfaces, userspace should fetch
TX power that is nested inside NL80211_ATTR_MLO_LINKS, similar to
how channel info(NL80211_ATTR_WIPHY_FREQ) is fetched.
Co-developed-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
Signed-off-by: Aaradhana Sahu <quic_aarasahu@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Link: https://patch.msgid.link/20241125083217.216095-2-quic_ramess@quicinc.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
 
 static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
                                       struct wireless_dev *wdev,
+                                      unsigned int link_id,
                                       int *dbm)
 {
        struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
 
 
 static s32
 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
-                           s32 *dbm)
+                           unsigned int link_id, s32 *dbm)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev);
 
 static int
 mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy,
                              struct wireless_dev *wdev,
-                             int *dbm)
+                             unsigned int link_id, int *dbm)
 {
        struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
        struct mwifiex_private *priv = mwifiex_get_priv(adapter,
 
 }
 
 static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
-                       int *dbm)
+                       unsigned int link_id, int *dbm)
 {
        int ret;
        struct wilc_vif *vif = netdev_priv(wdev->netdev);
 
 }
 
 static int qtnf_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
-                            int *dbm)
+                            unsigned int link_id, int *dbm)
 {
        struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
        int ret;
 
 }
 
 static int cfg80211_rtw_get_txpower(struct wiphy *wiphy,
-                                   struct wireless_dev *wdev, int *dbm)
+                                   struct wireless_dev *wdev,
+                                   unsigned int link_id, int *dbm)
 {
        *dbm = (12);
 
 
        int     (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
                                enum nl80211_tx_power_setting type, int mbm);
        int     (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
-                               int *dbm);
+                               unsigned int link_id, int *dbm);
 
        void    (*rfkill_poll)(struct wiphy *wiphy);
 
 
 
 static int ieee80211_get_tx_power(struct wiphy *wiphy,
                                  struct wireless_dev *wdev,
+                                 unsigned int link_id,
                                  int *dbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
 
                        goto nla_put_failure;
        }
 
-       if (rdev->ops->get_tx_power) {
+       if (rdev->ops->get_tx_power && !wdev->valid_links) {
                int dbm, ret;
 
-               ret = rdev_get_tx_power(rdev, wdev, &dbm);
+               ret = rdev_get_tx_power(rdev, wdev, 0, &dbm);
                if (ret == 0 &&
                    nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
                                DBM_TO_MBM(dbm)))
                        if (ret == 0 && nl80211_send_chandef(msg, &chandef))
                                goto nla_put_failure;
 
+                       if (rdev->ops->get_tx_power) {
+                               int dbm, ret;
+
+                               ret = rdev_get_tx_power(rdev, wdev, link_id, &dbm);
+                               if (ret == 0 &&
+                                   nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+                                               DBM_TO_MBM(dbm)))
+                                       goto nla_put_failure;
+                       }
                        nla_nest_end(msg, link);
                }
 
 
 }
 
 static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
-                                   struct wireless_dev *wdev, int *dbm)
+                                   struct wireless_dev *wdev, unsigned int link_id,
+                                   int *dbm)
 {
        int ret;
-       trace_rdev_get_tx_power(&rdev->wiphy, wdev);
-       ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);
+       trace_rdev_get_tx_power(&rdev->wiphy, wdev, link_id);
+       ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, link_id, dbm);
        trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
        return ret;
 }
 
                  WIPHY_PR_ARG, __entry->changed)
 );
 
-DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power,
-       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
-       TP_ARGS(wiphy, wdev)
+DECLARE_EVENT_CLASS(wiphy_wdev_link_evt,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                unsigned int link_id),
+       TP_ARGS(wiphy, wdev, link_id),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               WDEV_ENTRY
+               __field(unsigned int, link_id)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               WDEV_ASSIGN;
+               __entry->link_id = link_id;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
+);
+
+DEFINE_EVENT(wiphy_wdev_link_evt, rdev_get_tx_power,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                unsigned int link_id),
+       TP_ARGS(wiphy, wdev, link_id)
 );
 
 TRACE_EVENT(rdev_set_tx_power,
        TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", noack_map: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
 );
-
-DECLARE_EVENT_CLASS(wiphy_wdev_link_evt,
-       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
-                unsigned int link_id),
-       TP_ARGS(wiphy, wdev, link_id),
-       TP_STRUCT__entry(
-               WIPHY_ENTRY
-               WDEV_ENTRY
-               __field(unsigned int, link_id)
-       ),
-       TP_fast_assign(
-               WIPHY_ASSIGN;
-               WDEV_ASSIGN;
-               __entry->link_id = link_id;
-       ),
-       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u",
-                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
-);
-
 DEFINE_EVENT(wiphy_wdev_link_evt, rdev_get_channel,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
                 unsigned int link_id),
 
                return -EOPNOTSUPP;
 
        scoped_guard(wiphy, &rdev->wiphy) {
-               err = rdev_get_tx_power(rdev, wdev, &val);
+               err = rdev_get_tx_power(rdev, wdev, 0, &val);
        }
        if (err)
                return err;