From 0756e913fc020ab3640bcfe7de55b8024ecb88ad Mon Sep 17 00:00:00 2001 From: Mikhail Karpenko Date: Wed, 13 Nov 2019 11:06:59 +0000 Subject: qtnfmac: add support for getting/setting transmit power Add new command for getting/setting current transmit power and propagate requests from user space to firmware. Signed-off-by: Mikhail Karpenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 41 ++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.c | 65 +++++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.h | 3 ++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 42 +++++++++++++++ 4 files changed, 151 insertions(+) (limited to 'drivers/net/wireless/quantenna') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index d90016125dfc..aa0ed0f2b973 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -897,6 +897,45 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return ret; } +static int qtnf_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + int ret; + + ret = qtnf_cmd_get_tx_power(vif, dbm); + if (ret) + pr_err("MAC%u: failed to get Tx power\n", vif->mac->macid); + + return ret; +} + +static int qtnf_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + struct qtnf_vif *vif; + int ret; + + if (wdev) { + vif = qtnf_netdev_get_priv(wdev->netdev); + } else { + struct qtnf_wmac *mac = wiphy_priv(wiphy); + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", + mac->macid); + return -EFAULT; + } + } + + ret = qtnf_cmd_set_tx_power(vif, type, mbm); + if (ret) + pr_err("MAC%u: failed to set Tx power\n", vif->mac->macid); + + return ret; +} + #ifdef CONFIG_PM static int qtnf_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { @@ -991,6 +1030,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = { .start_radar_detection = qtnf_start_radar_detection, .set_mac_acl = qtnf_set_mac_acl, .set_power_mgmt = qtnf_set_power_mgmt, + .get_tx_power = qtnf_get_tx_power, + .set_tx_power = qtnf_set_tx_power, #ifdef CONFIG_PM .suspend = qtnf_suspend, .resume = qtnf_resume, diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c0c32805fb8d..61bda34e2ac2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2643,6 +2643,71 @@ out: return ret; } +int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm) +{ + struct qtnf_bus *bus = vif->mac->bus; + const struct qlink_resp_txpwr *resp; + struct sk_buff *resp_skb = NULL; + struct qlink_cmd_txpwr *cmd; + struct sk_buff *cmd_skb; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_TXPWR, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; + cmd->op_type = QLINK_TXPWR_GET; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, + sizeof(*resp), NULL); + if (ret) + goto out; + + resp = (const struct qlink_resp_txpwr *)resp_skb->data; + *dbm = MBM_TO_DBM(le32_to_cpu(resp->txpwr)); + +out: + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, + enum nl80211_tx_power_setting type, int mbm) +{ + struct qtnf_bus *bus = vif->mac->bus; + const struct qlink_resp_txpwr *resp; + struct sk_buff *resp_skb = NULL; + struct qlink_cmd_txpwr *cmd; + struct sk_buff *cmd_skb; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_TXPWR, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; + cmd->op_type = QLINK_TXPWR_SET; + cmd->txpwr_setting = type; + cmd->txpwr = cpu_to_le32(mbm); + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, + sizeof(*resp), NULL); + + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, const struct cfg80211_wowlan *wowl) { diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index 88d7a3cd90d2..e0de65261213 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -70,6 +70,9 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, const struct cfg80211_acl_data *params); int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout); +int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm); +int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, + enum nl80211_tx_power_setting type, int mbm); int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, const struct cfg80211_wowlan *wowl); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index ac1ebe4bb580..59c69c0a6e06 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -217,6 +217,8 @@ struct qlink_sta_info_state { * command is supported only if device reports QLINK_HW_SUPPORTS_REG_UPDATE * capability. * @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel. + * @QLINK_CMD_TXPWR: get or set current channel transmit power for + * the specified MAC. */ enum qlink_cmd_type { QLINK_CMD_FW_INIT = 0x0001, @@ -254,6 +256,7 @@ enum qlink_cmd_type { QLINK_CMD_PM_SET = 0x0062, QLINK_CMD_WOWLAN_SET = 0x0063, QLINK_CMD_EXTERNAL_AUTH = 0x0066, + QLINK_CMD_TXPWR = 0x0067, }; /** @@ -718,6 +721,32 @@ struct qlink_cmd_pm_set { u8 pm_mode; } __packed; +/** + * enum qlink_txpwr_op - transmit power operation type + * @QLINK_TXPWR_SET: set tx power + * @QLINK_TXPWR_GET: get current tx power setting + */ +enum qlink_txpwr_op { + QLINK_TXPWR_SET, + QLINK_TXPWR_GET +}; + +/** + * struct qlink_cmd_txpwr - get or set current transmit power + * + * @txpwr: new transmit power setting, in mBm + * @txpwr_setting: transmit power setting type, one of + * &enum nl80211_tx_power_setting + * @op_type: type of operation, one of &enum qlink_txpwr_op + */ +struct qlink_cmd_txpwr { + struct qlink_cmd chdr; + __le32 txpwr; + u8 txpwr_setting; + u8 op_type; + u8 rsvd[2]; +} __packed; + /** * enum qlink_wowlan_trigger * @@ -944,6 +973,19 @@ struct qlink_resp_channel_get { struct qlink_chandef chan; } __packed; +/** + * struct qlink_resp_txpwr - response for QLINK_CMD_TXPWR command + * + * This response is intended for QLINK_TXPWR_GET operation and does not + * contain any meaningful information in case of QLINK_TXPWR_SET operation. + * + * @txpwr: current transmit power setting, in mBm + */ +struct qlink_resp_txpwr { + struct qlink_resp rhdr; + __le32 txpwr; +} __packed; + /* QLINK Events messages related definitions */ -- cgit v1.2.3