xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/snoc/if_snoc.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2015-2018 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 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
82 
83 	if (hif_state == NULL) {
84 		HIF_ERROR("%s, hif_ctx null", __func__);
85 		return;
86 	}
87 	hif_display_ce_stats(hif_state);
88 }
89 
90 void hif_snoc_clear_stats(struct hif_softc *hif_ctx)
91 {
92 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
93 
94 	if (hif_state == NULL) {
95 		HIF_ERROR("%s, hif_ctx null", __func__);
96 		return;
97 	}
98 	hif_clear_ce_stats(hif_state);
99 }
100 
101 /**
102  * hif_snoc_close(): hif_bus_close
103  *
104  * Return: n/a
105  */
106 void hif_snoc_close(struct hif_softc *scn)
107 {
108 	hif_ce_close(scn);
109 }
110 
111 /**
112  * hif_bus_open(): hif_bus_open
113  * @hif_ctx: hif context
114  * @bus_type: bus type
115  *
116  * Return: n/a
117  */
118 QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
119 {
120 	return hif_ce_open(hif_ctx);
121 }
122 
123 /**
124  * hif_snoc_get_soc_info() - populates scn with hw info
125  *
126  * fills in the virtual and physical base address as well as
127  * soc version info.
128  *
129  * return 0 or QDF_STATUS_E_FAILURE
130  */
131 static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn)
132 {
133 	int ret;
134 	struct pld_soc_info soc_info;
135 
136 	qdf_mem_zero(&soc_info, sizeof(soc_info));
137 
138 	ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info);
139 	if (ret < 0) {
140 		HIF_ERROR("%s: pld_get_soc_info error = %d", __func__, ret);
141 		return QDF_STATUS_E_FAILURE;
142 	}
143 
144 	scn->mem = soc_info.v_addr;
145 	scn->mem_pa = soc_info.p_addr;
146 
147 	scn->target_info.soc_version = soc_info.soc_id;
148 	scn->target_info.target_version = soc_info.soc_id;
149 	scn->target_info.target_revision = 0;
150 	return QDF_STATUS_SUCCESS;
151 }
152 
153 /**
154  * hif_bus_configure() - configure the snoc bus
155  * @scn: pointer to the hif context.
156  *
157  * return: 0 for success. nonzero for failure.
158  */
159 int hif_snoc_bus_configure(struct hif_softc *scn)
160 {
161 	int ret;
162 	uint8_t wake_ce_id;
163 
164 	ret = hif_snoc_get_soc_info(scn);
165 	if (ret)
166 		return ret;
167 
168 	hif_ce_prepare_config(scn);
169 
170 	ret = hif_wlan_enable(scn);
171 	if (ret) {
172 		HIF_ERROR("%s: hif_wlan_enable error = %d",
173 				__func__, ret);
174 		return ret;
175 	}
176 
177 	ret = hif_config_ce(scn);
178 	if (ret)
179 		goto wlan_disable;
180 
181 	ret = hif_get_wake_ce_id(scn, &wake_ce_id);
182 	if (ret)
183 		goto unconfig_ce;
184 
185 	scn->wake_irq = pld_get_irq(scn->qdf_dev->dev, wake_ce_id);
186 
187 	HIF_INFO(FL("expecting wake from ce %d, irq %d"),
188 		 wake_ce_id, scn->wake_irq);
189 
190 	return 0;
191 
192 unconfig_ce:
193 	hif_unconfig_ce(scn);
194 
195 wlan_disable:
196 	hif_wlan_disable(scn);
197 
198 	return ret;
199 }
200 
201 /**
202  * hif_snoc_get_target_type(): Get the target type
203  *
204  * This function is used to query the target type.
205  *
206  * @ol_sc: hif_softc struct pointer
207  * @dev: device pointer
208  * @bdev: bus dev pointer
209  * @bid: bus id pointer
210  * @hif_type: HIF type such as HIF_TYPE_QCA6180
211  * @target_type: target type such as TARGET_TYPE_QCA6180
212  *
213  * Return: 0 for success
214  */
215 static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc,
216 	struct device *dev, void *bdev, const struct hif_bus_id *bid,
217 	uint32_t *hif_type, uint32_t *target_type)
218 {
219 	/* TODO: need to use HW version. Hard code for now */
220 #ifdef QCA_WIFI_3_0_ADRASTEA
221 	*hif_type = HIF_TYPE_ADRASTEA;
222 	*target_type = TARGET_TYPE_ADRASTEA;
223 #else
224 	*hif_type = 0;
225 	*target_type = 0;
226 #endif
227 	return 0;
228 }
229 
230 #ifdef IPA_OFFLOAD
231 static int hif_set_dma_coherent_mask(qdf_device_t osdev)
232 {
233 	uint8_t addr_bits;
234 
235 	if (false == hif_get_ipa_present())
236 		return qdf_set_dma_coherent_mask(osdev->dev,
237 					DMA_COHERENT_MASK_IPA_VER_3_AND_ABOVE);
238 
239 	if (hif_get_ipa_hw_type() < IPA_HW_v3_0)
240 		addr_bits = DMA_COHERENT_MASK_BELOW_IPA_VER_3;
241 	else
242 		addr_bits = DMA_COHERENT_MASK_IPA_VER_3_AND_ABOVE;
243 
244 	return qdf_set_dma_coherent_mask(osdev->dev, addr_bits);
245 }
246 #else
247 static int hif_set_dma_coherent_mask(qdf_device_t osdev)
248 {
249 	return qdf_set_dma_coherent_mask(osdev->dev, 37);
250 }
251 #endif
252 
253 /**
254  * hif_enable_bus(): hif_enable_bus
255  * @dev: dev
256  * @bdev: bus dev
257  * @bid: bus id
258  * @type: bus type
259  *
260  * Return: QDF_STATUS
261  */
262 QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc,
263 			  struct device *dev, void *bdev,
264 			  const struct hif_bus_id *bid,
265 			  enum hif_enable_type type)
266 {
267 	int ret;
268 	int hif_type;
269 	int target_type;
270 
271 	if (!ol_sc) {
272 		HIF_ERROR("%s: hif_ctx is NULL", __func__);
273 		return QDF_STATUS_E_NOMEM;
274 	}
275 
276 	ret = hif_set_dma_coherent_mask(ol_sc->qdf_dev);
277 	if (ret) {
278 		HIF_ERROR("%s: failed to set dma mask error = %d",
279 				__func__, ret);
280 		return ret;
281 	}
282 
283 	ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true);
284 	if (ret == -EEXIST)
285 		HIF_WARN("%s: device_init_wakeup already done",
286 				__func__);
287 	else if (ret) {
288 		HIF_ERROR("%s: device_init_wakeup: err= %d",
289 				__func__, ret);
290 		return ret;
291 	}
292 
293 	ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid,
294 			&hif_type, &target_type);
295 	if (ret < 0) {
296 		HIF_ERROR("%s: invalid device id/revision_id", __func__);
297 		return QDF_STATUS_E_FAILURE;
298 	}
299 
300 	ol_sc->target_info.target_type = target_type;
301 
302 	hif_register_tbl_attach(ol_sc, hif_type);
303 	hif_target_register_tbl_attach(ol_sc, target_type);
304 
305 	/* the bus should remain on durring suspend for snoc */
306 	hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc));
307 
308 	HIF_DBG("%s: X - hif_type = 0x%x, target_type = 0x%x",
309 		  __func__, hif_type, target_type);
310 
311 	return QDF_STATUS_SUCCESS;
312 }
313 
314 /**
315  * hif_disable_bus(): hif_disable_bus
316  *
317  * This function disables the bus
318  *
319  * @bdev: bus dev
320  *
321  * Return: none
322  */
323 void hif_snoc_disable_bus(struct hif_softc *scn)
324 {
325 	int ret;
326 
327 	hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn));
328 
329 	ret = qdf_device_init_wakeup(scn->qdf_dev, false);
330 	if (ret)
331 		HIF_ERROR("%s: device_init_wakeup: err %d", __func__, ret);
332 }
333 
334 /**
335  * hif_nointrs(): disable IRQ
336  *
337  * This function stops interrupt(s)
338  *
339  * @scn: struct hif_softc
340  *
341  * Return: none
342  */
343 void hif_snoc_nointrs(struct hif_softc *scn)
344 {
345 	struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
346 
347 	ce_unregister_irq(hif_state, CE_ALL_BITMAP);
348 }
349 
350 /**
351  * ce_irq_enable() - enable copy engine IRQ
352  * @scn: struct hif_softc
353  * @ce_id: ce_id
354  *
355  * Return: N/A
356  */
357 void hif_snoc_irq_enable(struct hif_softc *scn,
358 		int ce_id)
359 {
360 	ce_enable_irq_in_individual_register(scn, ce_id);
361 }
362 
363 /**
364  * ce_irq_disable() - disable copy engine IRQ
365  * @scn: struct hif_softc
366  * @ce_id: ce_id
367  *
368  * Return: N/A
369  */
370 void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id)
371 {
372 	ce_disable_irq_in_individual_register(scn, ce_id);
373 }
374 
375 /*
376  * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs
377  * @hif_softc: hif context
378  *
379  * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up
380  * the host driver. Ensure that the copy complete interrupt from this copy
381  * engine can wake up the apps processor.
382  *
383  * Return: 0 for success
384  */
385 static
386 QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable)
387 {
388 	int ret;
389 
390 	if (enable)
391 		ret = enable_irq_wake(scn->wake_irq);
392 	else
393 		ret = disable_irq_wake(scn->wake_irq);
394 
395 	if (ret) {
396 		HIF_ERROR("%s: Fail to setup wake IRQ!", __func__);
397 		return QDF_STATUS_E_RESOURCES;
398 	}
399 
400 	return QDF_STATUS_SUCCESS;
401 }
402 
403 /**
404  * hif_snoc_bus_suspend() - prepare to suspend the bus
405  * @scn: hif context
406  *
407  * Setup wakeup interrupt configuration.
408  * Disable CE interrupts (wakeup interrupt will still wake apps)
409  * Drain tasklets. - make sure that we don't suspend while processing
410  * the wakeup message.
411  *
412  * Return: 0 on success.
413  */
414 int hif_snoc_bus_suspend(struct hif_softc *scn)
415 {
416 	if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS)
417 		return -EFAULT;
418 	return 0;
419 }
420 
421 /**
422  * hif_snoc_bus_resume() - snoc bus resume function
423  * @scn: hif context
424  *
425  * Clear wakeup interrupt configuration.
426  * Reenable ce interrupts
427  *
428  * Return: 0 on success
429  */
430 int hif_snoc_bus_resume(struct hif_softc *scn)
431 {
432 	if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
433 		QDF_BUG(0);
434 
435 	return 0;
436 }
437 
438 /**
439  * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions
440  * @scn: hif context
441  *
442  * Ensure that if we received the wakeup message before the irq
443  * was disabled that the message is pocessed before suspending.
444  *
445  * Return: -EBUSY if we fail to flush the tasklets.
446  */
447 int hif_snoc_bus_suspend_noirq(struct hif_softc *scn)
448 {
449 	if (hif_drain_tasklets(scn) != 0)
450 		return -EBUSY;
451 	return 0;
452 }
453 
454 int hif_snoc_map_ce_to_irq(struct hif_softc *scn, int ce_id)
455 {
456 	return pld_get_irq(scn->qdf_dev->dev, ce_id);
457 }
458 
459 /**
460  * hif_is_target_register_access_allowed(): Check target register access allow
461  * @scn: HIF Context
462  *
463  * This function help to check whether target register access is allowed or not
464  *
465  * Return: true if target access is allowed else false
466  */
467 bool hif_is_target_register_access_allowed(struct hif_softc *scn)
468 {
469 	if (hif_is_recovery_in_progress(scn))
470 		return hif_is_target_ready(scn);
471 	else
472 		return true;
473 }
474 
475 /**
476  * hif_snoc_needs_bmi() - return true if the soc needs bmi through the driver
477  * @scn: hif context
478  *
479  * Return: true if soc needs driver bmi otherwise false
480  */
481 bool hif_snoc_needs_bmi(struct hif_softc *scn)
482 {
483 	return false;
484 }
485