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