Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97ff0618 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa4: use ipa_pm"

parents 114c6797 3e35081c
Loading
Loading
Loading
Loading
+88 −19
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <linux/sched.h>
#include <linux/atomic.h>
#include <linux/ecm_ipa.h>
#include "../ipa_common_i.h"
#include "../ipa_v3/ipa_pm.h"

#define DRIVER_NAME "ecm_ipa"
#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
@@ -120,6 +122,7 @@ enum ecm_ipa_operation {
 * @usb_to_ipa_client: producer client
 * @ipa_rm_resource_name_prod: IPA resource manager producer resource
 * @ipa_rm_resource_name_cons: IPA resource manager consumer resource
 * @pm_hdl: handle for IPA PM
 */
struct ecm_ipa_dev {
	struct net_device *net;
@@ -137,6 +140,7 @@ struct ecm_ipa_dev {
	enum ipa_client_type usb_to_ipa_client;
	enum ipa_rm_resource_name ipa_rm_resource_name_prod;
	enum ipa_rm_resource_name ipa_rm_resource_name_cons;
	u32 pm_hdl;
};

static int ecm_ipa_open(struct net_device *net);
@@ -158,6 +162,8 @@ static void ecm_ipa_rm_notify
static struct net_device_stats *ecm_ipa_get_stats(struct net_device *net);
static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_destroy_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
static netdev_tx_t ecm_ipa_start_xmit
@@ -403,10 +409,14 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, void *priv)
	ECM_IPA_DEBUG("usb_to_ipa_client = %d\n",
		      ecm_ipa_ctx->usb_to_ipa_client);

	if (ipa_pm_is_used()) {
		retval = ecm_ipa_register_pm_client(ecm_ipa_ctx);
	} else {
		ecm_ipa_ctx->ipa_rm_resource_name_cons =
			ipa_get_rm_resource_from_ep(ipa_to_usb_hdl);
		if (ecm_ipa_ctx->ipa_rm_resource_name_cons < 0) {
		ECM_IPA_ERROR("Error getting CONS RM resource from handle %d\n",
			ECM_IPA_ERROR(
			"Error getting CONS RM resource from handle %d\n",
				      ecm_ipa_ctx->ipa_rm_resource_name_cons);
			return -EINVAL;
		}
@@ -416,7 +426,8 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, void *priv)
		ecm_ipa_ctx->ipa_rm_resource_name_prod =
			ipa_get_rm_resource_from_ep(usb_to_ipa_hdl);
		if (ecm_ipa_ctx->ipa_rm_resource_name_prod < 0) {
		ECM_IPA_ERROR("Error getting PROD RM resource from handle %d\n",
			ECM_IPA_ERROR(
			"Error getting PROD RM resource from handle %d\n",
				      ecm_ipa_ctx->ipa_rm_resource_name_prod);
			return -EINVAL;
		}
@@ -424,6 +435,8 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, void *priv)
			      ecm_ipa_ctx->ipa_rm_resource_name_prod);

		retval = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
	}

	if (retval) {
		ECM_IPA_ERROR("fail on RM create\n");
		goto fail_create_rm;
@@ -488,6 +501,9 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, void *priv)
fail:
	ecm_ipa_deregister_properties();
fail_create_rm:
	if (ipa_pm_is_used())
		ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
	else
		ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
	return retval;
}
@@ -746,6 +762,9 @@ int ecm_ipa_disconnect(void *priv)
	netif_stop_queue(ecm_ipa_ctx->net);
	ECM_IPA_DEBUG("queue stopped\n");

	if (ipa_pm_is_used())
		ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
	else
		ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);

	outstanding_dropped_pkts =
@@ -1117,15 +1136,65 @@ static void ecm_ipa_destroy_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
	ECM_IPA_LOG_EXIT();
}

static void ecm_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
{
	struct ecm_ipa_dev *ecm_ipa_ctx = p;

	ECM_IPA_LOG_ENTRY();
	if (event != IPA_PM_CLIENT_ACTIVATED) {
		ECM_IPA_ERROR("unexpected event %d\n", event);
		WARN_ON(1);
		return;
	}

	if (netif_queue_stopped(ecm_ipa_ctx->net)) {
		ECM_IPA_DEBUG("Resource Granted - starting queue\n");
		netif_start_queue(ecm_ipa_ctx->net);
	}
	ECM_IPA_LOG_EXIT();
}

