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