xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2013-2019 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 #define ATH_MODULE_NAME hif
20 #include "a_debug.h"
21 
22 #include <qdf_types.h>
23 #include <qdf_status.h>
24 #include <qdf_timer.h>
25 #include <qdf_time.h>
26 #include <qdf_lock.h>
27 #include <qdf_mem.h>
28 #include <qdf_util.h>
29 #include <qdf_defer.h>
30 #include <qdf_atomic.h>
31 #include <qdf_nbuf.h>
32 #include <athdefs.h>
33 #include <qdf_net_types.h>
34 #include <a_types.h>
35 #include <athdefs.h>
36 #include <a_osapi.h>
37 #include <hif.h>
38 #include <htc_services.h>
39 #include "hif_sdio_internal.h"
40 #include "if_sdio.h"
41 #include "regtable_sdio.h"
42 
43 /**
44  * hif_dev_alloc_rx_buffer() - allocate rx buffer.
45  * @pDev: sdio device context
46  *
47  *
48  * Return: htc buffer pointer
49  */
50 HTC_PACKET *hif_dev_alloc_rx_buffer(struct hif_sdio_device *pdev)
51 {
52 	HTC_PACKET *packet;
53 	qdf_nbuf_t netbuf;
54 	uint32_t bufsize = 0, headsize = 0;
55 
56 	bufsize = HIF_SDIO_RX_BUFFER_SIZE + HIF_SDIO_RX_DATA_OFFSET;
57 	headsize = sizeof(HTC_PACKET);
58 	netbuf = qdf_nbuf_alloc(NULL, bufsize + headsize, 0, 4, false);
59 	if (!netbuf) {
60 		hif_err_rl("Allocate netbuf failed");
61 		return NULL;
62 	}
63 	packet = (HTC_PACKET *) qdf_nbuf_data(netbuf);
64 	qdf_nbuf_reserve(netbuf, headsize);
65 
66 	SET_HTC_PACKET_INFO_RX_REFILL(packet,
67 				      pdev,
68 				      qdf_nbuf_data(netbuf),
69 				      bufsize, ENDPOINT_0);
70 	SET_HTC_PACKET_NET_BUF_CONTEXT(packet, netbuf);
71 	return packet;
72 }
73 
74 /**
75  * hif_dev_create() - create hif device after probe.
76  * @hif_device: HIF context
77  * @callbacks: htc callbacks
78  * @target: HIF target
79  *
80  *
81  * Return: int
82  */
83 struct hif_sdio_device *hif_dev_create(struct hif_sdio_dev *hif_device,
84 			struct hif_msg_callbacks *callbacks, void *target)
85 {
86 
87 	QDF_STATUS status;
88 	struct hif_sdio_device *pdev;
89 
90 	HIF_ENTER();
91 	pdev = qdf_mem_malloc(sizeof(struct hif_sdio_device));
92 	if (!pdev) {
93 		A_ASSERT(false);
94 		return NULL;
95 	}
96 
97 	qdf_spinlock_create(&pdev->Lock);
98 	qdf_spinlock_create(&pdev->TxLock);
99 	qdf_spinlock_create(&pdev->RxLock);
100 
101 	pdev->HIFDevice = hif_device;
102 	pdev->pTarget = target;
103 	status = hif_configure_device(NULL, hif_device,
104 				      HIF_DEVICE_SET_HTC_CONTEXT,
105 				      (void *)pdev, sizeof(pdev));
106 	if (status != QDF_STATUS_SUCCESS)
107 		HIF_ERROR("%s: set context failed", __func__);
108 
109 	A_MEMCPY(&pdev->hif_callbacks, callbacks, sizeof(*callbacks));
110 
111 	HIF_EXIT();
112 	return pdev;
113 }
114 
115 /**
116  * hif_dev_destroy() - destroy hif device.
117  * @pDev: sdio device context
118  *
119  *
120  * Return: none
121  */
122 void hif_dev_destroy(struct hif_sdio_device *pdev)
123 {
124 	QDF_STATUS status;
125 
126 	status = hif_configure_device(NULL, pdev->HIFDevice,
127 				      HIF_DEVICE_SET_HTC_CONTEXT,
128 				      (void *)NULL, 0);
129 	if (status != QDF_STATUS_SUCCESS)
130 		HIF_ERROR("%s: set context failed", __func__);
131 
132 	qdf_mem_free(pdev);
133 }
134 
135 /**
136  * hif_dev_from_hif() - get sdio device from hif device.
137  * @pDev: hif device context
138  *
139  *
140  * Return: hif sdio device context
141  */
142 struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device)
143 {
144 	struct hif_sdio_device *pdev = NULL;
145 	QDF_STATUS status;
146 
147 	status = hif_configure_device(NULL, hif_device,
148 				      HIF_DEVICE_GET_HTC_CONTEXT,
149 				      (void **)&pdev,
150 				      sizeof(struct hif_sdio_device));
151 	if (status != QDF_STATUS_SUCCESS)
152 		HIF_ERROR("%s: set context failed", __func__);
153 
154 	return pdev;
155 }
156 
157 /**
158  * hif_dev_disable_interrupts() - disable hif device interrupts.
159  * @pDev: sdio device context
160  *
161  *
162  * Return: int
163  */
164 QDF_STATUS hif_dev_disable_interrupts(struct hif_sdio_device *pdev)
165 {
166 	QDF_STATUS status = QDF_STATUS_SUCCESS;
167 
168 	HIF_ENTER();
169 
170 	hif_dev_mask_interrupts(pdev);
171 
172 	/* To Do mask the host controller interrupts */
173 	hif_mask_interrupt(pdev->HIFDevice);
174 
175 	HIF_EXIT();
176 	return status;
177 }
178 
179 /**
180  * hif_dev_enable_interrupts() - enables hif device interrupts.
181  * @pDev: sdio device context
182  *
183  *
184  * Return: int
185  */
186 QDF_STATUS hif_dev_enable_interrupts(struct hif_sdio_device *pdev)
187 {
188 	QDF_STATUS status;
189 
190 	HIF_ENTER();
191 
192 	/* for good measure, make sure interrupt are disabled
193 	 * before unmasking at the HIF layer.
194 	 * The rationale here is that between device insertion
195 	 * (where we clear the interrupts the first time)
196 	 * and when HTC is finally ready to handle interrupts,
197 	 * other software can perform target "soft" resets.
198 	 */
199 	status = hif_dev_disable_interrupts(pdev);
200 
201 	/* Unmask the host controller interrupts */
202 	hif_un_mask_interrupt(pdev->HIFDevice);
203 
204 	hif_dev_unmask_interrupts(pdev);
205 
206 	HIF_EXIT();
207 
208 	return status;
209 }
210 
211 /**
212  * hif_dev_setup() - set up sdio device.
213  * @pDev: sdio device context
214  *
215  *
216  * Return: int
217  */
218 QDF_STATUS hif_dev_setup(struct hif_sdio_device *pdev)
219 {
220 	QDF_STATUS status;
221 	struct htc_callbacks htc_cbs;
222 	struct hif_sdio_dev *hif_device = pdev->HIFDevice;
223 
224 	HIF_ENTER();
225 
226 	status = hif_dev_setup_device(pdev);
227 
228 	if (status != QDF_STATUS_SUCCESS) {
229 		HIF_ERROR("%s: device specific setup failed", __func__);
230 		return QDF_STATUS_E_INVAL;
231 	}
232 
233 	pdev->BlockMask = pdev->BlockSize - 1;
234 	A_ASSERT((pdev->BlockSize & pdev->BlockMask) == 0);
235 
236 	/* assume we can process HIF interrupt events asynchronously */
237 	pdev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC;
238 
239 	/* see if the HIF layer overrides this assumption */
240 	hif_configure_device(NULL, hif_device,
241 			     HIF_DEVICE_GET_IRQ_PROC_MODE,
242 			     &pdev->HifIRQProcessingMode,
243 			     sizeof(pdev->HifIRQProcessingMode));
244 
245 	switch (pdev->HifIRQProcessingMode) {
246 	case HIF_DEVICE_IRQ_SYNC_ONLY:
247 		AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
248 			("HIF Interrupt processing is SYNC ONLY\n"));
249 		/* see if HIF layer wants HTC to yield */
250 		hif_configure_device(NULL, hif_device,
251 				     HIF_DEVICE_GET_IRQ_YIELD_PARAMS,
252 				     &pdev->HifIRQYieldParams,
253 				     sizeof(pdev->HifIRQYieldParams));
254 
255 		if (pdev->HifIRQYieldParams.recv_packet_yield_count > 0) {
256 			AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
257 				("HIF req of DSR yield per %d RECV packets\n",
258 				 pdev->HifIRQYieldParams.
259 				 recv_packet_yield_count));
260 			pdev->DSRCanYield = true;
261 		}
262 		break;
263 	case HIF_DEVICE_IRQ_ASYNC_SYNC:
264 		AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
265 			("HIF Interrupt processing is ASYNC and SYNC\n"));
266 		break;
267 	default:
268 		A_ASSERT(false);
269 		break;
270 	}
271 
272 	pdev->HifMaskUmaskRecvEvent = NULL;
273 
274 	/* see if the HIF layer implements the mask/unmask recv
275 	 * events function
276 	 */
277 	hif_configure_device(NULL, hif_device,
278 			     HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC,
279 			     &pdev->HifMaskUmaskRecvEvent,
280 			     sizeof(pdev->HifMaskUmaskRecvEvent));
281 
282 	status = hif_dev_disable_interrupts(pdev);
283 
284 	qdf_mem_zero(&htc_cbs, sizeof(struct htc_callbacks));
285 	/* the device layer handles these */
286 	htc_cbs.rw_compl_handler = hif_dev_rw_completion_handler;
287 	htc_cbs.dsr_handler = hif_dev_dsr_handler;
288 	htc_cbs.context = pdev;
289 	status = hif_attach_htc(pdev->HIFDevice, &htc_cbs);
290 
291 	HIF_EXIT();
292 	return status;
293 }
294