static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
{
	int result;
	struct ipa_pm_register_params pm_reg;

	memset(&pm_reg, 0, sizeof(pm_reg));
	pm_reg.name = ecm_ipa_ctx->net->name;
	pm_reg.user_data = ecm_ipa_ctx;
	pm_reg.callback = ecm_ipa_pm_cb;
	pm_reg.group = IPA_PM_GROUP_APPS;
	result = ipa_pm_register(&pm_reg, &ecm_ipa_ctx->pm_hdl);
	if (result) {
		ECM_IPA_ERROR("failed to create IPA PM client %d\n", result);
		return result;
	}
	return 0;
}

static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
{
	ipa_pm_deactivate_sync(ecm_ipa_ctx->pm_hdl);
	ipa_pm_deregister(ecm_ipa_ctx->pm_hdl);
	ecm_ipa_ctx->pm_hdl = ~0;
}

static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
{
	if (ipa_pm_is_used())
		return ipa_pm_activate(ecm_ipa_ctx->pm_hdl);

	return ipa_rm_inactivity_timer_request_resource(
		IPA_RM_RESOURCE_STD_ECM_PROD);
}

static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
{
	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
	if (ipa_pm_is_used())
		ipa_pm_deferred_deactivate(ecm_ipa_ctx->pm_hdl);
	else
		ipa_rm_inactivity_timer_release_resource(
			IPA_RM_RESOURCE_STD_ECM_PROD);
}

/**
+303 −123
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/ipa_qmi_service_v01.h>
#include <linux/ipa_mhi.h>
#include "../ipa_common_i.h"
#include "../ipa_v3/ipa_pm.h"

#define IPA_MHI_DRV_NAME "ipa_mhi_client"
#define IPA_MHI_DBG(fmt, args...) \
@@ -136,6 +137,8 @@ struct ipa_mhi_client_ctx {
	u32 use_ipadma;
	bool assert_bit40;
	bool test_mode;
	u32 pm_hdl;
	u32 modem_pm_hdl;
};

static struct ipa_mhi_client_ctx *ipa_mhi_client_ctx;
@@ -834,6 +837,18 @@ int ipa_mhi_start(struct ipa_mhi_start_params *params)
	IPA_MHI_DBG("event_context_array_addr 0x%llx\n",
		ipa_mhi_client_ctx->event_context_array_addr);

	if (ipa_pm_is_used()) {
		res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
		if (res) {
			IPA_MHI_ERR("failed activate client %d\n", res);
			goto fail_pm_activate;
		}
		res = ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
		if (res) {
			IPA_MHI_ERR("failed activate modem client %d\n", res);
			goto fail_pm_activate_modem;
		}
	} else {
		/* Add MHI <-> Q6 dependencies to IPA RM */
		res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
			IPA_RM_RESOURCE_Q6_CONS);
@@ -854,6 +869,7 @@ int ipa_mhi_start(struct ipa_mhi_start_params *params)
			IPA_MHI_ERR("failed request prod %d\n", res);
			goto fail_request_prod;
		}
	}

	/* gsi params */
	init_params.gsi.first_ch_idx =
@@ -880,14 +896,23 @@ int ipa_mhi_start(struct ipa_mhi_start_params *params)
	return 0;

fail_init_engine:
	if (!ipa_pm_is_used())
		ipa_mhi_release_prod();
fail_request_prod:
	if (!ipa_pm_is_used())
		ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
			IPA_RM_RESOURCE_MHI_CONS);
fail_add_q6_mhi_dep:
	if (!ipa_pm_is_used())
		ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
			IPA_RM_RESOURCE_Q6_CONS);
