1 /*
2 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /**
18 * DOC: wlan_hdd_txq_flush.c
19 *
20 * WLAN Host Device Driver Peer TX queue flush configuration APIs implementation
21 *
22 */
23
24 #include "osif_sync.h"
25 #include <wlan_hdd_includes.h>
26 #include "wlan_hdd_main.h"
27 #include "wlan_hdd_peer_txq_flush.h"
28 #include <qca_vendor.h>
29 #include "wlan_hdd_object_manager.h"
30
31 const struct nla_policy
32 peer_txq_flush_policy[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1] = {
33 [QCA_WLAN_VENDOR_ATTR_PEER_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
34 [QCA_WLAN_VENDOR_ATTR_AC] = { .type = NLA_U8 },
35 [QCA_WLAN_VENDOR_ATTR_TID_MASK] = { .type = NLA_U32 },
36 [QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY] = { .type = NLA_U32 },
37 };
38
39 /**
40 * map_txq_policy() - Map NL flush policy attribute value to DP
41 * @policy: NL flush policy attribute value
42 *
43 * This function maps NL flush policy attribute value to DP
44 *
45 * Return: Valid DP policy value, else invalid
46 */
47 static enum cdp_peer_txq_flush_policy
map_txq_policy(enum qca_wlan_vendor_flush_pending_policy policy)48 map_txq_policy(enum qca_wlan_vendor_flush_pending_policy policy)
49 {
50 switch (policy) {
51 case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_NONE:
52 return CDP_PEER_TXQ_FLUSH_POLICY_NONE;
53 case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_IMMEDIATE:
54 return CDP_PEER_TXQ_FLUSH_POLICY_IMMEDIATE;
55 case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_TWT_SP_END:
56 return CDP_PEER_TXQ_FLUSH_POLICY_TWT_SP_END;
57 default:
58 return CDP_PEER_TXQ_FLUSH_POLICY_INVALID;
59 }
60 }
61
62 /**
63 * hdd_peer_txq_flush_config() - Propagate txq flush config to DP
64 * @adapter: Pointer to HDD adapter structure
65 * @tb: NL attributes
66 *
67 * This function maps NL to DP attributes and proagates the configuration
68 *
69 * Return: 0 on success, negative errno on failure
70 */
hdd_peer_txq_flush_config(struct hdd_adapter * adapter,struct nlattr * tb[])71 static int hdd_peer_txq_flush_config(struct hdd_adapter *adapter,
72 struct nlattr *tb[])
73 {
74 void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC);
75 uint8_t addr[QDF_MAC_ADDR_SIZE];
76 uint32_t ac, tid, cmd_id;
77 enum qca_wlan_vendor_flush_pending_policy txq_policy;
78 enum cdp_peer_txq_flush_policy cdp_policy;
79
80 if (!tb || !dp_soc) {
81 hdd_err("Invalid attributes");
82 return -EINVAL;
83 }
84
85 nla_memcpy(addr, tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR], QDF_MAC_ADDR_SIZE);
86
87 if (tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]) {
88 tid = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]);
89
90 cmd_id = QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY;
91 if (!tb[cmd_id]) {
92 hdd_err("Flush policy not provided");
93 return -EINVAL;
94 }
95 txq_policy = nla_get_u32(tb[cmd_id]);
96 cdp_policy = map_txq_policy(txq_policy);
97 if (cdp_policy == CDP_PEER_TXQ_FLUSH_POLICY_INVALID) {
98 hdd_err("Invalid dp flush policy %d", txq_policy);
99 return -EINVAL;
100 }
101 ac = 0;
102 } else if (tb[QCA_WLAN_VENDOR_ATTR_AC]) {
103 ac = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_AC]);
104 cdp_policy = CDP_PEER_TXQ_FLUSH_POLICY_INVALID;
105 tid = 0;
106 } else {
107 hdd_err("No ac/tid mask");
108 return -EINVAL;
109 }
110
111 return cdp_set_peer_txq_flush_config(dp_soc, adapter->deflink->vdev_id,
112 addr, ac, tid, cdp_policy);
113 }
114
115 /**
116 * __wlan_hdd_cfg80211_peer_txq_flush_config() - flush peer txq config
117 * @wiphy: Pointer to wireless phy
118 * @wdev: Pointer to wireless device
119 * @data: Pointer to data
120 * @data_len: Length of @data
121 *
122 * This function is used to flush peer pending packets using vendor commands
123 *
124 * Return: 0 on success, negative errno on failure
125 */
126 static int
__wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)127 __wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy *wiphy,
128 struct wireless_dev *wdev,
129 const void *data, int data_len)
130 {
131 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
132 struct net_device *dev = wdev->netdev;
133 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
134 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1];
135 int ret;
136
137 hdd_enter();
138
139 ret = wlan_hdd_validate_context(hdd_ctx);
140 if (ret)
141 return ret;
142
143 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
144 hdd_err("Not allowed in FTM mode");
145 return -EINVAL;
146 }
147
148 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX,
149 data, data_len, peer_txq_flush_policy)) {
150 hdd_err("Invalid attributes");
151 return -EINVAL;
152 }
153
154 if (!tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR]) {
155 hdd_err("Peer mac not provided");
156 return -EINVAL;
157 }
158
159 if (!tb[QCA_WLAN_VENDOR_ATTR_AC] &&
160 !tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]) {
161 hdd_err("AC/TID mask not provided");
162 return -EINVAL;
163 }
164
165 ret = hdd_peer_txq_flush_config(adapter, tb);
166
167 hdd_exit();
168
169 return ret;
170 }
171
wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * attr,int attr_len)172 int wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy *wiphy,
173 struct wireless_dev *wdev,
174 const void *attr,
175 int attr_len)
176 {
177 int ret;
178 struct osif_vdev_sync *vdev_sync;
179
180 ret = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
181 if (ret)
182 return ret;
183
184 ret = __wlan_hdd_cfg80211_peer_txq_flush_config(wiphy, wdev,
185 attr, attr_len);
186
187 osif_vdev_sync_op_stop(vdev_sync);
188
189 return ret;
190 }
191