/**
 * ipa_mhi_init() - Initialize IPA MHI driver
 * @params: initialization params
 *
 * This function is called by MHI client driver on boot to initialize IPA MHI
 * Driver. When this function returns device can move to READY state.
 * This function is doing the following:
 *	- Initialize MHI IPA internal data structures
 *	- Create IPA RM resources
 *	- Initialize debugfs
 *
 * Return codes: 0	  : success
 *		 negative : error
 */
int ipa_mhi_init(struct ipa_mhi_init_params *params)
{
	int res;
	struct ipa_rm_create_params mhi_prod_params;
	struct ipa_rm_create_params mhi_cons_params;

	IPA_MHI_FUNC_ENTRY();

	if (!params) {
		IPA_MHI_ERR("null args\n");
		return -EINVAL;
	}

	if (!params->notify) {
		IPA_MHI_ERR("null notify function\n");
		return -EINVAL;
	}

	if (ipa_mhi_ctx) {
		IPA_MHI_ERR("already initialized\n");
		return -EPERM;
	}

	IPA_MHI_DBG("msi: addr_lo = 0x%x addr_hi = 0x%x\n",
		params->msi.addr_low, params->msi.addr_hi);
	IPA_MHI_DBG("msi: data = 0x%x mask = 0x%x\n",
		params->msi.data, params->msi.mask);
	IPA_MHI_DBG("mmio_addr = 0x%x\n", params->mmio_addr);
	IPA_MHI_DBG("first_ch_idx = 0x%x\n", params->first_ch_idx);
	IPA_MHI_DBG("first_er_idx = 0x%x\n", params->first_er_idx);
	IPA_MHI_DBG("notify = %pF priv = %p\n", params->notify, params->priv);

	/* Initialize context */
	ipa_mhi_ctx = kzalloc(sizeof(*ipa_mhi_ctx), GFP_KERNEL);
	if (!ipa_mhi_ctx) {
		IPA_MHI_ERR("no memory\n");
		res = -EFAULT;
		goto fail_alloc_ctx;
	}

	ipa_mhi_ctx->state = IPA_MHI_STATE_INITIALIZED;
	ipa_mhi_ctx->msi = params->msi;
	ipa_mhi_ctx->mmio_addr = params->mmio_addr;
	ipa_mhi_ctx->first_ch_idx = params->first_ch_idx;
	ipa_mhi_ctx->first_er_idx = params->first_er_idx;
	ipa_mhi_ctx->cb_notify = params->notify;
	ipa_mhi_ctx->cb_priv = params->priv;
	ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
	ipa_mhi_ctx->qmi_req_id = 0;
	init_completion(&ipa_mhi_ctx->rm_prod_granted_comp);
	spin_lock_init(&ipa_mhi_ctx->state_lock);
	init_completion(&ipa_mhi_ctx->rm_cons_comp);

	ipa_mhi_ctx->wq = create_singlethread_workqueue("ipa_mhi_wq");
	if (!ipa_mhi_ctx->wq) {
		IPA_MHI_ERR("failed to create workqueue\n");
		res = -EFAULT;
		goto fail_create_wq;
	}

	/* Initialize debugfs */
	ipa_mhi_debugfs_init();

	/* Create PROD in IPA RM */
	memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
	mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
	mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
	mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
	res = ipa_rm_create_resource(&mhi_prod_params);
	if (res) {
		IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
		goto fail_create_rm_prod;
	}

	/* Create CONS in IPA RM */
	memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
	mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
	mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
	mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
	mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
	res = ipa_rm_create_resource(&mhi_cons_params);
	if (res) {
		IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
		goto fail_create_rm_cons;
	}

	/* Initialize uC interface */
	ipa_uc_mhi_init(ipa_mhi_uc_ready_cb, ipa_mhi_uc_wakeup_request_cb);
	if (ipa_uc_state_check() == 0)
		ipa_mhi_set_state(IPA_MHI_STATE_READY);

	IPA_MHI_FUNC_EXIT();

	return 0;

fail_create_rm_cons:
	ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
fail_create_rm_prod:
	destroy_workqueue(ipa_mhi_ctx->wq);
fail_create_wq:
	kfree(ipa_mhi_ctx);
	ipa_mhi_ctx = NULL;
fail_alloc_ctx:
	return res;
}
示例#2
0
	} else {
		IPADBG("unsupported uC evt opcode=%u\n",
				ipa_ctx->uc_ctx.uc_sram_mmio->eventOp);
	}
	ipa_dec_client_disable_clks();

}