fail_add_mhi_q6_dep:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
fail_pm_activate_modem:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
fail_pm_activate:
	ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
	return res;
}
@@ -2095,6 +2120,18 @@ int ipa_mhi_suspend(bool force)
	 */
	IPA_ACTIVE_CLIENTS_INC_SIMPLE();

	if (ipa_pm_is_used()) {
		res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
		if (res) {
			IPA_MHI_ERR("fail to deactivate client %d\n", res);
			goto fail_deactivate_pm;
		}
		res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
		if (res) {
			IPA_MHI_ERR("fail to deactivate client %d\n", res);
			goto fail_deactivate_modem_pm;
		}
	} else {
		IPA_MHI_DBG("release prod\n");
		res = ipa_mhi_release_prod();
		if (res) {
@@ -2105,10 +2142,10 @@ int ipa_mhi_suspend(bool force)
		IPA_MHI_DBG("wait for cons release\n");
		res = ipa_mhi_wait_for_cons_release();
		if (res) {
		IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n", res);
			IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed\n");
			goto fail_release_cons;
		}

	}
	usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);

	res = ipa_mhi_suspend_dl(force);
@@ -2132,8 +2169,15 @@ int ipa_mhi_suspend(bool force)

fail_suspend_dl_channel:
fail_release_cons:
	if (!ipa_pm_is_used())
	ipa_mhi_request_prod();
fail_release_prod:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
fail_deactivate_modem_pm:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
fail_deactivate_pm:
	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
fail_suspend_ul_channel:
	ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels);
@@ -2193,11 +2237,24 @@ int ipa_mhi_resume(void)
		ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
	}

	if (ipa_pm_is_used()) {
		res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
		if (res) {
			IPA_MHI_ERR("fail to activate client %d\n", res);
			goto fail_pm_activate;
		}
		ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
		if (res) {
			IPA_MHI_ERR("fail to activate client %d\n", res);
			goto fail_pm_activate_modem;
		}
	} else {
		res = ipa_mhi_request_prod();
		if (res) {
			IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
			goto fail_request_prod;
		}
	}

	/* resume all UL channels */
	res = ipa_mhi_resume_channels(false,
@@ -2234,8 +2291,15 @@ int ipa_mhi_resume(void)
fail_resume_dl_channels2:
	ipa_mhi_suspend_channels(ipa_mhi_client_ctx->ul_channels);
fail_resume_ul_channels:
	if (!ipa_pm_is_used())
		ipa_mhi_release_prod();
fail_request_prod:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
fail_pm_activate_modem:
	if (ipa_pm_is_used())
		ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
fail_pm_activate:
	ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
fail_resume_dl_channels:
	ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
@@ -2319,54 +2383,28 @@ static void ipa_mhi_debugfs_destroy(void)
	debugfs_remove_recursive(dent);
}

/**
 * ipa_mhi_destroy() - Destroy MHI IPA
 *
 * This function is called by MHI client driver on MHI reset to destroy all IPA
 * MHI resources.
 * When this function returns ipa_mhi can re-initialize.
 */
void ipa_mhi_destroy(void)
static void ipa_mhi_delete_rm_resources(void)
{
	int res;

	IPA_MHI_FUNC_ENTRY();
	if (!ipa_mhi_client_ctx) {
		IPA_MHI_DBG("IPA MHI was not initialized, already destroyed\n");
		return;
	}
	/* reset all UL and DL acc channels and its accociated event rings */
	if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
		res = ipa_mhi_destroy_all_channels();
		if (res) {
			IPA_MHI_ERR("ipa_mhi_destroy_all_channels failed %d\n",
				res);
			goto fail;
		}
	}
	IPA_MHI_DBG("All channels are disconnected\n");

	if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_SPS) {
		IPA_MHI_DBG("cleanup uC MHI\n");
		ipa_uc_mhi_cleanup();
	}


	if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED  &&
		ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {

		IPA_MHI_DBG("release prod\n");
		res = ipa_mhi_release_prod();
		if (res) {
			IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
			IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n",
				res);
			goto fail;
		}
		IPA_MHI_DBG("wait for cons release\n");
		res = ipa_mhi_wait_for_cons_release();
		if (res) {
			IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n",
			IPA_MHI_ERR("ipa_mhi_wait_for_cons_release%d\n",
				res);
			goto fail;
		}

		usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
			IPA_MHI_SUSPEND_SLEEP_MAX);

