static void a4xx_destroy(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu); DBG("%s", gpu->name); adreno_gpu_cleanup(adreno_gpu); #ifdef CONFIG_MSM_OCMEM if (a4xx_gpu->ocmem_base) ocmem_free(OCMEM_GRAPHICS, a4xx_gpu->ocmem_hdl); #endif kfree(a4xx_gpu); }
/* * Perform the encessary operations to clean-up OCMEM after being notified that * there is no longer a client; if sensors was evicted; or if some error * has occurred. * * @param[i] do_free Whether the memory should be freed (true) or if shrink * should be called instead (false). */ static void sns_ocmem_evicted(bool do_free) { int err = 0; sns_ocmem_unmap(); if (do_free) { ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf); sns_ctl.buf = NULL; } else { err = ocmem_shrink(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, 0); BUG_ON(err != 0); } err = sns_ocmem_unmap_send(); if (err != 0) pr_err("sns_ocmem_unmap_send failed %i\n", err); }
/* * Waits for allocation to succeed. This may take considerable time if the device * is presently in a high-power use case. * * @return 0 on success; < 0 upon error */ static int sns_ocmem_wait_for_alloc(void) { int err = 0; err = sns_ocmem_wait(SNS_OCMEM_ALLOC_GROW | DSPS_HAS_NO_CLIENT, 0); if (err == 0) { if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) { pr_debug("%s: Lost client while waiting for GROW\n", __func__); ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf); sns_ctl.buf = NULL; return -EPIPE; } } else { pr_err("sns_ocmem_wait failed %i\n", err); return -EFAULT; } return 0; }
/* * Kicks-off the mapping of memory from DDR to ocmem. Waits for the process * to complete, then indicates so to the ADSP. * * @return 0: Success; < 0: Other error */ static int sns_ocmem_map(void) { int err = 0; unsigned long flags; spin_lock_irqsave(&sns_ctl.sns_lock, flags); sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_MAP_FAIL & ~SNS_OCMEM_MAP_DONE); spin_unlock_irqrestore(&sns_ctl.sns_lock, flags); /* vote for ocmem bus bandwidth */ err = msm_bus_scale_client_update_request( sns_ctl.sns_ocmem_bus_client, 0); if (err) pr_err("%s: failed to vote for bus bandwidth\n", __func__); err = ocmem_map(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, &sns_ctl.map_list); if (err != 0) { pr_debug("ocmem_map failed %i\n", err); ocmem_set_power_state(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, OCMEM_OFF); ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf); sns_ctl.buf = NULL; } else { err = sns_ocmem_wait(SNS_OCMEM_ALLOC_SHRINK | DSPS_HAS_NO_CLIENT | SNS_OCMEM_MAP_DONE | SNS_OCMEM_MAP_FAIL, 0); if (err == 0) { if (sns_ocmem_is_status_set(SNS_OCMEM_MAP_DONE)) pr_debug("%s: OCMEM mapping DONE\n", __func__); else if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) { pr_debug("%s: Lost client while waiting for MAP\n", __func__); sns_ocmem_unmap(); ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf); sns_ctl.buf = NULL; err = -EPIPE; } else if (sns_ocmem_is_status_set( SNS_OCMEM_ALLOC_SHRINK)) { pr_debug("%s: SHRINK while wait for MAP\n", __func__); sns_ocmem_unmap(); err = ocmem_shrink(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, 0); BUG_ON(err != 0); err = -EFAULT; } else if (sns_ocmem_is_status_set( SNS_OCMEM_MAP_FAIL)) { pr_err("%s: OCMEM mapping fails\n", __func__); ocmem_set_power_state(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, OCMEM_OFF); ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf); sns_ctl.buf = NULL; } else pr_err("%s: status flag not set\n", __func__); } else { pr_err("sns_ocmem_wait failed %i\n", err); } } return err; }