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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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