@@ -2375,8 +2413,8 @@ void ipa_mhi_destroy(void)
			IPA_RM_RESOURCE_MHI_CONS);
		if (res) {
			IPA_MHI_ERR(
				"Error deleting dependency %d->%d, res=%d\n"
				, IPA_RM_RESOURCE_Q6_PROD,
				"Error deleting dependency %d->%d, res=%d\n",
				IPA_RM_RESOURCE_Q6_PROD,
				IPA_RM_RESOURCE_MHI_CONS,
				res);
			goto fail;
@@ -2408,6 +2446,59 @@ void ipa_mhi_destroy(void)
		goto fail;
	}

	return;
fail:
	ipa_assert();
}

static void ipa_mhi_deregister_pm(void)
{
	ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
	ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
	ipa_mhi_client_ctx->pm_hdl = ~0;

	ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
	ipa_pm_deregister(ipa_mhi_client_ctx->modem_pm_hdl);
	ipa_mhi_client_ctx->modem_pm_hdl = ~0;
}

/**
 * ipa_mhi_destroy() - Destroy MHI IPA
 *
 * This function is called by MHI client driver on MHI reset to destroy all IPA
 * MHI resources.
 * When this function returns ipa_mhi can re-initialize.
 */
void ipa_mhi_destroy(void)
{
	int res;

	IPA_MHI_FUNC_ENTRY();
	if (!ipa_mhi_client_ctx) {
		IPA_MHI_DBG("IPA MHI was not initialized, already destroyed\n");
		return;
	}
	/* reset all UL and DL acc channels and its accociated event rings */
	if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
		res = ipa_mhi_destroy_all_channels();
		if (res) {
			IPA_MHI_ERR("ipa_mhi_destroy_all_channels failed %d\n",
				res);
			goto fail;
		}
	}
	IPA_MHI_DBG("All channels are disconnected\n");

	if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_SPS) {
		IPA_MHI_DBG("cleanup uC MHI\n");
		ipa_uc_mhi_cleanup();
	}

	if (ipa_pm_is_used())
		ipa_mhi_deregister_pm();
	else
		ipa_mhi_delete_rm_resources();

	ipa_mhi_debugfs_destroy();
	destroy_workqueue(ipa_mhi_client_ctx->wq);
	kfree(ipa_mhi_client_ctx);
@@ -2420,6 +2511,132 @@ void ipa_mhi_destroy(void)
	ipa_assert();
}

static void ipa_mhi_pm_cb(void *p, enum ipa_pm_cb_event event)
{
	unsigned long flags;

	IPA_MHI_FUNC_ENTRY();

	if (event != IPA_PM_REQUEST_WAKEUP) {
		IPA_MHI_ERR("Unexpected event %d\n", event);
		WARN_ON(1);
		return;
	}

	IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa_mhi_client_ctx->state));
	spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
	if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED) {
		ipa_mhi_notify_wakeup();
	} else if (ipa_mhi_client_ctx->state ==
		IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
		/* wakeup event will be trigger after suspend finishes */
		ipa_mhi_client_ctx->trigger_wakeup = true;
	}
	spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
	IPA_MHI_DBG("EXIT");
}

static int ipa_mhi_register_pm(void)
{
	int res;
	struct ipa_pm_register_params params;

	memset(&params, 0, sizeof(params));
	params.name = "MHI";
	params.callback = ipa_mhi_pm_cb;
	params.group = IPA_PM_GROUP_DEFAULT;
	res = ipa_pm_register(&params, &ipa_mhi_client_ctx->pm_hdl);
	if (res) {
		IPA_MHI_ERR("fail to register with PM %d\n", res);
		return res;
	}

	res = ipa_pm_associate_ipa_cons_to_client(ipa_mhi_client_ctx->pm_hdl,
		IPA_CLIENT_MHI_CONS);
	if (res) {
		IPA_MHI_ERR("fail to associate cons with PM %d\n", res);
		goto fail_pm_cons;
	}

	res = ipa_pm_set_perf_profile(ipa_mhi_client_ctx->pm_hdl, 1000);
	if (res) {
		IPA_MHI_ERR("fail to set perf profile to PM %d\n", res);
		goto fail_pm_cons;
	}

	/* create a modem client for clock scaling */
	memset(&params, 0, sizeof(params));
	params.name = "MODEM (MHI)";
	params.group = IPA_PM_GROUP_MODEM;
	params.skip_clk_vote = true;
	res = ipa_pm_register(&params, &ipa_mhi_client_ctx->modem_pm_hdl);
	if (res) {
		IPA_MHI_ERR("fail to register with PM %d\n", res);
		goto fail_pm_cons;
	}

	return 0;

fail_pm_cons:
	ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
	ipa_mhi_client_ctx->pm_hdl = ~0;
	return res;
}

