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

Commit 72dbdc73 authored by Ashok Vuyyuru's avatar Ashok Vuyyuru
Browse files

msm: ipa3: Fix to race condition in IPA client lock



Because accessing IPA client lock multiple place, checking endpoint
valid not unlocking some scenarios, it leads to unlocking the mutex.
To avoid this scenario add the lock based client.

Change-Id: I75c214eca1593e14eebe9f03a980f95b51924667
Signed-off-by: default avatarAshok Vuyyuru <avuyyuru@codeaurora.org>
parent d8508ccb
Loading
Loading
Loading
Loading
+37 −23
Original line number Diff line number Diff line
@@ -644,66 +644,80 @@ int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt,
	return 0;
}

static enum ipa_client_cb_type ipa_get_client_cb_type(u32 ipa_ep_idx)
{
	enum ipa_client_type client_type;
	enum ipa_client_cb_type client_cb;

	client_type = ipa3_get_client_by_pipe(ipa_ep_idx);

	if (client_type == IPA_CLIENT_USB_PROD ||
			client_type == IPA_CLIENT_USB_CONS) {
		IPADBG("USB Client registered\n");
		client_cb = IPA_USB_CLNT;
	} else if (client_type == IPA_CLIENT_MHI_PROD ||
			client_type == IPA_CLIENT_MHI_CONS) {
		IPADBG("MHI Client registered\n");
		client_cb = IPA_MHI_CLNT;
	} else {
		IPAERR("Invalid IPA client\n");
		client_cb = IPA_MAX_CLNT;
	}

	return client_cb;
}
void ipa3_register_lock_unlock_callback(int (*client_cb)(bool is_lock),
						u32 ipa_ep_idx)
{
	struct ipa3_ep_context *ep;
	enum ipa_client_cb_type client;

	IPADBG("entry\n");

	ep = &ipa3_ctx->ep[ipa_ep_idx];

	if (!ep->valid) {
		IPAERR("Invalid EP\n");
	client = ipa_get_client_cb_type(ipa_ep_idx);
	if (client == IPA_MAX_CLNT)
		return;
	}

	if (client_cb == NULL) {
		IPAERR("Bad Param");
		return;
	}

	ep->client_lock_unlock = client_cb;
	if (!ipa3_ctx->client_lock_unlock[client])
		ipa3_ctx->client_lock_unlock[client] = client_cb;
	IPADBG("exit\n");
}

void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx)
{
	struct ipa3_ep_context *ep;
	enum ipa_client_cb_type client_cb;

	IPADBG("entry\n");

	ep = &ipa3_ctx->ep[ipa_ep_idx];

	if (!ep->valid) {
		IPAERR("Invalid EP\n");
	client_cb = ipa_get_client_cb_type(ipa_ep_idx);
	if (client_cb == IPA_MAX_CLNT)
		return;
	}

	if (ep->client_lock_unlock == NULL) {
	if (ipa3_ctx->client_lock_unlock[client_cb] == NULL) {
		IPAERR("client_lock_unlock is already NULL");
		return;
	}

	ep->client_lock_unlock = NULL;
	ipa3_ctx->client_lock_unlock[client_cb] = NULL;
	IPADBG("exit\n");
}

static void client_lock_unlock_cb(u32 ipa_ep_idx, bool is_lock)
{
	struct ipa3_ep_context *ep;
	enum ipa_client_cb_type client_cb;

	IPADBG("entry\n");

	ep = &ipa3_ctx->ep[ipa_ep_idx];

	if (!ep->valid) {
		IPAERR("Invalid EP\n");
	client_cb = ipa_get_client_cb_type(ipa_ep_idx);
	if (client_cb == IPA_MAX_CLNT)
		return;
	}

	if (ep->client_lock_unlock)
		ep->client_lock_unlock(is_lock);
	if (ipa3_ctx->client_lock_unlock[client_cb])
		ipa3_ctx->client_lock_unlock[client_cb](is_lock);

	IPADBG("exit\n");
}
+8 −2
Original line number Diff line number Diff line
@@ -782,8 +782,6 @@ struct ipa3_ep_context {
	u32 eot_in_poll_err;
	bool ep_delay_set;

	int (*client_lock_unlock)(bool is_lock);

	/* sys MUST be the last element of this struct */
	struct ipa3_sys_context *sys;
};
@@ -1377,6 +1375,12 @@ enum ipa_smmu_cb_type {
	IPA_SMMU_CB_MAX
};

enum ipa_client_cb_type {
	IPA_USB_CLNT,
	IPA_MHI_CLNT,
	IPA_MAX_CLNT
};

/**
 * struct ipa3_char_device_context - IPA character device
 * @class: pointer to the struct class
@@ -1620,6 +1624,7 @@ struct ipa3_context {
	bool vlan_mode_iface[IPA_VLAN_IF_MAX];
	bool wdi_over_pcie;
	bool fw_loaded;
	int (*client_lock_unlock[IPA_MAX_CLNT])(bool is_lock);
};

struct ipa3_plat_drv_res {
@@ -2290,6 +2295,7 @@ void ipa3_proxy_clk_unvote(void);
bool ipa3_is_client_handle_valid(u32 clnt_hdl);

enum ipa_client_type ipa3_get_client_mapping(int pipe_idx);
enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx);

void ipa_init_ep_flt_bitmap(void);

+1 −1
Original line number Diff line number Diff line
@@ -2888,7 +2888,7 @@ enum ipa_client_type ipa3_get_client_mapping(int pipe_idx)
 *
 * Return value: client type
 */
static enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx)
enum ipa_client_type ipa3_get_client_by_pipe(int pipe_idx)
{
	int j = 0;