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 * 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 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 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 147 QDF_STATUS target_if_ftm_attach(struct wlan_objmgr_psoc *psoc) 148 { 149 int 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 (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 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 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