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