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