static int ipa_uc_panic_notifier(struct notifier_block *this,
		unsigned long event, void *ptr)
{
	int result = 0;

	IPADBG("this=%p evt=%lu ptr=%p\n", this, event, ptr);

	result = ipa_uc_state_check();
	if (result)
		goto fail;

	if (ipa_inc_client_enable_clks_no_block())
		goto fail;

	ipa_ctx->uc_ctx.uc_sram_mmio->cmdOp =
		IPA_CPU_2_HW_CMD_ERR_FATAL;
	ipa_ctx->uc_ctx.pending_cmd = ipa_ctx->uc_ctx.uc_sram_mmio->cmdOp;
	/* ensure write to shared memory is done before triggering uc */
	wmb();
	ipa_write_reg(ipa_ctx->mmio, IPA_IRQ_EE_UC_n_OFFS(0), 0x1);
	/* give uc enough time to save state */
	udelay(IPA_PKT_FLUSH_TO_US);
/**
 * ipa_mhi_start() - Start IPA MHI engine
 * @params: pcie addresses for MHI
 *
 * This function is called by MHI client driver on MHI engine start for
 * handling MHI accelerated channels. This function is called after
 * ipa_mhi_init() was called and can be called after MHI reset to restart MHI
 * engine. When this function returns device can move to M0 state.
 * This function is doing the following:
 *	- Send command to uC for initialization of MHI engine
 *	- Add dependencies to IPA RM
 *	- Request MHI_PROD in IPA RM
 *
 * Return codes: 0	  : success
 *		 negative : error
 */
int ipa_mhi_start(struct ipa_mhi_start_params *params)
{
	int res;

	IPA_MHI_FUNC_ENTRY();

	if (!params) {
		IPA_MHI_ERR("null args\n");
		return -EINVAL;
	}

	if (unlikely(!ipa_mhi_ctx)) {
		IPA_MHI_ERR("IPA MHI was not initialized\n");
		return -EINVAL;
	}

	if (ipa_uc_state_check()) {
		IPA_MHI_ERR("IPA uc is not loaded\n");
		return -EAGAIN;
	}

	res = ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
	if (res) {
		IPA_MHI_ERR("ipa_mhi_set_state %d\n", res);
		return res;
	}

	ipa_mhi_ctx->host_ctrl_addr = params->host_ctrl_addr;
	ipa_mhi_ctx->host_data_addr = params->host_data_addr;

	/* Add MHI <-> Q6 dependencies to IPA RM */
	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
		IPA_RM_RESOURCE_Q6_CONS);
	if (res && res != -EINPROGRESS) {
		IPA_MHI_ERR("failed to add dependency %d\n", res);
		goto fail_add_mhi_q6_dep;
	}

	res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
		IPA_RM_RESOURCE_MHI_CONS);
	if (res && res != -EINPROGRESS) {
		IPA_MHI_ERR("failed to add dependency %d\n", res);
		goto fail_add_q6_mhi_dep;
	}

	res = ipa_mhi_request_prod();
	if (res) {
		IPA_MHI_ERR("failed request prod %d\n", res);
		goto fail_request_prod;
	}

	/* Initialize IPA MHI engine */
	res = ipa_uc_mhi_init_engine(&ipa_mhi_ctx->msi, ipa_mhi_ctx->mmio_addr,
		ipa_mhi_ctx->host_ctrl_addr, ipa_mhi_ctx->host_data_addr,
		ipa_mhi_ctx->first_ch_idx, ipa_mhi_ctx->first_er_idx);
	if (res) {
		IPA_MHI_ERR("failed to start MHI engine %d\n", res);
		goto fail_init_engine;
	}

	/* Update UL/DL sync if valid */
	res = ipa_uc_mhi_send_dl_ul_sync_info(cached_dl_ul_sync_info);
	if (res) {
		IPA_MHI_ERR("failed to update ul/dl sync %d\n", res);
		goto fail_init_engine;
	}

	IPA_MHI_FUNC_EXIT();
	return 0;

fail_init_engine:
	ipa_mhi_release_prod();
fail_request_prod:
	ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
		IPA_RM_RESOURCE_MHI_CONS);
fail_add_q6_mhi_dep:
	ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
		IPA_RM_RESOURCE_Q6_CONS);
fail_add_mhi_q6_dep:
	ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
	return res;
}