1 /* 2 * Copyright (c) 2018 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 return &psoc->soc_cb.rx_ops.ftm_rx_ops; 36 } 37 38 static int 39 target_if_ftm_process_utf_event(ol_scn_t sc, uint8_t *event_buf, uint32_t len) 40 { 41 struct wlan_objmgr_psoc *psoc; 42 struct wlan_objmgr_pdev *pdev; 43 struct wmi_host_pdev_utf_event event; 44 struct wlan_lmac_if_ftm_rx_ops *ftm_rx_ops; 45 QDF_STATUS status = QDF_STATUS_E_FAILURE; 46 uint32_t pdev_id; 47 struct wmi_unified *wmi_handle; 48 49 psoc = target_if_get_psoc_from_scn_hdl(sc); 50 if (!psoc) { 51 ftm_err("null psoc"); 52 return QDF_STATUS_E_INVAL; 53 } 54 55 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FTM_ID); 56 if (QDF_IS_STATUS_ERROR(status)) { 57 ftm_err("unable to get psoc reference"); 58 return QDF_STATUS_E_INVAL; 59 } 60 61 event.datalen = len; 62 63 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 64 if (!wmi_handle) { 65 ftm_err("Invalid WMI handle"); 66 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID); 67 return QDF_STATUS_E_INVAL; 68 } 69 70 if (wmi_extract_pdev_utf_event(wmi_handle, event_buf, &event) 71 != QDF_STATUS_SUCCESS) { 72 ftm_err("Extracting utf event failed"); 73 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID); 74 return QDF_STATUS_E_INVAL; 75 } 76 77 pdev_id = event.pdev_id; 78 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_FTM_ID); 79 if (!pdev) { 80 pdev_id = TGT_WMI_PDEV_ID_SOC; 81 ftm_debug("Can't find pdev by pdev_id %d, try soc_id", 82 event.pdev_id); 83 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_FTM_ID); 84 if (!pdev) { 85 ftm_err("null pdev"); 86 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID); 87 return QDF_STATUS_E_INVAL; 88 } 89 } 90 91 ftm_rx_ops = target_if_ftm_get_rx_ops(psoc); 92 93 if (ftm_rx_ops->ftm_ev_handler) { 94 status = ftm_rx_ops->ftm_ev_handler(pdev, 95 event.data, event.datalen); 96 if (QDF_IS_STATUS_ERROR(status)) 97 status = QDF_STATUS_E_INVAL; 98 } else { 99 status = QDF_STATUS_E_INVAL; 100 } 101 102 wlan_objmgr_pdev_release_ref(pdev, WLAN_FTM_ID); 103 wlan_objmgr_psoc_release_ref(psoc, WLAN_FTM_ID); 104 105 return status; 106 } 107 108 QDF_STATUS target_if_ftm_cmd_send(struct wlan_objmgr_pdev *pdev, 109 uint8_t *buf, uint32_t len, 110 uint8_t pdev_id) 111 { 112 QDF_STATUS ret; 113 wmi_unified_t handle; 114 struct pdev_utf_params param; 115 116 if (!pdev) { 117 target_if_err("null pdev"); 118 return QDF_STATUS_E_FAILURE; 119 } 120 121 handle = get_wmi_unified_hdl_from_pdev(pdev); 122 if (!handle) { 123 target_if_err("null handle"); 124 return QDF_STATUS_E_FAILURE; 125 } 126 param.utf_payload = buf; 127 param.len = len; 128 129 ret = wmi_unified_pdev_utf_cmd_send(handle, ¶m, pdev_id); 130 if (QDF_IS_STATUS_ERROR(ret)) 131 ftm_err("wmi utf cmd send failed, ret: %d", ret); 132 133 return ret; 134 } 135 136 QDF_STATUS target_if_ftm_attach(struct wlan_objmgr_psoc *psoc) 137 { 138 int ret; 139 wmi_unified_t handle; 140 141 if (!psoc) { 142 target_if_err("null psoc"); 143 return QDF_STATUS_E_FAILURE; 144 } 145 146 handle = get_wmi_unified_hdl_from_psoc(psoc); 147 if (!handle) { 148 target_if_err("null handle"); 149 return QDF_STATUS_E_FAILURE; 150 } 151 ret = wmi_unified_register_event_handler(handle, 152 wmi_pdev_utf_event_id, 153 target_if_ftm_process_utf_event, 154 WMI_RX_UMAC_CTX); 155 if (ret) { 156 ftm_err("wmi event registration failed, ret: %d", ret); 157 return QDF_STATUS_E_FAILURE; 158 } 159 160 return QDF_STATUS_SUCCESS; 161 } 162 163 QDF_STATUS target_if_ftm_detach(struct wlan_objmgr_psoc *psoc) 164 165 { 166 int ret; 167 wmi_unified_t handle; 168 169 if (!psoc) { 170 target_if_err("null psoc"); 171 return QDF_STATUS_E_FAILURE; 172 } 173 174 handle = get_wmi_unified_hdl_from_psoc(psoc); 175 if (!handle) { 176 target_if_err("null handle"); 177 return QDF_STATUS_E_FAILURE; 178 } 179 ret = wmi_unified_unregister_event_handler(handle, 180 wmi_pdev_utf_event_id); 181 182 if (ret) { 183 ftm_err("wmi event deregistration failed, ret: %d", ret); 184 return QDF_STATUS_E_FAILURE; 185 } 186 187 return QDF_STATUS_SUCCESS; 188 } 189 190 QDF_STATUS target_if_ftm_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 191 { 192 struct wlan_lmac_if_ftm_tx_ops *ftm_tx_ops; 193 194 if (!tx_ops) { 195 ftm_err("invalid tx_ops"); 196 return QDF_STATUS_E_FAILURE; 197 } 198 199 ftm_tx_ops = &tx_ops->ftm_tx_ops; 200 ftm_tx_ops->ftm_attach = target_if_ftm_attach; 201 ftm_tx_ops->ftm_detach = target_if_ftm_detach; 202 ftm_tx_ops->ftm_cmd_send = target_if_ftm_cmd_send; 203 204 return QDF_STATUS_SUCCESS; 205 } 206