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