1 /*
2 * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved.
3 *
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: offload lmac interface APIs definitions for FTM
22 */
23
24 #include <qdf_status.h>
25 #include <target_if_ftm.h>
26 #include <wmi_unified_priv.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include <target_if.h>
29 #include <wlan_lmac_if_def.h>
30 #include <wlan_ftm_ucfg_api.h>
31
32 static inline struct wlan_lmac_if_ftm_rx_ops *
target_if_ftm_get_rx_ops(struct wlan_objmgr_psoc * psoc)33 target_if_ftm_get_rx_ops(struct wlan_objmgr_psoc *psoc)
34 {
35 struct wlan_lmac_if_rx_ops *rx_ops;
36
37 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
38 if (!rx_ops) {
39 ftm_err("rx_ops is NULL");
40 return NULL;
41 }
42
43 return &rx_ops->ftm_rx_ops;
44 }
45
46 static int
target_if_ftm_process_utf_event(ol_scn_t sc,uint8_t * event_buf,uint32_t len)47 target_if_ftm_process_utf_event(ol_scn_t sc, uint8_t *event_buf, uint32_t len)
48 {
49 struct wlan_objmgr_psoc *psoc;
50 struct wlan_objmgr_pdev *pdev;
51 struct wmi_host_pdev_utf_event event;
52 struct wlan_lmac_if_ftm_rx_ops *ftm_rx_ops;
53 QDF_STATUS status = QDF_STATUS_E_FAILURE;
54 uint32_t pdev_id;
55 struct wmi_unified *wmi_handle;
56
57 psoc = target_if_get_psoc_from_scn_hdl(sc);
58 if (!psoc) {
59 ftm_err("null psoc");
60 return QDF_STATUS_E_INVAL;
61 }
62
63 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FTM_ID);
64 if (QDF_IS_STATUS_ERROR(status)) {
65 ftm_err("unable to get psoc reference");
66 return QDF_STATUS_E_INVAL;
67 }
68
69 event.datalen = len;
70
71 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
72 if (!wmi_handle) {
73 ftm_err("Invalid WMI handle");
74 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
75 return QDF_STATUS_E_INVAL;
76 }
77
78 if (wmi_extract_pdev_utf_event(wmi_handle, event_buf, &event)
79 != QDF_STATUS_SUCCESS) {
80 ftm_err("Extracting utf event failed");
81 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
82 return QDF_STATUS_E_INVAL;
83 }
84
85 pdev_id = event.pdev_id;
86 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_FTM_ID);
87 if (!pdev) {
88 pdev_id = TGT_WMI_PDEV_ID_SOC;
89 ftm_debug("Can't find pdev by pdev_id %d, try soc_id",
90 event.pdev_id);
91 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_FTM_ID);
92 if (!pdev) {
93 ftm_err("null pdev");
94 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
95 return QDF_STATUS_E_INVAL;
96 }
97 }
98
99 ftm_rx_ops = target_if_ftm_get_rx_ops(psoc);
100 if (!ftm_rx_ops) {
101 ftm_err("ftm_rx_ops is NULL");
102 return QDF_STATUS_E_INVAL;
103 }
104 if (ftm_rx_ops->ftm_ev_handler) {
105 status = ftm_rx_ops->ftm_ev_handler(pdev,
106 event.data, event.datalen);
107 if (QDF_IS_STATUS_ERROR(status))
108 status = QDF_STATUS_E_INVAL;
109 } else {
110 status = QDF_STATUS_E_INVAL;
111 }
112
113 wlan_objmgr_pdev_release_ref(pdev, WLAN_FTM_ID);
114 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID);
115
116 return status;
117 }
118
target_if_ftm_cmd_send(struct wlan_objmgr_pdev * pdev,uint8_t * buf,uint32_t len,uint8_t pdev_id)119 QDF_STATUS target_if_ftm_cmd_send(struct wlan_objmgr_pdev *pdev,
120 uint8_t *buf, uint32_t len,
121 uint8_t pdev_id)
122 {
123 QDF_STATUS ret;
124 wmi_unified_t handle;
125 struct pdev_utf_params param;
126
127 if (!pdev) {
128 target_if_err("null pdev");
129 return QDF_STATUS_E_FAILURE;
130 }
131
132 handle = get_wmi_unified_hdl_from_pdev(pdev);
133 if (!handle) {
134 target_if_err("null handle");
135 return QDF_STATUS_E_FAILURE;
136 }
137 param.utf_payload = buf;
138 param.len = len;
139
140 ret = wmi_unified_pdev_utf_cmd_send(handle, ¶m, pdev_id);
141 if (QDF_IS_STATUS_ERROR(ret))
142 ftm_err("wmi utf cmd send failed, ret: %d", ret);
143
144 return ret;
145 }
146
target_if_ftm_attach(struct wlan_objmgr_psoc * psoc)147 QDF_STATUS target_if_ftm_attach(struct wlan_objmgr_psoc *psoc)
148 {
149 QDF_STATUS ret;
150 wmi_unified_t handle;
151
152 if (!psoc) {
153 target_if_err("null psoc");
154 return QDF_STATUS_E_FAILURE;
155 }
156
157 handle = get_wmi_unified_hdl_from_psoc(psoc);
158 if (!handle) {
159 target_if_err("null handle");
160 return QDF_STATUS_E_FAILURE;
161 }
162 ret = wmi_unified_register_event_handler(handle,
163 wmi_pdev_utf_event_id,
164 target_if_ftm_process_utf_event,
165 WMI_RX_UMAC_CTX);
166 if (QDF_IS_STATUS_ERROR(ret)) {
167 ftm_err("wmi event registration failed, ret: %d", ret);
168 return QDF_STATUS_E_FAILURE;
169 }
170
171 return QDF_STATUS_SUCCESS;
172 }
173
target_if_ftm_detach(struct wlan_objmgr_psoc * psoc)174 QDF_STATUS target_if_ftm_detach(struct wlan_objmgr_psoc *psoc)
175
176 {
177 int ret;
178 wmi_unified_t handle;
179
180 if (!psoc) {
181 target_if_err("null psoc");
182 return QDF_STATUS_E_FAILURE;
183 }
184
185 handle = get_wmi_unified_hdl_from_psoc(psoc);
186 if (!handle) {
187 target_if_err("null handle");
188 return QDF_STATUS_E_FAILURE;
189 }
190 ret = wmi_unified_unregister_event_handler(handle,
191 wmi_pdev_utf_event_id);
192
193 if (ret) {
194 ftm_err("wmi event deregistration failed, ret: %d", ret);
195 return QDF_STATUS_E_FAILURE;
196 }
197
198 return QDF_STATUS_SUCCESS;
199 }
200
target_if_ftm_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)201 QDF_STATUS target_if_ftm_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
202 {
203 struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops;
204
205 if (!tx_ops) {
206 ftm_err("invalid tx_ops");
207 return QDF_STATUS_E_FAILURE;
208 }
209
210 ftm_tx_ops = &tx_ops->ftm_tx_ops;
211 ftm_tx_ops->ftm_attach = target_if_ftm_attach;
212 ftm_tx_ops->ftm_detach = target_if_ftm_detach;
213 ftm_tx_ops->ftm_cmd_send = target_if_ftm_cmd_send;
214
215 return QDF_STATUS_SUCCESS;
216 }
217