static int ipa_mhi_create_rm_resources(void)
{
	int res;
	struct ipa_rm_create_params mhi_prod_params;
	struct ipa_rm_create_params mhi_cons_params;
	struct ipa_rm_perf_profile profile;

	/* 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;
	}

	memset(&profile, 0, sizeof(profile));
	profile.max_supported_bandwidth_mbps = 1000;
	res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
	if (res) {
		IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
		goto fail_perf_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;
	}

	memset(&profile, 0, sizeof(profile));
	profile.max_supported_bandwidth_mbps = 1000;
	res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
	if (res) {
		IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
		goto fail_perf_rm_cons;
	}
fail_perf_rm_cons:
	ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
fail_create_rm_cons:
fail_perf_rm_prod:
	ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
fail_create_rm_prod:
	return res;
}

/**
 * ipa_mhi_init() - Initialize IPA MHI driver
 * @params: initialization params
@@ -2437,9 +2654,6 @@ void ipa_mhi_destroy(void)
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;
	struct ipa_rm_perf_profile profile;

	IPA_MHI_FUNC_ENTRY();

@@ -2500,43 +2714,14 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params)
		goto fail_create_wq;
	}

	/* 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;
	}

	memset(&profile, 0, sizeof(profile));
	profile.max_supported_bandwidth_mbps = 1000;
	res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
	if (res) {
		IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
		goto fail_perf_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;
	}

	memset(&profile, 0, sizeof(profile));
	profile.max_supported_bandwidth_mbps = 1000;
	res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
	if (ipa_pm_is_used())
		res = ipa_mhi_register_pm();
	else
		res = ipa_mhi_create_rm_resources();
	if (res) {
		IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
		goto fail_perf_rm_cons;
		IPA_MHI_ERR("failed to create RM resources\n");
		res = -EFAULT;
		goto fail_rm;
	}

	/* Initialize uC interface */
@@ -2551,12 +2736,7 @@ int ipa_mhi_init(struct ipa_mhi_init_params *params)
	IPA_MHI_FUNC_EXIT();
	return 0;

fail_perf_rm_cons:
	ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
fail_create_rm_cons:
fail_perf_rm_prod:
	ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
fail_create_rm_prod:
fail_rm:
	destroy_workqueue(ipa_mhi_client_ctx->wq);
fail_create_wq:
	kfree(ipa_mhi_client_ctx);
+143 −51
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/ipa_uc_offload.h>
#include <linux/msm_ipa.h>
#include "../ipa_common_i.h"
#include "../ipa_v3/ipa_pm.h"

#define IPA_NTN_DMA_POOL_ALIGNMENT 8
#define OFFLOAD_DRV_NAME "ipa_uc_offload"
@@ -69,6 +70,7 @@ struct ipa_uc_offload_ctx {
	char netdev_name[IPA_RESOURCE_NAME_MAX];
	ipa_notify_cb notify;
	struct completion ntn_completion;
	u32 pm_hdl;
};

static struct ipa_uc_offload_ctx *ipa_uc_offload_ctx[IPA_UC_MAX_PROT_SIZE];
@@ -113,22 +115,53 @@ static int ipa_commit_partial_hdr(
	return 0;
}

static int ipa_uc_offload_ntn_reg_intf(
	struct ipa_uc_offload_intf_params *inp,
	struct ipa_uc_offload_out_params *outp,
static void ipa_uc_offload_ntn_pm_cb(void *p, enum ipa_pm_cb_event event)
{
	/* suspend/resume is not supported */
	IPA_UC_OFFLOAD_DBG("event = %d\n", event);
}

static int ipa_uc_offload_ntn_register_pm_client(
	struct ipa_uc_offload_ctx *ntn_ctx)
{
	struct ipa_ioc_add_hdr *hdr = NULL;
	struct ipa_tx_intf tx;
	struct ipa_rx_intf rx;
	struct ipa_ioc_tx_intf_prop tx_prop[2];
	struct ipa_ioc_rx_intf_prop rx_prop[2];
	int res;
	struct ipa_pm_register_params params;

	memset(&params, 0, sizeof(params));
	params.name = "ETH";
	params.callback = ipa_uc_offload_ntn_pm_cb;
	params.user_data = ntn_ctx;
	params.group = IPA_PM_GROUP_DEFAULT;
	res = ipa_pm_register(&params, &ntn_ctx->pm_hdl);
	if (res) {
		IPA_UC_OFFLOAD_ERR("fail to register with PM %d\n", res);
		return res;
	}

	res = ipa_pm_associate_ipa_cons_to_client(ntn_ctx->pm_hdl,
		IPA_CLIENT_ETHERNET_CONS);
	if (res) {
		IPA_UC_OFFLOAD_ERR("fail to associate cons with PM %d\n", res);
		ipa_pm_deregister(ntn_ctx->pm_hdl);
		ntn_ctx->pm_hdl = ~0;
		return res;
	}

	return 0;
}

static void ipa_uc_offload_ntn_deregister_pm_client(
	struct ipa_uc_offload_ctx *ntn_ctx)
{
	ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
	ipa_pm_deregister(ntn_ctx->pm_hdl);
}
static int ipa_uc_offload_ntn_create_rm_resources(
	struct ipa_uc_offload_ctx *ntn_ctx)
{
	int ret;
	struct ipa_rm_create_params param;
	u32 len;
	int ret = 0;

	IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
					 inp->netdev_name);
	memset(&param, 0, sizeof(param));
	param.name = IPA_RM_RESOURCE_ETHERNET_PROD;
	param.reg_params.user_data = ntn_ctx;
@@ -147,9 +180,37 @@ static int ipa_uc_offload_ntn_reg_intf(
	ret = ipa_rm_create_resource(&param);
	if (ret) {
		IPA_UC_OFFLOAD_ERR("fail to create ETHERNET_CONS resource\n");
		goto fail_create_rm_cons;
		ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
		return -EFAULT;
	}

	return 0;
}

static int ipa_uc_offload_ntn_reg_intf(
	struct ipa_uc_offload_intf_params *inp,
	struct ipa_uc_offload_out_params *outp,
	struct ipa_uc_offload_ctx *ntn_ctx)
{
	struct ipa_ioc_add_hdr *hdr = NULL;
	struct ipa_tx_intf tx;
	struct ipa_rx_intf rx;
	struct ipa_ioc_tx_intf_prop tx_prop[2];
	struct ipa_ioc_rx_intf_prop rx_prop[2];
	int ret = 0;
	u32 len;


	IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
					 inp->netdev_name);
	if (ipa_pm_is_used())
		ret = ipa_uc_offload_ntn_register_pm_client(ntn_ctx);
	else
		ret = ipa_uc_offload_ntn_create_rm_resources(ntn_ctx);
	if (ret) {
		IPA_UC_OFFLOAD_ERR("fail to create rm resource\n");
		return -EFAULT;
	}
	memcpy(ntn_ctx->netdev_name, inp->netdev_name, IPA_RESOURCE_NAME_MAX);
	ntn_ctx->hdr_len = inp->hdr_info[0].hdr_len;
	ntn_ctx->notify = inp->notify;
@@ -228,9 +289,12 @@ static int ipa_uc_offload_ntn_reg_intf(
fail:
	kfree(hdr);
fail_alloc:
	if (ipa_pm_is_used()) {
		ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
	} else {
		ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS);
fail_create_rm_cons:
		ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
	}
	return ret;
}

@@ -348,18 +412,26 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
		return -EINVAL;
	}

	if (ipa_pm_is_used()) {
		result = ipa_pm_activate_sync(ntn_ctx->pm_hdl);
		if (result) {
			IPA_UC_OFFLOAD_ERR("fail to activate: %d\n", result);
			return result;
		}
	} else {
		result = ipa_rm_add_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
			IPA_RM_RESOURCE_APPS_CONS);
		if (result) {
		IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n", result);
			IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n",
				result);
			return result;
		}

		result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
		if (result == -EINPROGRESS) {
		if (wait_for_completion_timeout(&ntn_ctx->ntn_completion,
			10*HZ) == 0) {
			IPA_UC_OFFLOAD_ERR("ETH_PROD resource req time out\n");
			if (wait_for_completion_timeout(&ntn_ctx->ntn_completion
				, 10*HZ) == 0) {
				IPA_UC_OFFLOAD_ERR("ETH_PROD req timeout\n");
				result = -EFAULT;
				goto fail;
			}
@@ -368,6 +440,7 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
			result = -EFAULT;
			goto fail;
		}
	}

	ntn_ctx->state = IPA_UC_OFFLOAD_STATE_UP;
	result = ipa_setup_uc_ntn_pipes(inp, ntn_ctx->notify,
@@ -383,6 +456,7 @@ int ipa_uc_ntn_conn_pipes(struct ipa_ntn_conn_in_params *inp,
	return 0;

fail:
	if (!ipa_pm_is_used())
		ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
			IPA_RM_RESOURCE_APPS_CONS);
	return result;
@@ -455,6 +529,11 @@ int ipa_set_perf_profile(struct ipa_perf_profile *profile)
		return -EINVAL;
	}

	if (ipa_pm_is_used())
		return ipa_pm_set_perf_profile(
			ipa_uc_offload_ctx[IPA_UC_NTN]->pm_hdl,
			profile->max_supported_bw_mbps);

	if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
		IPA_UC_OFFLOAD_ERR("fail to setup rm perf profile\n");
		return -EFAULT;
