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