xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/snoc/if_snoc.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: if_snoc.c
21  *
22  * c file for snoc specif implementations.
23  */
24 
25 #include "hif.h"
26 #include "hif_main.h"
27 #include "hif_debug.h"
28 #include "hif_io32.h"
29 #include "ce_main.h"
30 #include "ce_tasklet.h"
31 #include "ce_api.h"
32 #include "ce_internal.h"
33 #include "snoc_api.h"
34 #include "pld_common.h"
35 #include "qdf_util.h"
36 #ifdef IPA_OFFLOAD
37 #include <uapi/linux/msm_ipa.h>
38 #endif
39 #include "target_type.h"
40 
41 /**
42  * hif_disable_isr(): disable isr
43  *
44  * This function disables isr and kills tasklets
45  *
46  * @hif_ctx: struct hif_softc
47  *
48  * Return: void
49  */
50 void hif_snoc_disable_isr(struct hif_softc *scn)
51 {
52 	hif_exec_kill(&scn->osc);
53 	hif_nointrs(scn);
54 	ce_tasklet_kill(scn);
55 	qdf_atomic_set(&scn->active_tasklet_cnt, 0);
56 	qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
57 }
58 
59 /**
60  * hif_dump_registers(): dump bus debug registers
61  * @hif_ctx: struct hif_opaque_softc
62  *
63  * This function dumps hif bus debug registers
64  *
65  * Return: 0 for success or error code
66  */
67 int hif_snoc_dump_registers(struct hif_softc *hif_ctx)
68 {
69 	int status;
70 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
71 
72 	status = hif_dump_ce_registers(scn);
73 	if (status)
74 		HIF_ERROR("%s: Dump CE Registers Failed", __func__);
75 
76 	return 0;
77 }
78 
79 void hif_snoc_display_stats(struct hif_softc *hif_ctx)
80 {
81 	if (!hif_ctx) {
82 		HIF_ERROR("%s, hif_ctx null", __func__);
83 		return;
84 	}
85 	hif_display_ce_stats(hif_ctx);
86 }
87 
88 void hif_snoc_clear_stats(struct hif_softc *hif_ctx)
89 {
90 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
91 
92 	if (!hif_state) {
93 		HIF_ERROR("%s, hif_ctx null", __func__);
94 		return;
95 	}
96 	hif_clear_ce_stats(hif_state);
97 }
98 
99 /**
100  * hif_snoc_close(): hif_bus_close
101  *
102  * Return: n/a
103  */
104 void hif_snoc_close(struct hif_softc *scn)
105 {
106 	hif_ce_close(scn);
107 }
108 
109 /**
110  * hif_bus_open(): hif_bus_open
111  * @hif_ctx: hif context
112  * @bus_type: bus type
113  *
114  * Return: n/a
115  */
116 QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
117 {
118 	return hif_ce_open(hif_ctx);
119 }
120 
121 /**
122  * hif_snoc_get_soc_info() - populates scn with hw info
123  *
124  * fills in the virtual and physical base address as well as
125  * soc version info.
126  *
127  * return 0 or QDF_STATUS_E_FAILURE
128  */
129 static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn)
130 {
131 	int ret;
132 	struct pld_soc_info soc_info;
133 
134 	qdf_mem_zero(&soc_info, sizeof(soc_info));
135 
136 	ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info);
137 	if (ret < 0) {
138 		HIF_ERROR("%s: pld_get_soc_info error = %d", __func__, ret);
139 		return QDF_STATUS_E_FAILURE;
140 	}
141 
142 	scn->mem = soc_info.v_addr;
143 	scn->mem_pa = soc_info.p_addr;
144 
145 	scn->target_info.soc_version = soc_info.soc_id;
146 	scn->target_info.target_version = soc_info.soc_id;
147 	scn->target_info.target_revision = 0;
148 	return QDF_STATUS_SUCCESS;
149 }
150 
151 /**
152  * hif_bus_configure() - configure the snoc bus
153  * @scn: pointer to the hif context.
154  *
155  * return: 0 for success. nonzero for failure.
156  */
157 int hif_snoc_bus_configure(struct hif_softc *scn)
158 {
159 	int ret;
160 	uint8_t wake_ce_id;
161 
162 	ret = hif_snoc_get_soc_info(scn);
163 	if (ret)
164 		return ret;
165 
166 	hif_ce_prepare_config(scn);
167 
168 	ret = hif_wlan_enable(scn);
169 	if (ret) {
170 		HIF_ERROR("%s: hif_wlan_enable error = %d",
171 				__func__, ret);
172 		return ret;
173 	}
174 
175 	ret = hif_config_ce(scn);
176 	if (ret)
177 		goto wlan_disable;
178 
179 	ret = hif_get_wake_ce_id(scn, &wake_ce_id);
180 	if (ret)
181 		goto unconfig_ce;
182 
183 	scn->wake_irq = pld_get_irq(scn->qdf_dev->dev, wake_ce_id);
184 
185 	HIF_INFO(FL("expecting wake from ce %d, irq %d"),
186 		 wake_ce_id, scn->wake_irq);
187 
188 	return 0;
189 
190 unconfig_ce:
191 	hif_unconfig_ce(scn);
192 
193 wlan_disable:
194 	hif_wlan_disable(scn);
195 
196 	return ret;
197 }
198 
199 /**
200  * hif_snoc_get_target_type(): Get the target type
201  *
202  * This function is used to query the target type.
203  *
204  * @ol_sc: hif_softc struct pointer
205  * @dev: device pointer
206  * @bdev: bus dev pointer
207  * @bid: bus id pointer
208  * @hif_type: HIF type such as HIF_TYPE_QCA6180
209  * @target_type: target type such as TARGET_TYPE_QCA6180
210  *
211  * Return: 0 for success
212  */
213 static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc,
214 	struct device *dev, void *bdev, const struct hif_bus_id *bid,
215 	uint32_t *hif_type, uint32_t *target_type)
216 {
217 	/* TODO: need to use HW version. Hard code for now */
218 #ifdef QCA_WIFI_3_0_ADRASTEA
219 	*hif_type = HIF_TYPE_ADRASTEA;
220 	*target_type = TARGET_TYPE_ADRASTEA;
221 #else
222 	*hif_type = 0;
223 	*target_type = 0;
224 #endif
225 	return 0;
226 }
227 
228 #ifdef IPA_OFFLOAD
229 static int hif_set_dma_coherent_mask(qdf_device_t osdev)
230 {
231 	uint8_t addr_bits;
232 
233 	if (false == hif_get_ipa_present())
234 		return qdf_set_dma_coherent_mask(osdev->dev,
235 					DMA_COHERENT_MASK_DEFAULT);
236 
237 	if (hif_get_ipa_hw_type() < IPA_HW_v3_0)
238 		addr_bits = DMA_COHERENT_MASK_BELOW_IPA_VER_3;
239 	else
240 		addr_bits = DMA_COHERENT_MASK_DEFAULT;
241 
242 	return qdf_set_dma_coherent_mask(osdev->dev, addr_bits);
243 }
244 #else
245 static int hif_set_dma_coherent_mask(qdf_device_t osdev)
246 {
247 	return qdf_set_dma_coherent_mask(osdev->dev,
248 					DMA_COHERENT_MASK_DEFAULT);
249 }
250 #endif
251 
252 /**
253  * hif_enable_bus(): hif_enable_bus
254  * @dev: dev
255  * @bdev: bus dev
256  * @bid: bus id
257  * @type: bus type
258  *
259  * Return: QDF_STATUS
260  */
261 QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc,
262 			  struct device *dev, void *bdev,
263 			  const struct hif_bus_id *bid,
264 			  enum hif_enable_type type)
265 {
266 	int ret;
267 	int hif_type;
268 	int target_type;
269 
270 	if (!ol_sc) {
271 		HIF_ERROR("%s: hif_ctx is NULL", __func__);
272 		return QDF_STATUS_E_NOMEM;
273 	}
274 
275 	ret = hif_set_dma_coherent_mask(ol_sc->qdf_dev);
276 	if (ret) {
277 		HIF_ERROR("%s: failed to set dma mask error = %d",
278 				__func__, ret);
279 		return ret;
280 	}
281 
282 	ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true);
283 	if (ret == -EEXIST)
284 		HIF_WARN("%s: device_init_wakeup already done",
285 				__func__);
286 	else if (ret) {
287 		HIF_ERROR("%s: device_init_wakeup: err= %d",
288 				__func__, ret);
289 		return ret;
290 	}
291 
292 	ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid,
293 			&hif_type, &target_type);
294 	if (ret < 0) {
295 		HIF_ERROR("%s: invalid device id/revision_id", __func__);
296 		return QDF_STATUS_E_FAILURE;
297 	}
298 
299 	ol_sc->target_info.target_type = target_type;
300 
301 	hif_register_tbl_attach(ol_sc, hif_type);
302 	hif_target_register_tbl_attach(ol_sc, target_type);
303 
304 	/* the bus should remain on durring suspend for snoc */
305 	hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc));
306 
307 	HIF_DBG("%s: X - hif_type = 0x%x, target_type = 0x%x",
308 		  __func__, hif_type, target_type);
309 
310 	return QDF_STATUS_SUCCESS;
311 }
312 
313 /**
314  * hif_disable_bus(): hif_disable_bus
315  *
316  * This function disables the bus
317  *
318  * @bdev: bus dev
319  *
320  * Return: none
321  */
322 void hif_snoc_disable_bus(struct hif_softc *scn)
323 {
324 	int ret;
325 
326 	hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn));
327 
328 	ret = qdf_device_init_wakeup(scn->qdf_dev, false);
329 	if (ret)
330 		HIF_ERROR("%s: device_init_wakeup: err %d", __func__, ret);
331 }
332 
333 /**
334  * hif_nointrs(): disable IRQ
335  *
336  * This function stops interrupt(s)
337  *
338  * @scn: struct hif_softc
339  *
340  * Return: none
341  */
342 void hif_snoc_nointrs(struct hif_softc *scn)
343 {
344 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
345 
346 	ce_unregister_irq(hif_state, CE_ALL_BITMAP);
347 }
348 
349 /**
350  * ce_irq_enable() - enable copy engine IRQ
351  * @scn: struct hif_softc
352  * @ce_id: ce_id
353  *
354  * Return: N/A
355  */
356 void hif_snoc_irq_enable(struct hif_softc *scn,
357 		int ce_id)
358 {
359 	ce_enable_irq_in_individual_register(scn, ce_id);
360 }
361 
362 /**
363  * ce_irq_disable() - disable copy engine IRQ
364  * @scn: struct hif_softc
365  * @ce_id: ce_id
366  *
367  * Return: N/A
368  */
369 void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id)
370 {
371 	ce_disable_irq_in_individual_register(scn, ce_id);
372 }
373 
374 /*
375  * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs
376  * @hif_softc: hif context
377  *
378  * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up
379  * the host driver. Ensure that the copy complete interrupt from this copy
380  * engine can wake up the apps processor.
381  *
382  * Return: 0 for success
383  */
384 static
385 QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable)
386 {
387 	int ret;
388 
389 	if (enable)
390 		ret = enable_irq_wake(scn->wake_irq);
391 	else
392 		ret = disable_irq_wake(scn->wake_irq);
393 
394 	if (ret) {
395 		HIF_ERROR("%s: Fail to setup wake IRQ!", __func__);
396 		return QDF_STATUS_E_RESOURCES;
397 	}
398 
399 	return QDF_STATUS_SUCCESS;
400 }
401 
402 /**
403  * hif_snoc_bus_suspend() - prepare to suspend the bus
404  * @scn: hif context
405  *
406  * Setup wakeup interrupt configuration.
407  * Disable CE interrupts (wakeup interrupt will still wake apps)
408  * Drain tasklets. - make sure that we don't suspend while processing
409  * the wakeup message.
410  *
411  * Return: 0 on success.
412  */
413 int hif_snoc_bus_suspend(struct hif_softc *scn)
414 {
415 	if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS)
416 		return -EFAULT;
417 	return 0;
418 }
419 
420 /**
421  * hif_snoc_bus_resume() - snoc bus resume function
422  * @scn: hif context
423  *
424  * Clear wakeup interrupt configuration.
425  * Reenable ce interrupts
426  *
427  * Return: 0 on success
428  */
429 int hif_snoc_bus_resume(struct hif_softc *scn)
430 {
431 	if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
432 		QDF_BUG(0);
433 
434 	return 0;
435 }
436 
437 /**
438  * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions
439  * @scn: hif context
440  *
441  * Ensure that if we received the wakeup message before the irq
442  * was disabled that the message is pocessed before suspending.
443  *
444  * Return: -EBUSY if we fail to flush the tasklets.
445  */
446 int hif_snoc_bus_suspend_noirq(struct hif_softc *scn)
447 {
448 	if (hif_drain_tasklets(scn) != 0)
449 		return -EBUSY;
450 	return 0;
451 }
452 
453 int hif_snoc_map_ce_to_irq(struct hif_softc *scn, int ce_id)
454 {
455 	return pld_get_irq(scn->qdf_dev->dev, ce_id);
456 }
457 
458 /**
459  * hif_is_target_register_access_allowed(): Check target register access allow
460  * @scn: HIF Context
461  *
462  * This function help to check whether target register access is allowed or not
463  *
464  * Return: true if target access is allowed else false
465  */
466 bool hif_is_target_register_access_allowed(struct hif_softc *scn)
467 {
468 	if (hif_is_recovery_in_progress(scn))
469 		return hif_is_target_ready(scn);
470 	else
471 		return true;
472 }
473 
474 /**
475  * hif_snoc_needs_bmi() - return true if the soc needs bmi through the driver
476  * @scn: hif context
477  *
478  * Return: true if soc needs driver bmi otherwise false
479  */
480 bool hif_snoc_needs_bmi(struct hif_softc *scn)
481 {
482 	return false;
483 }
484