@@ -471,9 +550,17 @@ static int ipa_uc_ntn_disconn_pipes(struct ipa_uc_offload_ctx *ntn_ctx)

	ntn_ctx->state = IPA_UC_OFFLOAD_STATE_INITIALIZED;

	if (ipa_pm_is_used()) {
		ret = ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
		if (ret) {
			IPA_UC_OFFLOAD_ERR("fail to deactivate res: %d\n",
			ret);
			return -EFAULT;
		}
	} else {
		ret = ipa_rm_release_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
		if (ret) {
		IPA_UC_OFFLOAD_ERR("fail to release ETHERNET_PROD res: %d\n",
			IPA_UC_OFFLOAD_ERR("fail release ETHERNET_PROD: %d\n",
							ret);
			return -EFAULT;
		}
@@ -481,9 +568,10 @@ static int ipa_uc_ntn_disconn_pipes(struct ipa_uc_offload_ctx *ntn_ctx)
		ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
			IPA_RM_RESOURCE_APPS_CONS);
		if (ret) {
		IPA_UC_OFFLOAD_ERR("fail to del dep ETH_PROD->APPS, %d\n", ret);
			IPA_UC_OFFLOAD_ERR("fail del dep ETH->APPS, %d\n", ret);
			return -EFAULT;
		}
	}

	ipa_ep_idx_ul = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_PROD);
	ipa_ep_idx_dl = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_CONS);
@@ -539,15 +627,19 @@ static int ipa_uc_ntn_cleanup(struct ipa_uc_offload_ctx *ntn_ctx)
	int len, result = 0;
	struct ipa_ioc_del_hdr *hdr;

	if (ipa_pm_is_used()) {
		ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
	} else {
		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD)) {
		IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD resource\n");
			IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD\n");
			return -EFAULT;
		}

		if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS)) {
		IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS resource\n");
			IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS\n");
			return -EFAULT;
		}
	}

	len = sizeof(struct ipa_ioc_del_hdr) + 2 * sizeof(struct ipa_hdr_del);
	hdr = kzalloc(len, GFP_KERNEL);
+215 −44

File changed.

Preview size limit exceeded, changes collapsed.

+146 −41

File changed.

Preview size limit exceeded, changes collapsed.

Loading