1 /*
2 * Copyright (c) 2013-2019 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 #include <linux/mmc/card.h>
21 #include <linux/mmc/host.h>
22 #include <linux/mmc/sdio_func.h>
23 #include <linux/mmc/sdio_ids.h>
24 #include <linux/mmc/sdio.h>
25 #include <linux/kthread.h>
26 #include "hif_internal.h"
27 #include <qdf_mem.h>
28 #include "dl_list.h"
29 #define ATH_MODULE_NAME hif
30 #include "a_debug.h"
31 #include <transfer/transfer.h>
32
33 #ifdef HIF_LINUX_MMC_SCATTER_SUPPORT
34
35 #define _CMD53_ARG_READ 0
36 #define _CMD53_ARG_WRITE 1
37 #define _CMD53_ARG_BLOCK_BASIS 1
38 #define _CMD53_ARG_FIXED_ADDRESS 0
39 #define _CMD53_ARG_INCR_ADDRESS 1
40
41 #define SDIO_SET_CMD53_ARG(arg, rw, func, mode, opcode, address, bytes_blocks) \
42 ((arg) = (((rw) & 1) << 31) | \
43 ((func & 0x7) << 28) | \
44 (((mode) & 1) << 27) | \
45 (((opcode) & 1) << 26) | \
46 (((address) & 0x1FFFF) << 9) | \
47 ((bytes_blocks) & 0x1FF))
48
49 /**
50 * free_scatter_req() - free scattered request.
51 * @device: hif device context
52 * @pReq: scatter list node
53 *
54 * Return: none
55 */
free_scatter_req(struct hif_sdio_dev * device,struct _HIF_SCATTER_REQ * pReq)56 static void free_scatter_req(struct hif_sdio_dev *device,
57 struct _HIF_SCATTER_REQ *pReq)
58 {
59 qdf_spin_lock_irqsave(&device->lock);
60
61 dl_list_insert_tail(&device->scatter_req_head, &pReq->list_link);
62
63 qdf_spin_unlock_irqrestore(&device->lock);
64 }
65
66 /**
67 * alloc_scatter_req() - allocate scattered request.
68 * @device: hif device context
69 *
70 *
71 * Return: pointer to allocated scatter list node
72 */
alloc_scatter_req(struct hif_sdio_dev * device)73 static struct _HIF_SCATTER_REQ *alloc_scatter_req(struct hif_sdio_dev *device)
74 {
75 DL_LIST *item;
76
77 qdf_spin_lock_irqsave(&device->lock);
78
79 item = dl_list_remove_item_from_head(&device->scatter_req_head);
80
81 qdf_spin_unlock_irqrestore(&device->lock);
82
83 if (item)
84 return A_CONTAINING_STRUCT(item,
85 struct _HIF_SCATTER_REQ, list_link);
86
87 return NULL;
88 }
89
90 /**
91 * do_hif_read_write_scatter() - rd/wr scattered operation.
92 * @device: hif device context
93 * @busrequest: rd/wr bus request
94 *
95 * called by async task to perform the operation synchronously
96 * using direct MMC APIs
97 * Return: int
98 */
do_hif_read_write_scatter(struct hif_sdio_dev * device,struct bus_request * busrequest)99 QDF_STATUS do_hif_read_write_scatter(struct hif_sdio_dev *device,
100 struct bus_request *busrequest)
101 {
102 int i;
103 uint8_t rw;
104 uint8_t opcode;
105 struct mmc_request mmcreq;
106 struct mmc_command cmd;
107 struct mmc_data data;
108 struct HIF_SCATTER_REQ_PRIV *req_priv;
109 struct _HIF_SCATTER_REQ *req;
110 QDF_STATUS status = QDF_STATUS_SUCCESS;
111 struct scatterlist *sg;
112
113 HIF_ENTER();
114
115 req_priv = busrequest->scatter_req;
116
117 A_ASSERT(req_priv);
118 if (!req_priv) {
119 return QDF_STATUS_E_FAILURE;
120 }
121
122 req = req_priv->hif_scatter_req;
123
124 memset(&mmcreq, 0, sizeof(struct mmc_request));
125 memset(&cmd, 0, sizeof(struct mmc_command));
126 memset(&data, 0, sizeof(struct mmc_data));
127
128 data.blksz = HIF_BLOCK_SIZE;
129 data.blocks = req->total_length / HIF_BLOCK_SIZE;
130
131 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
132 ("HIF-SCATTER: (%s) Address: 0x%X, (BlockLen: %d, BlockCount: %d), (tot:%d,sg:%d)\n",
133 (req->request & HIF_SDIO_WRITE) ? "WRITE" : "READ",
134 req->address, data.blksz, data.blocks,
135 req->total_length, req->valid_scatter_entries));
136
137 if (req->request & HIF_SDIO_WRITE) {
138 rw = _CMD53_ARG_WRITE;
139 data.flags = MMC_DATA_WRITE;
140 } else {
141 rw = _CMD53_ARG_READ;
142 data.flags = MMC_DATA_READ;
143 }
144
145 if (req->request & HIF_FIXED_ADDRESS)
146 opcode = _CMD53_ARG_FIXED_ADDRESS;
147 else
148 opcode = _CMD53_ARG_INCR_ADDRESS;
149
150 /* fill SG entries */
151 sg = req_priv->sgentries;
152 sg_init_table(sg, req->valid_scatter_entries);
153
154 /* assemble SG list */
155 for (i = 0; i < req->valid_scatter_entries; i++, sg++) {
156 /* setup each sg entry */
157 if ((unsigned long)req->scatter_list[i].buffer & 0x3) {
158 /* note some scatter engines can handle unaligned
159 * buffers, print this as informational only
160 */
161 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
162 ("HIF: (%s) Scatter Buf is unaligned 0x%lx\n",
163 req->
164 request & HIF_SDIO_WRITE ? "WRITE" : "READ",
165 (unsigned long)req->scatter_list[i].
166 buffer));
167 }
168
169 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
170 (" %d: Addr:0x%lX, Len:%d\n", i,
171 (unsigned long)req->scatter_list[i].buffer,
172 req->scatter_list[i].length));
173
174 sg_set_buf(sg, req->scatter_list[i].buffer,
175 req->scatter_list[i].length);
176 }
177 /* set scatter-gather table for request */
178 data.sg = req_priv->sgentries;
179 data.sg_len = req->valid_scatter_entries;
180 /* set command argument */
181 SDIO_SET_CMD53_ARG(cmd.arg,
182 rw,
183 device->func->num,
184 _CMD53_ARG_BLOCK_BASIS,
185 opcode, req->address, data.blocks);
186
187 cmd.opcode = SD_IO_RW_EXTENDED;
188 cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
189
190 mmcreq.cmd = &cmd;
191 mmcreq.data = &data;
192
193 mmc_set_data_timeout(&data, device->func->card);
194 /* synchronous call to process request */
195 mmc_wait_for_req(device->func->card->host, &mmcreq);
196
197 if (cmd.error) {
198 status = QDF_STATUS_E_FAILURE;
199 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
200 ("HIF-SCATTER: cmd error: %d\n", cmd.error));
201 }
202
203 if (data.error) {
204 status = QDF_STATUS_E_FAILURE;
205 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
206 ("HIF-SCATTER: data error: %d\n", data.error));
207 }
208
209 if (QDF_IS_STATUS_ERROR(status)) {
210 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
211 ("HIF-SCATTER: FAILED!!! (%s) Address: 0x%X, Block mode (BlockLen: %d, BlockCount: %d)\n",
212 (req->request & HIF_SDIO_WRITE) ? "WRITE" : "READ",
213 req->address, data.blksz, data.blocks));
214 }
215
216 /* set completion status, fail or success */
217 req->completion_status = status;
218
219 if (req->request & HIF_ASYNCHRONOUS) {
220 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
221 ("HIF-SCATTER: async_task completion routine req: 0x%lX (%d)\n",
222 (unsigned long)busrequest, status));
223 /* complete the request */
224 A_ASSERT(req->completion_routine);
225 if (req->completion_routine) {
226 req->completion_routine(req);
227 }
228 } else {
229 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
230 ("HIF-SCATTER async_task upping busreq : 0x%lX (%d)\n",
231 (unsigned long)busrequest, status));
232 /* signal wait */
233 up(&busrequest->sem_req);
234 }
235 HIF_EXIT();
236
237 return status;
238 }
239
240 /**
241 * hif_read_write_scatter() - callback to issue a read-write
242 * scatter request.
243 * @device: hif device context
244 * @req: rd/wr scatter request
245 *
246 * Return: QDF_STATUS
247 */
hif_read_write_scatter(struct hif_sdio_dev * device,struct _HIF_SCATTER_REQ * req)248 static QDF_STATUS hif_read_write_scatter(struct hif_sdio_dev *device,
249 struct _HIF_SCATTER_REQ *req)
250 {
251 QDF_STATUS status = QDF_STATUS_E_INVAL;
252 uint32_t request = req->request;
253 struct HIF_SCATTER_REQ_PRIV *req_priv =
254 (struct HIF_SCATTER_REQ_PRIV *) req->hif_private[0];
255
256 do {
257
258 A_ASSERT(req_priv);
259 if (!req_priv) {
260 break;
261 }
262
263 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
264 ("HIF-SCATTER: total len: %d Scatter Entries: %d\n",
265 req->total_length,
266 req->valid_scatter_entries));
267
268 if (!(request & HIF_EXTENDED_IO)) {
269 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
270 ("HIF-SCATTER: Invalid command type: 0x%08x\n",
271 request));
272 break;
273 }
274
275 if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) {
276 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
277 ("HIF-SCATTER: Invalid mode: 0x%08x\n",
278 request));
279 break;
280 }
281
282 if (!(request & HIF_BLOCK_BASIS)) {
283 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
284 ("HIF-SCATTER: Invalid data mode: 0x%08x\n",
285 request));
286 break;
287 }
288
289 if (req->total_length > MAX_SCATTER_REQ_TRANSFER_SIZE) {
290 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
291 ("HIF-SCATTER: Invalid length: %d\n",
292 req->total_length));
293 break;
294 }
295
296 if (req->total_length == 0) {
297 A_ASSERT(false);
298 break;
299 }
300
301 /* add bus request to the async list for the async
302 * I/O thread to process
303 */
304 add_to_async_list(device, req_priv->busrequest);
305
306 if (request & HIF_SYNCHRONOUS) {
307 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
308 ("HIF-SCATTER: queued sync req: 0x%lX\n",
309 (unsigned long)req_priv->busrequest));
310 /* signal thread and wait */
311 up(&device->sem_async);
312 if (down_interruptible(&req_priv->busrequest->sem_req)
313 != 0) {
314 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
315 ("HIF-SCATTER: interrupted!\n"));
316 /* interrupted, exit */
317 status = QDF_STATUS_E_FAILURE;
318 break;
319 }
320 status = req->completion_status;
321 } else {
322 AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER,
323 ("HIF-SCATTER: queued async req: 0x%lX\n",
324 (unsigned long)req_priv->busrequest));
325 /* wake thread, it will process and then take
326 * care of the async callback
327 */
328 up(&device->sem_async);
329 status = QDF_STATUS_SUCCESS;
330 }
331
332 } while (false);
333
334 if (QDF_IS_STATUS_ERROR(status) && (request & HIF_ASYNCHRONOUS)) {
335 req->completion_status = status;
336 req->completion_routine(req);
337 status = QDF_STATUS_SUCCESS;
338 }
339
340 return status;
341 }
342
343 /**
344 * setup_hif_scatter_support() - setup of HIF scatter resources
345 * scatter request.
346 * @device: hif device context
347 * @info: scatter info
348 *
349 * Return: int
350 */
setup_hif_scatter_support(struct hif_sdio_dev * device,struct HIF_DEVICE_SCATTER_SUPPORT_INFO * info)351 QDF_STATUS setup_hif_scatter_support(struct hif_sdio_dev *device,
352 struct HIF_DEVICE_SCATTER_SUPPORT_INFO *info)
353 {
354 QDF_STATUS status = QDF_STATUS_E_FAILURE;
355 int i;
356 struct HIF_SCATTER_REQ_PRIV *req_priv;
357 struct bus_request *busrequest;
358
359 if (device->func->card->host->max_segs <
360 MAX_SCATTER_ENTRIES_PER_REQ) {
361 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
362 ("host only supports scatter of : %d entries, need: %d\n",
363 device->func->card->host->max_segs,
364 MAX_SCATTER_ENTRIES_PER_REQ));
365 status = QDF_STATUS_E_NOSUPPORT;
366 goto end;
367 }
368
369 AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
370 ("max scatter req : %d entries: %d\n",
371 MAX_SCATTER_REQUESTS,
372 MAX_SCATTER_ENTRIES_PER_REQ));
373
374 for (i = 0; i < MAX_SCATTER_REQUESTS; i++) {
375 /* allocate the private request blob */
376 req_priv =
377 (struct HIF_SCATTER_REQ_PRIV *)
378 qdf_mem_malloc(sizeof(
379 struct HIF_SCATTER_REQ_PRIV));
380 if (!req_priv)
381 goto end;
382 /* save the device instance */
383 req_priv->device = device;
384 /* allocate the scatter request */
385 req_priv->hif_scatter_req =
386 (struct _HIF_SCATTER_REQ *)
387 qdf_mem_malloc(sizeof(struct _HIF_SCATTER_REQ) +
388 (MAX_SCATTER_ENTRIES_PER_REQ -
389 1) * (sizeof(struct _HIF_SCATTER_ITEM)));
390
391 if (!req_priv->hif_scatter_req) {
392 qdf_mem_free(req_priv);
393 goto end;
394 }
395 /* back pointer to the private struct */
396 req_priv->hif_scatter_req->hif_private[0] = req_priv;
397 /* allocate a bus request for this scatter request */
398 busrequest = hif_allocate_bus_request(device);
399 if (!busrequest) {
400 qdf_mem_free(req_priv->hif_scatter_req);
401 qdf_mem_free(req_priv);
402 goto end;
403 }
404 /* assign the scatter request to this bus request */
405 busrequest->scatter_req = req_priv;
406 /* point back to the request */
407 req_priv->busrequest = busrequest;
408 /* req_priv it to the scatter pool */
409 free_scatter_req(device, req_priv->hif_scatter_req);
410 }
411
412 if (i != MAX_SCATTER_REQUESTS) {
413 status = QDF_STATUS_E_NOMEM;
414 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
415 ("failed to alloc scatter resources !\n"));
416 goto end;
417 }
418
419 /* set scatter function pointers */
420 info->allocate_req_func = alloc_scatter_req;
421 info->free_req_func = free_scatter_req;
422 info->read_write_scatter_func = hif_read_write_scatter;
423 info->max_scatter_entries = MAX_SCATTER_ENTRIES_PER_REQ;
424 info->max_tx_size_per_scatter_req =
425 MAX_SCATTER_REQ_TRANSFER_SIZE;
426
427 status = QDF_STATUS_SUCCESS;
428
429 end:
430 if (QDF_IS_STATUS_ERROR(status))
431 cleanup_hif_scatter_resources(device);
432
433 return status;
434 }
435
436 /**
437 * cleanup_hif_scatter_resources() - cleanup HIF scatter resources
438 * scatter request.
439 * @device: hif device context
440 *
441 *
442 * Return: none
443 */
cleanup_hif_scatter_resources(struct hif_sdio_dev * device)444 void cleanup_hif_scatter_resources(struct hif_sdio_dev *device)
445 {
446 struct HIF_SCATTER_REQ_PRIV *req_priv;
447 struct _HIF_SCATTER_REQ *req;
448
449 /* empty the free list */
450
451 while (true) {
452 req = alloc_scatter_req(device);
453
454 if (!req)
455 break;
456
457 req_priv = (struct HIF_SCATTER_REQ_PRIV *)req->hif_private[0];
458 A_ASSERT(req_priv);
459 if (!req_priv) {
460 continue;
461 }
462
463 if (req_priv->busrequest) {
464 req_priv->busrequest->scatter_req = NULL;
465 /* free bus request */
466 hif_free_bus_request(device, req_priv->busrequest);
467 req_priv->busrequest = NULL;
468 }
469
470 if (req_priv->hif_scatter_req) {
471 qdf_mem_free(req_priv->hif_scatter_req);
472 req_priv->hif_scatter_req = NULL;
473 }
474
475 qdf_mem_free(req_priv);
476 }
477 }
478
479 #endif /* HIF_LINUX_MMC_SCATTER_SUPPORT */
480