1 /* 2 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. 3 * 4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc. 5 * 6 * 7 * Permission to use, copy, modify, and/or distribute this software for 8 * any purpose with or without fee is hereby granted, provided that the 9 * above copyright notice and this permission notice appear in all 10 * copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 19 * PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 /* 23 * This file was originally distributed by Qualcomm Atheros, Inc. 24 * under proprietary terms before Copyright ownership was assigned 25 * to the Linux Foundation. 26 */ 27 28 #ifndef EXPORT_SYMTAB 29 #define EXPORT_SYMTAB 30 #endif 31 32 #include <osdep.h> 33 #include <linux/slab.h> 34 #include <linux/interrupt.h> 35 #include <linux/if_arp.h> 36 #include <linux/mmc/card.h> 37 #include <linux/mmc/mmc.h> 38 #include <linux/mmc/host.h> 39 #include <linux/mmc/sdio_func.h> 40 #include <linux/mmc/sdio_ids.h> 41 #include <linux/mmc/sdio.h> 42 #include <linux/mmc/sd.h> 43 #include <linux/wait.h> 44 #include <qdf_mem.h> 45 #include "if_sdio.h" 46 #include <qdf_trace.h> 47 #include <cds_api.h> 48 #include "regtable_sdio.h" 49 #include <hif_debug.h> 50 #include "target_type.h" 51 #include "epping_main.h" 52 #include "pld_sdio.h" 53 #include "targaddrs.h" 54 #include "sdio_api.h" 55 #ifndef REMOVE_PKT_LOG 56 #include "ol_txrx_types.h" 57 #include "pktlog_ac_api.h" 58 #include "pktlog_ac.h" 59 #endif 60 61 #ifndef ATH_BUS_PM 62 #ifdef CONFIG_PM 63 #define ATH_BUS_PM 64 #endif /* CONFIG_PM */ 65 #endif /* ATH_BUS_PM */ 66 67 #ifndef REMOVE_PKT_LOG 68 struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs; 69 #endif 70 #define HIF_SDIO_LOAD_TIMEOUT 1000 71 72 struct hif_sdio_softc *scn; 73 struct hif_softc *ol_sc; 74 static atomic_t hif_sdio_load_state; 75 /* Wait queue for MC thread */ 76 wait_queue_head_t sync_wait_queue; 77 78 /** 79 * hif_sdio_probe() - configure sdio device 80 * @context: sdio device context 81 * @hif_handle: pointer to hif handle 82 * 83 * Return: 0 for success and non-zero for failure 84 */ 85 static A_STATUS hif_sdio_probe(void *context, void *hif_handle) 86 { 87 int ret = 0; 88 struct HIF_DEVICE_OS_DEVICE_INFO os_dev_info; 89 struct sdio_func *func = NULL; 90 const struct sdio_device_id *id; 91 uint32_t target_type; 92 93 HIF_ENTER(); 94 scn = (struct hif_sdio_softc *)qdf_mem_malloc(sizeof(*scn)); 95 if (!scn) { 96 ret = -ENOMEM; 97 goto err_alloc; 98 } 99 100 scn->hif_handle = hif_handle; 101 hif_configure_device(hif_handle, HIF_DEVICE_GET_OS_DEVICE, 102 &os_dev_info, 103 sizeof(os_dev_info)); 104 105 scn->aps_osdev.device = os_dev_info.os_dev; 106 scn->aps_osdev.bc.bc_bustype = QDF_BUS_TYPE_SDIO; 107 spin_lock_init(&scn->target_lock); 108 ol_sc = qdf_mem_malloc(sizeof(*ol_sc)); 109 if (!ol_sc) { 110 ret = -ENOMEM; 111 goto err_attach; 112 } 113 OS_MEMZERO(ol_sc, sizeof(*ol_sc)); 114 115 { 116 /* 117 * Attach Target register table. This is needed early on 118 * even before BMI since PCI and HIF initialization 119 * directly access Target registers. 120 * 121 * TBDXXX: targetdef should not be global -- should be stored 122 * in per-device struct so that we can support multiple 123 * different Target types with a single Host driver. 124 * The whole notion of an "hif type" -- (not as in the hif 125 * module, but generic "Host Interface Type") is bizarre. 126 * At first, one one expect it to be things like SDIO, USB, PCI. 127 * But instead, it's an actual platform type. Inexplicably, the 128 * values used for HIF platform types are *different* from the 129 * values used for Target Types. 130 */ 131 132 #if defined(CONFIG_AR9888_SUPPORT) 133 hif_register_tbl_attach(ol_sc, HIF_TYPE_AR9888); 134 target_register_tbl_attach(ol_sc, TARGET_TYPE_AR9888); 135 target_type = TARGET_TYPE_AR9888; 136 #elif defined(CONFIG_AR6320_SUPPORT) 137 id = ((struct hif_sdio_dev *) hif_handle)->id; 138 if (((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == 139 MANUFACTURER_ID_QCA9377_BASE) || 140 ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == 141 MANUFACTURER_ID_QCA9379_BASE)) { 142 hif_register_tbl_attach(ol_sc, HIF_TYPE_AR6320V2); 143 target_register_tbl_attach(ol_sc, TARGET_TYPE_AR6320V2); 144 } else if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == 145 MANUFACTURER_ID_AR6320_BASE) { 146 int ar6kid = id->device & MANUFACTURER_ID_AR6K_REV_MASK; 147 148 if (ar6kid >= 1) { 149 /* v2 or higher silicon */ 150 hif_register_tbl_attach(ol_sc, 151 HIF_TYPE_AR6320V2); 152 target_register_tbl_attach(ol_sc, 153 TARGET_TYPE_AR6320V2); 154 } else { 155 /* legacy v1 silicon */ 156 hif_register_tbl_attach(ol_sc, 157 HIF_TYPE_AR6320); 158 target_register_tbl_attach(ol_sc, 159 TARGET_TYPE_AR6320); 160 } 161 } 162 target_type = TARGET_TYPE_AR6320; 163 164 #endif 165 } 166 func = ((struct hif_sdio_dev *) hif_handle)->func; 167 scn->targetdef = ol_sc->targetdef; 168 scn->hostdef = ol_sc->hostdef; 169 scn->aps_osdev.bdev = func; 170 ol_sc->bus_type = scn->aps_osdev.bc.bc_bustype; 171 scn->ol_sc = *ol_sc; 172 ol_sc->target_info.target_type = target_type; 173 174 scn->ramdump_base = pld_hif_sdio_get_virt_ramdump_mem( 175 scn->aps_osdev.device, 176 &scn->ramdump_size); 177 if (scn->ramdump_base == NULL || !scn->ramdump_size) { 178 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, 179 "%s: Failed to get RAM dump memory address or size!\n", 180 __func__); 181 } else { 182 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, 183 "%s: ramdump base 0x%pK size %d\n", __func__, 184 scn->ramdump_base, (int)scn->ramdump_size); 185 } 186 187 if (athdiag_procfs_init(scn) != 0) { 188 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, 189 "%s athdiag_procfs_init failed", __func__); 190 ret = QDF_STATUS_E_FAILURE; 191 goto err_attach1; 192 } 193 194 atomic_set(&hif_sdio_load_state, true); 195 wake_up_interruptible(&sync_wait_queue); 196 197 return 0; 198 199 err_attach1: 200 if (scn->ramdump_base) 201 pld_hif_sdio_release_ramdump_mem(scn->ramdump_base); 202 qdf_mem_free(ol_sc); 203 err_attach: 204 qdf_mem_free(scn); 205 scn = NULL; 206 err_alloc: 207 return ret; 208 } 209 210 /** 211 * hif_sdio_remove() - remove sdio device 212 * @conext: sdio device context 213 * @hif_handle: pointer to sdio function 214 * 215 * Return: 0 for success and non-zero for failure 216 */ 217 static A_STATUS hif_sdio_remove(void *context, void *hif_handle) 218 { 219 HIF_ENTER(); 220 221 if (!scn) { 222 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, 223 "Global SDIO context is NULL"); 224 return A_ERROR; 225 } 226 227 atomic_set(&hif_sdio_load_state, false); 228 athdiag_procfs_remove(); 229 230 #ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM 231 iounmap(scn->ramdump_base); 232 #endif 233 234 if (ol_sc) { 235 qdf_mem_free(ol_sc); 236 ol_sc = NULL; 237 } 238 239 if (scn) { 240 qdf_mem_free(scn); 241 scn = NULL; 242 } 243 244 HIF_EXIT(); 245 246 return 0; 247 } 248 249 /** 250 * hif_sdio_suspend() - sdio suspend routine 251 * @context: sdio device context 252 * 253 * Return: 0 for success and non-zero for failure 254 */ 255 static A_STATUS hif_sdio_suspend(void *context) 256 { 257 return 0; 258 } 259 260 /** 261 * hif_sdio_resume() - sdio resume routine 262 * @context: sdio device context 263 * 264 * Return: 0 for success and non-zero for failure 265 */ 266 static A_STATUS hif_sdio_resume(void *context) 267 { 268 return 0; 269 } 270 271 /** 272 * hif_sdio_power_change() - change power state of sdio bus 273 * @conext: sdio device context 274 * @config: power state configurartion 275 * 276 * Return: 0 for success and non-zero for failure 277 */ 278 static A_STATUS hif_sdio_power_change(void *context, uint32_t config) 279 { 280 return 0; 281 } 282 283 /* 284 * Module glue. 285 */ 286 #include <linux/version.h> 287 static char *version = "HIF (Atheros/multi-bss)"; 288 static char *dev_info = "ath_hif_sdio"; 289 290 /** 291 * init_ath_hif_sdio() - initialize hif sdio callbacks 292 * @param: none 293 * 294 * Return: 0 for success and non-zero for failure 295 */ 296 static int init_ath_hif_sdio(void) 297 { 298 QDF_STATUS status; 299 struct osdrv_callbacks osdrv_callbacks; 300 301 HIF_ENTER(); 302 qdf_mem_zero(&osdrv_callbacks, sizeof(osdrv_callbacks)); 303 osdrv_callbacks.device_inserted_handler = hif_sdio_probe; 304 osdrv_callbacks.device_removed_handler = hif_sdio_remove; 305 osdrv_callbacks.device_suspend_handler = hif_sdio_suspend; 306 osdrv_callbacks.device_resume_handler = hif_sdio_resume; 307 osdrv_callbacks.device_power_change_handler = hif_sdio_power_change; 308 309 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, "%s %d", __func__, 310 __LINE__); 311 status = hif_init(&osdrv_callbacks); 312 if (status != QDF_STATUS_SUCCESS) { 313 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL, 314 "%s hif_init failed!", __func__); 315 return -ENODEV; 316 } 317 QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, 318 "%s: %s\n", dev_info, version); 319 320 return 0; 321 } 322 323 /** 324 * hif_sdio_bus_suspend() - suspend the bus 325 * 326 * This function suspends the bus, but sdio doesn't need to suspend. 327 * Therefore do nothing. 328 * 329 * Return: 0 for success and non-zero for failure 330 */ 331 int hif_sdio_bus_suspend(struct hif_softc *hif_ctx) 332 { 333 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); 334 struct hif_sdio_dev *hif_device = scn->hif_handle; 335 struct device *dev = &hif_device->func->dev; 336 337 hif_device_suspend(dev); 338 return 0; 339 } 340 341 342 /** 343 * hif_sdio_bus_resume() - hif resume API 344 * 345 * This function resumes the bus. but sdio doesn't need to resume. 346 * Therefore do nothing. 347 * 348 * Return: 0 for success and non-zero for failure 349 */ 350 int hif_sdio_bus_resume(struct hif_softc *hif_ctx) 351 { 352 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); 353 struct hif_sdio_dev *hif_device = scn->hif_handle; 354 struct device *dev = &hif_device->func->dev; 355 356 hif_device_resume(dev); 357 return 0; 358 } 359 360 /** 361 * hif_enable_power_gating() - enable HW power gating 362 * 363 * Return: n/a 364 */ 365 void hif_enable_power_gating(void *hif_ctx) 366 { 367 } 368 369 /** 370 * hif_sdio_close() - hif_bus_close 371 * 372 * Return: None 373 */ 374 void hif_sdio_close(struct hif_softc *hif_sc) 375 { 376 if (ol_sc) { 377 qdf_mem_free(ol_sc); 378 ol_sc = NULL; 379 } 380 381 if (scn) { 382 qdf_mem_free(scn); 383 scn = NULL; 384 } 385 } 386 387 /** 388 * hif_sdio_open() - hif_bus_open 389 * @hif_sc: hif context 390 * @bus_type: bus type 391 * 392 * Return: QDF status 393 */ 394 QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc, 395 enum qdf_bus_type bus_type) 396 { 397 QDF_STATUS status; 398 399 hif_sc->bus_type = bus_type; 400 status = init_ath_hif_sdio(); 401 402 return status; 403 } 404 405 void hif_get_target_revision(struct hif_softc *ol_sc) 406 { 407 struct hif_softc *ol_sc_local = (struct hif_softc *)ol_sc; 408 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc_local); 409 uint32_t chip_id = 0; 410 QDF_STATUS rv; 411 412 rv = hif_diag_read_access(hif_hdl, 413 (CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id); 414 if (rv != QDF_STATUS_SUCCESS) { 415 HIF_ERROR("%s[%d]: get chip id fail\n", __func__, __LINE__); 416 } else { 417 ol_sc_local->target_info.target_revision = 418 CHIP_ID_REVISION_GET(chip_id); 419 } 420 } 421 422 /** 423 * hif_sdio_enable_bus() - hif_enable_bus 424 * @hif_sc: hif context 425 * @dev: dev 426 * @bdev: bus dev 427 * @bid: bus id 428 * @type: bus type 429 * 430 * Return: QDF_STATUS 431 */ 432 QDF_STATUS hif_sdio_enable_bus(struct hif_softc *hif_sc, 433 struct device *dev, void *bdev, const struct hif_bus_id *bid, 434 enum hif_enable_type type) 435 { 436 int ret = 0; 437 const struct sdio_device_id *id = (const struct sdio_device_id *)bid; 438 struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); 439 440 init_waitqueue_head(&sync_wait_queue); 441 if (hif_sdio_device_inserted(dev, id)) { 442 HIF_ERROR("wlan: %s hif_sdio_device_inserted failed", __func__); 443 return QDF_STATUS_E_NOMEM; 444 } 445 446 wait_event_interruptible_timeout(sync_wait_queue, 447 atomic_read(&hif_sdio_load_state) == true, 448 HIF_SDIO_LOAD_TIMEOUT); 449 hif_sc->hostdef = ol_sc->hostdef; 450 hif_sc->targetdef = ol_sc->targetdef; 451 hif_sc->bus_type = ol_sc->bus_type; 452 hif_sc->target_info.target_type = ol_sc->target_info.target_type; 453 454 sc->hif_handle = scn->hif_handle; 455 sc->aps_osdev.device = scn->aps_osdev.device; 456 sc->aps_osdev.bc.bc_bustype = scn->aps_osdev.bc.bc_bustype; 457 sc->target_lock = scn->target_lock; 458 sc->targetdef = scn->targetdef; 459 sc->hostdef = scn->hostdef; 460 sc->aps_osdev.bdev = scn->aps_osdev.bdev; 461 sc->ramdump_size = scn->ramdump_size; 462 sc->ramdump_base = scn->ramdump_base; 463 464 return ret; 465 } 466 467 468 /** 469 * hif_sdio_disable_bus() - sdio disable bus 470 * @hif_sc: hif softc pointer 471 * 472 * Return: none 473 */ 474 void hif_sdio_disable_bus(struct hif_softc *hif_sc) 475 { 476 struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); 477 struct sdio_func *func = sc->aps_osdev.bdev; 478 479 hif_sdio_device_removed(func); 480 } 481 482 /** 483 * hif_sdio_get_config_item - sdio configure bus 484 * @hif_sc: hif context 485 * @opcode: configuration type 486 * @config: configuration value to set 487 * @config_len: configuration length 488 * 489 * Return: QDF_STATUS_SUCCESS for sucess 490 */ 491 QDF_STATUS hif_sdio_get_config_item(struct hif_softc *hif_sc, 492 int opcode, void *config, uint32_t config_len) 493 { 494 struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); 495 struct hif_sdio_dev *hif_device = sc->hif_handle; 496 497 return hif_configure_device(hif_device, 498 opcode, config, config_len); 499 } 500 501 /** 502 * hif_sdio_set_mailbox_swap - set mailbox swap 503 * @hif_sc: hif context 504 * 505 * Return: None 506 */ 507 void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc) 508 { 509 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc); 510 struct hif_sdio_dev *hif_device = scn->hif_handle; 511 512 hif_device->swap_mailbox = true; 513 } 514 515 /** 516 * hif_sdio_claim_device - set mailbox swap 517 * @hif_sc: hif context 518 * 519 * Return: None 520 */ 521 void hif_sdio_claim_device(struct hif_softc *hif_sc) 522 { 523 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc); 524 struct hif_sdio_dev *hif_device = scn->hif_handle; 525 526 hif_device->claimed_ctx = hif_sc; 527 } 528 529 /** 530 * hif_sdio_mask_interrupt_call() - disbale hif device irq 531 * @scn: pointr to softc structure 532 * 533 * Return: None 534 */ 535 void hif_sdio_mask_interrupt_call(struct hif_softc *scn) 536 { 537 struct hif_sdio_softc *hif_ctx = HIF_GET_SDIO_SOFTC(scn); 538 struct hif_sdio_dev *hif_device = hif_ctx->hif_handle; 539 540 hif_mask_interrupt(hif_device); 541 } 542 543 /** 544 * hif_trigger_dump() - trigger various dump cmd 545 * @scn: struct hif_opaque_softc 546 * @cmd_id: dump command id 547 * @start: start/stop dump 548 * 549 * Return: None 550 */ 551 void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start) 552 { 553 } 554 555 /** 556 * hif_check_fw_reg() - check fw selfrecovery indication 557 * @hif_ctx: hif_opaque_softc 558 * 559 * Return: int 560 */ 561 int hif_check_fw_reg(struct hif_opaque_softc *hif_ctx) 562 { 563 int ret = 1; 564 uint32_t fw_indication = 0; 565 struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); 566 567 if (hif_diag_read_access(hif_ctx, FW_INDICATOR_ADDRESS, 568 &fw_indication) != QDF_STATUS_SUCCESS) { 569 HIF_ERROR("%s Get fw indication failed\n", __func__); 570 return 1; 571 } 572 HIF_INFO("%s: fw indication is 0x%x def 0x%x.\n", __func__, 573 fw_indication, FW_IND_HELPER); 574 if (fw_indication & FW_IND_HELPER) 575 ret = 0; 576 577 return ret; 578 } 579 580 /** 581 * hif_wlan_disable() - call the platform driver to disable wlan 582 * @scn: scn 583 * 584 * Return: void 585 */ 586 void hif_wlan_disable(struct hif_softc *scn) 587 { 588 } 589 590 /** 591 * hif_sdio_needs_bmi() - return true if the soc needs bmi through the driver 592 * @scn: hif context 593 * 594 * Return: true if soc needs driver bmi otherwise false 595 */ 596 bool hif_sdio_needs_bmi(struct hif_softc *scn) 597 { 598 return true; 599 } 600