Exemplo n.º 1
0
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;
}