1 /*
2 * Copyright (c) 2020-2021, The Linux Foundation. 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: target_if_dcs.c
19 *
20 * This file provide definition for APIs registered through lmac Tx Ops
21 */
22
23 #include <wmi_unified_api.h>
24 #include <wmi_unified_priv.h>
25 #include <wmi_unified_dcs_api.h>
26 #include <init_deinit_lmac.h>
27 #include "wlan_dcs_tgt_api.h"
28 #include "target_if_dcs.h"
29
30 /**
31 * target_if_dcs_interference_event_handler() - function to handle dcs event
32 * from firmware.
33 * @scn: scn handle
34 * @data: data buffer for event
35 * @datalen: data length
36 *
37 * Return: status of operation.
38 */
target_if_dcs_interference_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)39 static int target_if_dcs_interference_event_handler(ol_scn_t scn,
40 uint8_t *data,
41 uint32_t datalen)
42 {
43 QDF_STATUS status;
44 struct wlan_host_dcs_event ev;
45 struct wlan_objmgr_psoc *psoc;
46 struct wmi_unified *wmi_handle;
47 struct wlan_target_if_dcs_rx_ops *rx_ops;
48
49 if (!scn || !data) {
50 target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
51 return -EINVAL;
52 }
53 psoc = target_if_get_psoc_from_scn_hdl(scn);
54 if (!psoc) {
55 target_if_err("null psoc");
56 return -EINVAL;
57 }
58
59 rx_ops = target_if_dcs_get_rx_ops(psoc);
60 if (!rx_ops || !rx_ops->process_dcs_event) {
61 target_if_err("callback not registered");
62 return -EINVAL;
63 }
64
65 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
66 if (!wmi_handle) {
67 target_if_err("wmi_handle is null");
68 return -EINVAL;
69 }
70
71 if (wmi_extract_dcs_interference_type(wmi_handle, data,
72 &ev.dcs_param) !=
73 QDF_STATUS_SUCCESS) {
74 target_if_err("Unable to extract dcs interference type");
75 return -EINVAL;
76 }
77
78 if (ev.dcs_param.interference_type == WLAN_HOST_DCS_WLANIM &&
79 wmi_extract_dcs_im_tgt_stats(wmi_handle, data, &ev.wlan_stat) !=
80 QDF_STATUS_SUCCESS) {
81 target_if_err("Unable to extract WLAN IM stats");
82 return -EINVAL;
83 }
84
85 if (ev.dcs_param.interference_type == WLAN_HOST_DCS_AWGNIM &&
86 wmi_extract_dcs_awgn_info(wmi_handle, data, &ev.awgn_info) !=
87 QDF_STATUS_SUCCESS) {
88 target_if_err("Unable to extract AWGN info");
89 return -EINVAL;
90 }
91
92 status = rx_ops->process_dcs_event(psoc, &ev);
93
94 return qdf_status_to_os_return(status);
95 }
96
97 static QDF_STATUS
target_if_dcs_register_event_handler(struct wlan_objmgr_psoc * psoc)98 target_if_dcs_register_event_handler(struct wlan_objmgr_psoc *psoc)
99 {
100 QDF_STATUS ret_val;
101 struct wmi_unified *wmi_handle;
102
103 if (!psoc) {
104 target_if_err("PSOC is NULL!");
105 return QDF_STATUS_E_NULL_VALUE;
106 }
107
108 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
109 if (!wmi_handle) {
110 target_if_err("wmi_handle is null");
111 return QDF_STATUS_E_INVAL;
112 }
113
114 ret_val = wmi_unified_register_event_handler(
115 wmi_handle,
116 wmi_dcs_interference_event_id,
117 target_if_dcs_interference_event_handler,
118 WMI_RX_WORK_CTX);
119 if (QDF_IS_STATUS_ERROR(ret_val))
120 target_if_err("Failed to register dcs interference event cb");
121
122 return ret_val;
123 }
124
125 static QDF_STATUS
target_if_dcs_unregister_event_handler(struct wlan_objmgr_psoc * psoc)126 target_if_dcs_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
127 {
128 struct wmi_unified *wmi_handle;
129
130 if (!psoc) {
131 target_if_err("PSOC is NULL!");
132 return QDF_STATUS_E_INVAL;
133 }
134
135 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
136 if (!wmi_handle) {
137 target_if_err("wmi_handle is null");
138 return QDF_STATUS_E_INVAL;
139 }
140 wmi_unified_unregister_event_handler(wmi_handle,
141 wmi_dcs_interference_event_id);
142
143 return QDF_STATUS_SUCCESS;
144 }
145
146 /**
147 * target_if_dcs_cmd_send() - Send WMI command for dcs requests
148 * @psoc: psoc pointer
149 * @pdev_id: pdev_id
150 * @is_host_pdev_id: pdev_id is host pdev_id or not
151 * @dcs_enable: dcs enable or not
152 *
153 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error
154 */
155 static QDF_STATUS
target_if_dcs_cmd_send(struct wlan_objmgr_psoc * psoc,uint32_t pdev_id,bool is_host_pdev_id,uint32_t dcs_enable)156 target_if_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id,
157 bool is_host_pdev_id, uint32_t dcs_enable)
158 {
159 QDF_STATUS ret;
160 struct wmi_unified *wmi_handle;
161
162 if (!psoc) {
163 target_if_err("null psoc");
164 return QDF_STATUS_E_FAILURE;
165 }
166
167 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
168 if (!wmi_handle) {
169 target_if_err("null handle");
170 return QDF_STATUS_E_FAILURE;
171 }
172
173 ret = wmi_send_dcs_pdev_param(wmi_handle, pdev_id,
174 is_host_pdev_id, dcs_enable);
175 if (QDF_IS_STATUS_ERROR(ret))
176 target_if_err("wmi dcs cmd send failed, ret: %d", ret);
177
178 return ret;
179 }
180
181 QDF_STATUS
target_if_dcs_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)182 target_if_dcs_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
183 {
184 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
185
186 if (!tx_ops) {
187 target_if_err("lmac tx ops is NULL!");
188 return QDF_STATUS_E_INVAL;
189 }
190
191 dcs_tx_ops = &tx_ops->dcs_tx_ops;
192 if (!dcs_tx_ops) {
193 target_if_err("lmac tx ops is NULL!");
194 return QDF_STATUS_E_FAILURE;
195 }
196
197 dcs_tx_ops->dcs_attach =
198 target_if_dcs_register_event_handler;
199 dcs_tx_ops->dcs_detach =
200 target_if_dcs_unregister_event_handler;
201 dcs_tx_ops->dcs_cmd_send = target_if_dcs_cmd_send;
202
203 return QDF_STATUS_SUCCESS;
204 }
205
206