1 /* 2 * Copyright (c) 2016-2018, 2020 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 /* this file dispatches functions to bus specific definitions */ 20 #include "hif_debug.h" 21 #include "hif.h" 22 #include "hif_main.h" 23 #include "hif_io32.h" 24 #include "multibus.h" 25 #include "dummy.h" 26 #if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || \ 27 defined(HIF_IPCI) 28 #include "ce_main.h" 29 #include "ce_api.h" 30 #include "ce_internal.h" 31 #endif 32 #include "htc_services.h" 33 #include "a_types.h" 34 #include "dummy.h" 35 #include "qdf_module.h" 36 37 /** 38 * hif_initialize_default_ops() - initializes default operations values 39 * 40 * bus specific features should assign their dummy implementations here. 41 */ 42 static void hif_initialize_default_ops(struct hif_softc *hif_sc) 43 { 44 struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; 45 46 /* must be filled in by hif_bus_open */ 47 bus_ops->hif_bus_close = NULL; 48 /* dummy implementations */ 49 bus_ops->hif_display_stats = 50 &hif_dummy_display_stats; 51 bus_ops->hif_clear_stats = 52 &hif_dummy_clear_stats; 53 bus_ops->hif_set_bundle_mode = &hif_dummy_set_bundle_mode; 54 bus_ops->hif_bus_reset_resume = &hif_dummy_bus_reset_resume; 55 bus_ops->hif_bus_suspend_noirq = &hif_dummy_bus_suspend_noirq; 56 bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq; 57 bus_ops->hif_bus_early_suspend = &hif_dummy_bus_suspend; 58 bus_ops->hif_bus_late_resume = &hif_dummy_bus_resume; 59 bus_ops->hif_map_ce_to_irq = &hif_dummy_map_ce_to_irq; 60 bus_ops->hif_grp_irq_configure = &hif_dummy_grp_irq_configure; 61 bus_ops->hif_config_irq_affinity = 62 &hif_dummy_config_irq_affinity; 63 bus_ops->hif_config_irq_by_ceid = &hif_dummy_config_irq_by_ceid; 64 } 65 66 #define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *)) 67 68 /** 69 * hif_verify_basic_ops() - ensure required bus apis are defined 70 * 71 * all bus operations must be defined to avoid crashes 72 * itterate over the structure and ensure all function pointers 73 * are non null. 74 * 75 * Return: QDF_STATUS_SUCCESS if all the operations are defined 76 */ 77 static QDF_STATUS hif_verify_basic_ops(struct hif_softc *hif_sc) 78 { 79 struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; 80 void **ops_array = (void *)bus_ops; 81 QDF_STATUS status = QDF_STATUS_SUCCESS; 82 int i; 83 84 for (i = 0; i < NUM_OPS; i++) { 85 if (!ops_array[i]) { 86 hif_err("ops_array[%d] is null", i); 87 status = QDF_STATUS_E_NOSUPPORT; 88 } 89 } 90 return status; 91 } 92 93 /** 94 * hif_bus_get_context_size - API to return size of the bus specific structure 95 * 96 * Return: sizeof of hif_pci_softc 97 */ 98 int hif_bus_get_context_size(enum qdf_bus_type bus_type) 99 { 100 switch (bus_type) { 101 case QDF_BUS_TYPE_PCI: 102 return hif_pci_get_context_size(); 103 case QDF_BUS_TYPE_IPCI: 104 return hif_ipci_get_context_size(); 105 case QDF_BUS_TYPE_AHB: 106 return hif_ahb_get_context_size(); 107 case QDF_BUS_TYPE_SNOC: 108 return hif_snoc_get_context_size(); 109 case QDF_BUS_TYPE_SDIO: 110 return hif_sdio_get_context_size(); 111 case QDF_BUS_TYPE_USB: 112 return hif_usb_get_context_size(); 113 default: 114 return 0; 115 } 116 } 117 118 /** 119 * hif_bus_open() - initialize the bus_ops and call the bus specific open 120 * hif_sc: hif_context 121 * bus_type: type of bus being enumerated 122 * 123 * Return: QDF_STATUS_SUCCESS or error 124 */ 125 QDF_STATUS hif_bus_open(struct hif_softc *hif_sc, 126 enum qdf_bus_type bus_type) 127 { 128 QDF_STATUS status = QDF_STATUS_E_INVAL; 129 130 hif_initialize_default_ops(hif_sc); 131 132 switch (bus_type) { 133 case QDF_BUS_TYPE_PCI: 134 status = hif_initialize_pci_ops(hif_sc); 135 break; 136 case QDF_BUS_TYPE_IPCI: 137 status = hif_initialize_ipci_ops(hif_sc); 138 break; 139 case QDF_BUS_TYPE_SNOC: 140 status = hif_initialize_snoc_ops(&hif_sc->bus_ops); 141 break; 142 case QDF_BUS_TYPE_AHB: 143 status = hif_initialize_ahb_ops(&hif_sc->bus_ops); 144 break; 145 case QDF_BUS_TYPE_SDIO: 146 status = hif_initialize_sdio_ops(hif_sc); 147 break; 148 case QDF_BUS_TYPE_USB: 149 status = hif_initialize_usb_ops(&hif_sc->bus_ops); 150 break; 151 default: 152 status = QDF_STATUS_E_NOSUPPORT; 153 break; 154 } 155 156 if (status != QDF_STATUS_SUCCESS) { 157 hif_err("bus_type: %d not supported", bus_type); 158 return status; 159 } 160 161 status = hif_verify_basic_ops(hif_sc); 162 if (status != QDF_STATUS_SUCCESS) 163 return status; 164 165 return hif_sc->bus_ops.hif_bus_open(hif_sc, bus_type); 166 } 167 168 /** 169 * hif_bus_close() - close the bus 170 * @hif_sc: hif_context 171 */ 172 void hif_bus_close(struct hif_softc *hif_sc) 173 { 174 hif_sc->bus_ops.hif_bus_close(hif_sc); 175 } 176 177 /** 178 * hif_bus_prevent_linkdown() - prevent linkdown 179 * @hif_ctx: hif context 180 * @flag: true = keep bus alive false = let bus go to sleep 181 * 182 * Keeps the bus awake durring suspend. 183 */ 184 void hif_bus_prevent_linkdown(struct hif_softc *hif_sc, bool flag) 185 { 186 hif_sc->bus_ops.hif_bus_prevent_linkdown(hif_sc, flag); 187 } 188 189 190 void hif_reset_soc(struct hif_opaque_softc *hif_ctx) 191 { 192 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 193 194 hif_sc->bus_ops.hif_reset_soc(hif_sc); 195 } 196 197 int hif_bus_early_suspend(struct hif_opaque_softc *hif_ctx) 198 { 199 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 200 201 return hif_sc->bus_ops.hif_bus_early_suspend(hif_sc); 202 } 203 204 int hif_bus_late_resume(struct hif_opaque_softc *hif_ctx) 205 { 206 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 207 208 return hif_sc->bus_ops.hif_bus_late_resume(hif_sc); 209 } 210 211 int hif_bus_suspend(struct hif_opaque_softc *hif_ctx) 212 { 213 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 214 215 return hif_sc->bus_ops.hif_bus_suspend(hif_sc); 216 } 217 218 int hif_bus_resume(struct hif_opaque_softc *hif_ctx) 219 { 220 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 221 222 return hif_sc->bus_ops.hif_bus_resume(hif_sc); 223 } 224 225 int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx) 226 { 227 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 228 229 return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc); 230 } 231 232 int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx) 233 { 234 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 235 236 return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc); 237 } 238 239 int hif_target_sleep_state_adjust(struct hif_softc *hif_sc, 240 bool sleep_ok, bool wait_for_it) 241 { 242 return hif_sc->bus_ops.hif_target_sleep_state_adjust(hif_sc, 243 sleep_ok, wait_for_it); 244 } 245 qdf_export_symbol(hif_target_sleep_state_adjust); 246 247 void hif_disable_isr(struct hif_opaque_softc *hif_hdl) 248 { 249 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 250 251 hif_sc->bus_ops.hif_disable_isr(hif_sc); 252 } 253 254 void hif_nointrs(struct hif_softc *hif_sc) 255 { 256 hif_sc->bus_ops.hif_nointrs(hif_sc); 257 } 258 259 QDF_STATUS hif_enable_bus(struct hif_softc *hif_sc, struct device *dev, 260 void *bdev, const struct hif_bus_id *bid, 261 enum hif_enable_type type) 262 { 263 return hif_sc->bus_ops.hif_enable_bus(hif_sc, dev, bdev, bid, type); 264 } 265 266 void hif_disable_bus(struct hif_softc *hif_sc) 267 { 268 hif_sc->bus_ops.hif_disable_bus(hif_sc); 269 } 270 271 #ifdef FEATURE_RUNTIME_PM 272 struct hif_runtime_pm_ctx *hif_bus_get_rpm_ctx(struct hif_softc *hif_sc) 273 { 274 return hif_sc->bus_ops.hif_bus_get_rpm_ctx(hif_sc); 275 } 276 277 struct device *hif_bus_get_dev(struct hif_softc *hif_sc) 278 { 279 return hif_sc->bus_ops.hif_bus_get_dev(hif_sc); 280 } 281 #endif 282 283 int hif_bus_configure(struct hif_softc *hif_sc) 284 { 285 return hif_sc->bus_ops.hif_bus_configure(hif_sc); 286 } 287 288 QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx, 289 int opcode, void *config, uint32_t config_len) 290 { 291 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 292 293 return hif_sc->bus_ops.hif_get_config_item(hif_sc, opcode, config, 294 config_len); 295 } 296 297 void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx) 298 { 299 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 300 301 hif_sc->bus_ops.hif_set_mailbox_swap(hif_sc); 302 } 303 304 void hif_claim_device(struct hif_opaque_softc *hif_ctx) 305 { 306 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 307 308 hif_sc->bus_ops.hif_claim_device(hif_sc); 309 } 310 311 void hif_shutdown_device(struct hif_opaque_softc *hif_ctx) 312 { 313 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 314 315 hif_sc->bus_ops.hif_shutdown_device(hif_sc); 316 } 317 318 void hif_stop(struct hif_opaque_softc *hif_ctx) 319 { 320 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); 321 322 hif_sc->bus_ops.hif_stop(hif_sc); 323 } 324 325 void hif_cancel_deferred_target_sleep(struct hif_softc *hif_sc) 326 { 327 return hif_sc->bus_ops.hif_cancel_deferred_target_sleep(hif_sc); 328 } 329 330 void hif_irq_enable(struct hif_softc *hif_sc, int irq_id) 331 { 332 hif_sc->bus_ops.hif_irq_enable(hif_sc, irq_id); 333 } 334 qdf_export_symbol(hif_irq_enable); 335 336 void hif_irq_disable(struct hif_softc *hif_sc, int irq_id) 337 { 338 hif_sc->bus_ops.hif_irq_disable(hif_sc, irq_id); 339 } 340 341 int hif_grp_irq_configure(struct hif_softc *hif_sc, 342 struct hif_exec_context *hif_exec) 343 { 344 return hif_sc->bus_ops.hif_grp_irq_configure(hif_sc, hif_exec); 345 } 346 347 int hif_dump_registers(struct hif_opaque_softc *hif_hdl) 348 { 349 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 350 351 return hif_sc->bus_ops.hif_dump_registers(hif_sc); 352 } 353 354 void hif_dump_target_memory(struct hif_opaque_softc *hif_hdl, 355 void *ramdump_base, 356 uint32_t address, uint32_t size) 357 { 358 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 359 360 hif_sc->bus_ops.hif_dump_target_memory(hif_sc, ramdump_base, 361 address, size); 362 } 363 364 void hif_ipa_get_ce_resource(struct hif_opaque_softc *hif_hdl, 365 qdf_shared_mem_t **ce_sr, 366 uint32_t *ce_sr_ring_size, 367 qdf_dma_addr_t *ce_reg_paddr) 368 { 369 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 370 371 hif_sc->bus_ops.hif_ipa_get_ce_resource(hif_sc, ce_sr, 372 ce_sr_ring_size, ce_reg_paddr); 373 } 374 375 void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl) 376 { 377 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 378 379 hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc); 380 } 381 382 void hif_display_bus_stats(struct hif_opaque_softc *scn) 383 { 384 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); 385 386 hif_sc->bus_ops.hif_display_stats(hif_sc); 387 } 388 389 void hif_clear_bus_stats(struct hif_opaque_softc *scn) 390 { 391 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); 392 393 hif_sc->bus_ops.hif_clear_stats(hif_sc); 394 } 395 396 /** 397 * hif_enable_power_management() - enable power management after driver load 398 * @hif_hdl: opaque pointer to the hif context 399 * is_packet_log_enabled: true if packet log is enabled 400 * 401 * Driver load and firmware download are done in a high performance mode. 402 * Enable power management after the driver is loaded. 403 * packet log can require fewer power management features to be enabled. 404 */ 405 void hif_enable_power_management(struct hif_opaque_softc *hif_hdl, 406 bool is_packet_log_enabled) 407 { 408 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 409 410 hif_sc->bus_ops.hif_enable_power_management(hif_sc, 411 is_packet_log_enabled); 412 } 413 414 /** 415 * hif_disable_power_management() - reset the bus power management 416 * @hif_hdl: opaque pointer to the hif context 417 * 418 * return the power management of the bus to its default state. 419 * This isn't necessarily a complete reversal of its counterpart. 420 * This should be called when unloading the driver. 421 */ 422 void hif_disable_power_management(struct hif_opaque_softc *hif_hdl) 423 { 424 struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); 425 426 hif_sc->bus_ops.hif_disable_power_management(hif_sc); 427 } 428 429 /** 430 * hif_set_bundle_mode() - enable bundling and set default rx bundle cnt 431 * @scn: pointer to hif_opaque_softc structure 432 * @enabled: flag to enable/disable bundling 433 * @rx_bundle_cnt: bundle count to be used for RX 434 * 435 * Return: none 436 */ 437 void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled, 438 int rx_bundle_cnt) 439 { 440 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); 441 442 hif_sc->bus_ops.hif_set_bundle_mode(hif_sc, enabled, rx_bundle_cnt); 443 } 444 445 /** 446 * hif_bus_reset_resume() - resume the bus after reset 447 * @scn: struct hif_opaque_softc 448 * 449 * This function is called to tell the driver that USB device has been resumed 450 * and it has also been reset. The driver should redo any necessary 451 * initialization. This function resets WLAN SOC. 452 * 453 * Return: int 0 for success, non zero for failure 454 */ 455 int hif_bus_reset_resume(struct hif_opaque_softc *scn) 456 { 457 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); 458 459 return hif_sc->bus_ops.hif_bus_reset_resume(hif_sc); 460 } 461 462 int hif_apps_irqs_disable(struct hif_opaque_softc *hif_ctx) 463 { 464 struct hif_softc *scn; 465 int i; 466 467 QDF_BUG(hif_ctx); 468 scn = HIF_GET_SOFTC(hif_ctx); 469 if (!scn) 470 return -EINVAL; 471 472 /* if the wake_irq is shared, don't disable it twice */ 473 disable_irq(scn->wake_irq); 474 for (i = 0; i < scn->ce_count; ++i) { 475 int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i); 476 477 if (irq != scn->wake_irq) 478 disable_irq(irq); 479 } 480 481 return 0; 482 } 483 484 int hif_apps_irqs_enable(struct hif_opaque_softc *hif_ctx) 485 { 486 struct hif_softc *scn; 487 int i; 488 489 QDF_BUG(hif_ctx); 490 scn = HIF_GET_SOFTC(hif_ctx); 491 if (!scn) 492 return -EINVAL; 493 494 /* if the wake_irq is shared, don't enable it twice */ 495 enable_irq(scn->wake_irq); 496 for (i = 0; i < scn->ce_count; ++i) { 497 int irq = scn->bus_ops.hif_map_ce_to_irq(scn, i); 498 499 if (irq != scn->wake_irq) 500 enable_irq(irq); 501 } 502 503 return 0; 504 } 505 506 int hif_apps_wake_irq_disable(struct hif_opaque_softc *hif_ctx) 507 { 508 struct hif_softc *scn; 509 510 QDF_BUG(hif_ctx); 511 scn = HIF_GET_SOFTC(hif_ctx); 512 if (!scn) 513 return -EINVAL; 514 515 disable_irq(scn->wake_irq); 516 517 return 0; 518 } 519 520 int hif_apps_wake_irq_enable(struct hif_opaque_softc *hif_ctx) 521 { 522 struct hif_softc *scn; 523 524 QDF_BUG(hif_ctx); 525 scn = HIF_GET_SOFTC(hif_ctx); 526 if (!scn) 527 return -EINVAL; 528 529 enable_irq(scn->wake_irq); 530 531 return 0; 532 } 533 534 int hif_apps_disable_irq_wake(struct hif_opaque_softc *hif_ctx) 535 { 536 struct hif_softc *scn; 537 538 QDF_BUG(hif_ctx); 539 scn = HIF_GET_SOFTC(hif_ctx); 540 if (!scn) 541 return -EINVAL; 542 543 return disable_irq_wake(scn->wake_irq); 544 } 545 546 int hif_apps_enable_irq_wake(struct hif_opaque_softc *hif_ctx) 547 { 548 struct hif_softc *scn; 549 550 QDF_BUG(hif_ctx); 551 scn = HIF_GET_SOFTC(hif_ctx); 552 if (!scn) 553 return -EINVAL; 554 555 return enable_irq_wake(scn->wake_irq); 556 } 557 558 #ifdef WLAN_FEATURE_BMI 559 bool hif_needs_bmi(struct hif_opaque_softc *scn) 560 { 561 struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); 562 563 return hif_sc->bus_ops.hif_needs_bmi(hif_sc); 564 } 565 qdf_export_symbol(hif_needs_bmi); 566 #endif /* WLAN_FEATURE_BMI */ 567 568 void hif_config_irq_affinity(struct hif_softc *hif_sc) 569 { 570 hif_sc->bus_ops.hif_config_irq_affinity(hif_sc); 571 } 572 573 int hif_config_irq_by_ceid(struct hif_softc *hif_sc, int ce_id) 574 { 575 return hif_sc->bus_ops.hif_config_irq_by_ceid(hif_sc, ce_id); 576 } 577 578 #ifdef HIF_BUS_LOG_INFO 579 bool hif_log_bus_info(struct hif_softc *hif_sc, uint8_t *data, 580 unsigned int *offset) 581 { 582 if (hif_sc->bus_ops.hif_log_bus_info) 583 return hif_sc->bus_ops.hif_log_bus_info(hif_sc, data, offset); 584 585 return false; 586 } 587 #endif 588