1 /* 2 * Copyright (c) 2015-2021 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 /** 20 * DOC: if_snoc.c 21 * 22 * c file for snoc specif implementations. 23 */ 24 25 #include "hif.h" 26 #include "hif_main.h" 27 #include "hif_debug.h" 28 #include "hif_io32.h" 29 #include "ce_main.h" 30 #include "ce_tasklet.h" 31 #include "ce_api.h" 32 #include "ce_internal.h" 33 #include "snoc_api.h" 34 #include "pld_common.h" 35 #include "qdf_util.h" 36 #ifdef IPA_OFFLOAD 37 #include <uapi/linux/msm_ipa.h> 38 #endif 39 #include "target_type.h" 40 41 /** 42 * hif_disable_isr(): disable isr 43 * 44 * This function disables isr and kills tasklets 45 * 46 * @hif_ctx: struct hif_softc 47 * 48 * Return: void 49 */ 50 void hif_snoc_disable_isr(struct hif_softc *scn) 51 { 52 hif_exec_kill(&scn->osc); 53 hif_nointrs(scn); 54 ce_tasklet_kill(scn); 55 qdf_atomic_set(&scn->active_tasklet_cnt, 0); 56 qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0); 57 } 58 59 /** 60 * hif_dump_registers(): dump bus debug registers 61 * @hif_ctx: struct hif_opaque_softc 62 * 63 * This function dumps hif bus debug registers 64 * 65 * Return: 0 for success or error code 66 */ 67 int hif_snoc_dump_registers(struct hif_softc *hif_ctx) 68 { 69 int status; 70 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); 71 72 status = hif_dump_ce_registers(scn); 73 if (status) 74 hif_err("Dump CE Registers Failed"); 75 76 return 0; 77 } 78 79 void hif_snoc_display_stats(struct hif_softc *hif_ctx) 80 { 81 if (!hif_ctx) { 82 hif_err("hif_ctx null"); 83 return; 84 } 85 hif_display_ce_stats(hif_ctx); 86 } 87 88 void hif_snoc_clear_stats(struct hif_softc *hif_ctx) 89 { 90 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); 91 92 if (!hif_state) { 93 hif_err("hif_ctx null"); 94 return; 95 } 96 hif_clear_ce_stats(hif_state); 97 } 98 99 /** 100 * hif_snoc_close(): hif_bus_close 101 * 102 * Return: n/a 103 */ 104 void hif_snoc_close(struct hif_softc *scn) 105 { 106 hif_ce_close(scn); 107 } 108 109 /** 110 * hif_bus_open(): hif_bus_open 111 * @hif_ctx: hif context 112 * @bus_type: bus type 113 * 114 * Return: n/a 115 */ 116 QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) 117 { 118 return hif_ce_open(hif_ctx); 119 } 120 121 /** 122 * hif_snoc_get_soc_info() - populates scn with hw info 123 * 124 * fills in the virtual and physical base address as well as 125 * soc version info. 126 * 127 * return 0 or QDF_STATUS_E_FAILURE 128 */ 129 static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn) 130 { 131 int ret; 132 struct pld_soc_info soc_info; 133 134 qdf_mem_zero(&soc_info, sizeof(soc_info)); 135 136 ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info); 137 if (ret < 0) { 138 hif_err("pld_get_soc_info error = %d", ret); 139 return QDF_STATUS_E_FAILURE; 140 } 141 142 scn->mem = soc_info.v_addr; 143 scn->mem_pa = soc_info.p_addr; 144 145 scn->target_info.soc_version = soc_info.soc_id; 146 scn->target_info.target_version = soc_info.soc_id; 147 scn->target_info.target_revision = 0; 148 return QDF_STATUS_SUCCESS; 149 } 150 151 /** 152 * hif_bus_configure() - configure the snoc bus 153 * @scn: pointer to the hif context. 154 * 155 * return: 0 for success. nonzero for failure. 156 */ 157 int hif_snoc_bus_configure(struct hif_softc *scn) 158 { 159 int ret; 160 uint8_t wake_ce_id; 161 162 ret = hif_snoc_get_soc_info(scn); 163 if (ret) 164 return ret; 165 166 hif_ce_prepare_config(scn); 167 168 ret = hif_wlan_enable(scn); 169 if (ret) { 170 hif_err("hif_wlan_enable error = %d", ret); 171 return ret; 172 } 173 174 ret = hif_config_ce(scn); 175 if (ret) 176 goto wlan_disable; 177 178 ret = hif_get_wake_ce_id(scn, &wake_ce_id); 179 if (ret) 180 goto unconfig_ce; 181 182 scn->wake_irq = pld_get_irq(scn->qdf_dev->dev, wake_ce_id); 183 scn->wake_irq_type = HIF_PM_CE_WAKE; 184 185 hif_info("expecting wake from ce %d, irq %d", 186 wake_ce_id, scn->wake_irq); 187 188 return 0; 189 190 unconfig_ce: 191 hif_unconfig_ce(scn); 192 193 wlan_disable: 194 hif_wlan_disable(scn); 195 196 return ret; 197 } 198 199 /** 200 * hif_snoc_get_target_type(): Get the target type 201 * 202 * This function is used to query the target type. 203 * 204 * @ol_sc: hif_softc struct pointer 205 * @dev: device pointer 206 * @bdev: bus dev pointer 207 * @bid: bus id pointer 208 * @hif_type: HIF type such as HIF_TYPE_QCA6180 209 * @target_type: target type such as TARGET_TYPE_QCA6180 210 * 211 * Return: 0 for success 212 */ 213 static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc, 214 struct device *dev, void *bdev, const struct hif_bus_id *bid, 215 uint32_t *hif_type, uint32_t *target_type) 216 { 217 /* TODO: need to use HW version. Hard code for now */ 218 #ifdef QCA_WIFI_3_0_ADRASTEA 219 *hif_type = HIF_TYPE_ADRASTEA; 220 *target_type = TARGET_TYPE_ADRASTEA; 221 #else 222 *hif_type = 0; 223 *target_type = 0; 224 #endif 225 return 0; 226 } 227 228 #ifdef IPA_OFFLOAD 229 static int hif_set_dma_coherent_mask(qdf_device_t osdev) 230 { 231 uint8_t addr_bits; 232 233 if (false == hif_get_ipa_present()) 234 return qdf_set_dma_coherent_mask(osdev->dev, 235 DMA_COHERENT_MASK_DEFAULT); 236 237 if (hif_get_ipa_hw_type() < IPA_HW_v3_0) 238 addr_bits = DMA_COHERENT_MASK_BELOW_IPA_VER_3; 239 else 240 addr_bits = DMA_COHERENT_MASK_DEFAULT; 241 242 return qdf_set_dma_coherent_mask(osdev->dev, addr_bits); 243 } 244 #else 245 static int hif_set_dma_coherent_mask(qdf_device_t osdev) 246 { 247 return qdf_set_dma_coherent_mask(osdev->dev, 248 DMA_COHERENT_MASK_DEFAULT); 249 } 250 #endif 251 252 /** 253 * hif_enable_bus(): hif_enable_bus 254 * @dev: dev 255 * @bdev: bus dev 256 * @bid: bus id 257 * @type: bus type 258 * 259 * Return: QDF_STATUS 260 */ 261 QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc, 262 struct device *dev, void *bdev, 263 const struct hif_bus_id *bid, 264 enum hif_enable_type type) 265 { 266 int ret; 267 int hif_type; 268 int target_type; 269 270 if (!ol_sc) { 271 hif_err("hif_ctx is NULL"); 272 return QDF_STATUS_E_NOMEM; 273 } 274 275 ret = hif_set_dma_coherent_mask(ol_sc->qdf_dev); 276 if (ret) { 277 hif_err("Failed to set dma mask error = %d", ret); 278 return qdf_status_from_os_return(ret); 279 } 280 281 ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true); 282 if (ret == -EEXIST) 283 hif_warn("device_init_wakeup already done"); 284 else if (ret) { 285 hif_err("device_init_wakeup: err= %d", ret); 286 return qdf_status_from_os_return(ret); 287 } 288 289 ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid, 290 &hif_type, &target_type); 291 if (ret < 0) { 292 hif_err("Invalid device id/revision_id"); 293 return QDF_STATUS_E_FAILURE; 294 } 295 296 ol_sc->target_info.target_type = target_type; 297 298 hif_register_tbl_attach(ol_sc, hif_type); 299 hif_target_register_tbl_attach(ol_sc, target_type); 300 301 /* the bus should remain on durring suspend for snoc */ 302 hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc)); 303 304 hif_debug("X - hif_type = 0x%x, target_type = 0x%x", 305 hif_type, target_type); 306 307 return QDF_STATUS_SUCCESS; 308 } 309 310 /** 311 * hif_disable_bus(): hif_disable_bus 312 * 313 * This function disables the bus 314 * 315 * @bdev: bus dev 316 * 317 * Return: none 318 */ 319 void hif_snoc_disable_bus(struct hif_softc *scn) 320 { 321 int ret; 322 323 hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn)); 324 325 ret = qdf_device_init_wakeup(scn->qdf_dev, false); 326 if (ret) 327 hif_err("device_init_wakeup: err %d", ret); 328 } 329 330 /** 331 * hif_nointrs(): disable IRQ 332 * 333 * This function stops interrupt(s) 334 * 335 * @scn: struct hif_softc 336 * 337 * Return: none 338 */ 339 void hif_snoc_nointrs(struct hif_softc *scn) 340 { 341 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 342 343 scn->free_irq_done = true; 344 ce_unregister_irq(hif_state, CE_ALL_BITMAP); 345 } 346 347 /** 348 * ce_irq_enable() - enable copy engine IRQ 349 * @scn: struct hif_softc 350 * @ce_id: ce_id 351 * 352 * Return: N/A 353 */ 354 void hif_snoc_irq_enable(struct hif_softc *scn, 355 int ce_id) 356 { 357 ce_enable_irq_in_individual_register(scn, ce_id); 358 } 359 360 /** 361 * ce_irq_disable() - disable copy engine IRQ 362 * @scn: struct hif_softc 363 * @ce_id: ce_id 364 * 365 * Return: N/A 366 */ 367 void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id) 368 { 369 ce_disable_irq_in_individual_register(scn, ce_id); 370 } 371 372 /* 373 * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs 374 * @hif_softc: hif context 375 * 376 * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up 377 * the host driver. Ensure that the copy complete interrupt from this copy 378 * engine can wake up the apps processor. 379 * 380 * Return: 0 for success 381 */ 382 static 383 QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable) 384 { 385 int ret; 386 387 if (enable) 388 ret = enable_irq_wake(scn->wake_irq); 389 else 390 ret = disable_irq_wake(scn->wake_irq); 391 392 if (ret) { 393 hif_err("Fail to setup wake IRQ!"); 394 return QDF_STATUS_E_RESOURCES; 395 } 396 397 return QDF_STATUS_SUCCESS; 398 } 399 400 /** 401 * hif_snoc_bus_suspend() - prepare to suspend the bus 402 * @scn: hif context 403 * 404 * Setup wakeup interrupt configuration. 405 * Disable CE interrupts (wakeup interrupt will still wake apps) 406 * Drain tasklets. - make sure that we don't suspend while processing 407 * the wakeup message. 408 * 409 * Return: 0 on success. 410 */ 411 int hif_snoc_bus_suspend(struct hif_softc *scn) 412 { 413 if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS) 414 return -EFAULT; 415 return 0; 416 } 417 418 /** 419 * hif_snoc_bus_resume() - snoc bus resume function 420 * @scn: hif context 421 * 422 * Clear wakeup interrupt configuration. 423 * Reenable ce interrupts 424 * 425 * Return: 0 on success 426 */ 427 int hif_snoc_bus_resume(struct hif_softc *scn) 428 { 429 if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS) 430 QDF_BUG(0); 431 432 return 0; 433 } 434 435 /** 436 * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions 437 * @scn: hif context 438 * 439 * Ensure that if we received the wakeup message before the irq 440 * was disabled that the message is pocessed before suspending. 441 * 442 * Return: -EBUSY if we fail to flush the tasklets. 443 */ 444 int hif_snoc_bus_suspend_noirq(struct hif_softc *scn) 445 { 446 if (hif_drain_tasklets(scn) != 0) 447 return -EBUSY; 448 return 0; 449 } 450 451 int hif_snoc_map_ce_to_irq(struct hif_softc *scn, int ce_id) 452 { 453 return pld_get_irq(scn->qdf_dev->dev, ce_id); 454 } 455 456 /** 457 * hif_is_target_register_access_allowed(): Check target register access allow 458 * @scn: HIF Context 459 * 460 * This function help to check whether target register access is allowed or not 461 * 462 * Return: true if target access is allowed else false 463 */ 464 bool hif_is_target_register_access_allowed(struct hif_softc *scn) 465 { 466 if (hif_is_recovery_in_progress(scn)) 467 return hif_is_target_ready(scn); 468 else 469 return true; 470 } 471 472 /** 473 * hif_snoc_needs_bmi() - return true if the soc needs bmi through the driver 474 * @scn: hif context 475 * 476 * Return: true if soc needs driver bmi otherwise false 477 */ 478 bool hif_snoc_needs_bmi(struct hif_softc *scn) 479 { 480 return false; 481 } 482