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