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

Commit ba314f24 authored by Siddartha Mohanadoss's avatar Siddartha Mohanadoss
Browse files

msm: mhi_dev: Add uevent support



Clients need notification for connect, disconnect state
for the individual channels once they are updated by the
host. Send the events for clients listening to uevents
such as MBIMD for channel state updates. Client can also
poll for the current channel state through MHI ctrl uevent.

Change-Id: Ie764b4866e5e41df072a7a76105a740c89f91f17
Signed-off-by: default avatarSiddartha Mohanadoss <smohanad@codeaurora.org>
parent f0aab7ac
Loading
Loading
Loading
Loading
+40 −20
Original line number Diff line number Diff line
@@ -71,11 +71,12 @@ static struct mhi_dev *mhi_ctx;
static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event,
	unsigned long data);
static void mhi_ring_init_cb(void *user_data);
static void mhi_update_state_info(uint32_t info);
static void mhi_update_state_info(uint32_t uevent_idx, enum mhi_ctrl_info info);
static int mhi_deinit(struct mhi_dev *mhi);
static void mhi_dev_resume_init_with_link_up(struct ep_pcie_notify *notify);
static int mhi_dev_pcie_notify_event;
static void mhi_dev_transfer_completion_cb(void *mreq);
static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];

/*
 * mhi_dev_ring_cache_completion_cb () - Call back function called
@@ -454,7 +455,7 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event,
			return;
		}

		mhi_update_state_info(MHI_STATE_CONNECTED);
		mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_CONNECTED);

		ep_pcie_mask_irq_event(mhi_ctx->phandle,
				EP_PCIE_INT_EVT_MHI_A7, true);
@@ -829,7 +830,7 @@ static void mhi_dev_trigger_cb(void)

	list_for_each_entry(info, &mhi_ctx->client_cb_list, list)
		if (info->cb) {
			mhi_ctrl_state_info(&state_data);
			mhi_ctrl_state_info(info->cb_data.channel, &state_data);
			info->cb_data.ctrl_info = state_data;
			info->cb(&info->cb_data);
		}
@@ -935,6 +936,8 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
	struct mhi_addr host_addr;
	struct mhi_dev_channel *ch;
	struct mhi_dev_ring *ring;
	char *connected[2] = { "MHI_CHANNEL_STATE_12=CONNECTED", NULL};
	char *disconnected[2] = { "MHI_CHANNEL_STATE_12=DISCONNECTED", NULL};

	ch_id = el->generic.chid;
	mhi_log(MHI_MSG_VERBOSE, "for channel:%d and cmd:%d\n",
@@ -1020,6 +1023,10 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
		/* Trigger callback to clients */
		mhi_dev_trigger_cb();

		mhi_update_state_info(ch_id, MHI_STATE_CONNECTED);
		if (ch_id == MHI_CLIENT_MBIM_OUT)
			kobject_uevent_env(&mhi_ctx->dev->kobj,
						KOBJ_CHANGE, connected);
		break;
	case MHI_DEV_RING_EL_STOP:
		if (ch_id >= HW_CHANNEL_BASE) {
@@ -1072,6 +1079,10 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
				pr_err("stop event send failed\n");

			mutex_unlock(&ch->ch_lock);
			mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED);
			if (ch_id == MHI_CLIENT_MBIM_OUT)
				kobject_uevent_env(&mhi_ctx->dev->kobj,
						KOBJ_CHANGE, disconnected);
		}
		break;
	case MHI_DEV_RING_EL_RESET:
@@ -1144,6 +1155,10 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
			if (rc)
				pr_err("Error sending command completion event\n");
			mutex_unlock(&ch->ch_lock);
			mhi_update_state_info(ch_id, MHI_STATE_DISCONNECTED);
			if (ch_id == MHI_CLIENT_MBIM_OUT)
				kobject_uevent_env(&mhi_ctx->dev->kobj,
						KOBJ_CHANGE, disconnected);
		}
		break;
	default:
@@ -1325,7 +1340,7 @@ static int mhi_dev_abort(struct mhi_dev *mhi)
	}

	/* Update ctrl node */
	mhi_update_state_info(MHI_STATE_DISCONNECTED);
	mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_DISCONNECTED);

	flush_workqueue(mhi->ring_init_wq);
	flush_workqueue(mhi->pending_ring_wq);
@@ -1806,7 +1821,7 @@ int mhi_dev_resume(struct mhi_dev *mhi)
		mhi_dev_write_to_host(mhi, &data_transfer, NULL,
				MHI_DEV_DMA_SYNC);
	}
	mhi_update_state_info(MHI_STATE_CONNECTED);
	mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_CONNECTED);

	atomic_set(&mhi->is_suspended, 0);

@@ -2367,7 +2382,7 @@ static void mhi_dev_enable(struct work_struct *work)
	if (mhi_ctx->config_iatu || mhi_ctx->mhi_int)
		enable_irq(mhi_ctx->mhi_irq);

	mhi_update_state_info(MHI_STATE_CONNECTED);
	mhi_update_state_info(MHI_DEV_UEVENT_CTRL, MHI_STATE_CONFIGURED);
}

static void mhi_ring_init_cb(void *data)
@@ -2427,28 +2442,32 @@ int mhi_register_state_cb(void (*mhi_state_cb)
}
EXPORT_SYMBOL(mhi_register_state_cb);

static void mhi_update_state_info(uint32_t info)
static void mhi_update_state_info(uint32_t uevent_idx, enum mhi_ctrl_info info)
{
	struct mhi_dev_client_cb_reason reason;

	if (uevent_idx == MHI_DEV_UEVENT_CTRL)
		mhi_ctx->ctrl_info = info;

	if (info == MHI_STATE_CONNECTED)
		return;
	channel_state_info[uevent_idx].ctrl_info = info;

	if (uevent_idx == MHI_CLIENT_QMI_OUT ||
			uevent_idx == MHI_CLIENT_QMI_IN) {
		/* For legacy reasons for QTI client */
		reason.reason = MHI_DEV_CTRL_UPDATE;
		uci_ctrl_update(&reason);
	}

int mhi_ctrl_state_info(uint32_t *info)
{
	if (!info) {
		pr_err("Invalid info\n");
		return -EINVAL;
}

int mhi_ctrl_state_info(uint32_t idx, uint32_t *info)
{
	if (idx == MHI_DEV_UEVENT_CTRL)
		*info = mhi_ctx->ctrl_info;
	mhi_log(MHI_MSG_VERBOSE, "ctrl:%d", mhi_ctx->ctrl_info);
	else
		*info = channel_state_info[idx].ctrl_info;

	mhi_log(MHI_MSG_VERBOSE, "idx:%d, ctrl:%d", idx, *info);

	return 0;
}
@@ -2943,7 +2962,8 @@ static int mhi_dev_probe(struct platform_device *pdev)
				"Failed to create IPC logging context\n");
		}
		mhi_uci_init();
		mhi_update_state_info(MHI_STATE_CONFIGURED);
		mhi_update_state_info(MHI_DEV_UEVENT_CTRL,
						MHI_STATE_CONFIGURED);
	}

	INIT_WORK(&mhi_ctx->pcie_event, mhi_dev_pcie_handle_event);
+15 −2
Original line number Diff line number Diff line
@@ -275,7 +275,7 @@ struct mhi_config {
#define MHI_ENV_VALUE			2
#define MHI_MASK_ROWS_CH_EV_DB		4
#define TRB_MAX_DATA_SIZE		8192
#define MHI_CTRL_STATE			25
#define MHI_CTRL_STATE			100
#define IPA_DMA_SYNC                    1
#define IPA_DMA_ASYNC                   0

@@ -607,6 +607,8 @@ struct mhi_dev {
	bool				mhi_int;
	/* Registered client callback list */
	struct list_head		client_cb_list;

	struct kobj_uevent_env		kobj_env;
};

struct mhi_req {
@@ -712,6 +714,14 @@ enum mhi_client_channel {
	MHI_MAX_CHANNELS = 102,
};

/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 is used for internal only */
#define MHI_DEV_UEVENT_CTRL	0

struct mhi_dev_uevent_info {
	enum mhi_client_channel	channel;
	enum mhi_ctrl_info	ctrl_info;
};

struct mhi_dev_iov {
	void		*addr;
	uint32_t	buf_size;
@@ -1251,6 +1261,9 @@ void mhi_dev_notify_a7_event(struct mhi_dev *mhi);

/**
 * mhi_ctrl_state_info() - Provide MHI state info
 *		@idx: Channel number idx. Look at channel_state_info and
 *		pass the index for the corresponding channel.
 *		@info: Return the control info.
 *		MHI_STATE=CONFIGURED - MHI device is present but not ready
 *					for data traffic.
 *		MHI_STATE=CONNECTED - MHI device is ready for data transfer.
@@ -1258,7 +1271,7 @@ void mhi_dev_notify_a7_event(struct mhi_dev *mhi);
 *		exposes device nodes for the supported MHI software
 *		channels.
 */
int mhi_ctrl_state_info(uint32_t *info);
int mhi_ctrl_state_info(uint32_t idx, uint32_t *info);

/**
 * uci_ctrl_update() - Update UCI once TRE's are available for clients to
+58 −1
Original line number Diff line number Diff line
@@ -441,6 +441,61 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
	return rc;
}

static void  mhi_parse_state(char *buf, int *nbytes, uint32_t info)
{
	switch (info) {
	case MHI_STATE_CONNECTED:
		*nbytes = scnprintf(buf, MHI_CTRL_STATE,
			"CONNECTED");
		break;
	case MHI_STATE_DISCONNECTED:
		*nbytes = scnprintf(buf, MHI_CTRL_STATE,
			"DISCONNECTED");
		break;
	case MHI_STATE_CONFIGURED:
	default:
		*nbytes = scnprintf(buf, MHI_CTRL_STATE,
			"CONFIGURED");
		break;
	}
}

static int mhi_state_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	int rc, nbytes = 0;
	uint32_t info = 0;
	char buf[MHI_CTRL_STATE];

	rc = mhi_ctrl_state_info(MHI_DEV_UEVENT_CTRL, &info);
	if (rc) {
		pr_err("Failed to obtain MHI_STATE\n");
		return -EINVAL;
	}

	mhi_parse_state(buf, &nbytes, info);
	add_uevent_var(env, "MHI_STATE=%s", buf);

	rc = mhi_ctrl_state_info(MHI_CLIENT_QMI_OUT, &info);
	if (rc) {
		pr_err("Failed to obtain channel 14 state\n");
		return -EINVAL;
	}
	nbytes = 0;
	mhi_parse_state(buf, &nbytes, info);
	add_uevent_var(env, "MHI_CHANNEL_STATE_14=%s", buf);

	rc = mhi_ctrl_state_info(MHI_CLIENT_MBIM_OUT, &info);
	if (rc) {
		pr_err("Failed to obtain channel 12 state\n");
		return -EINVAL;
	}
	nbytes = 0;
	mhi_parse_state(buf, &nbytes, info);
	add_uevent_var(env, "MHI_CHANNEL_STATE_12=%s", buf);

	return 0;
}

static ssize_t mhi_uci_ctrl_client_read(struct file *file,
		char __user *user_buf,
		size_t count, loff_t *offp)
@@ -455,7 +510,7 @@ static ssize_t mhi_uci_ctrl_client_read(struct file *file,
		return -EINVAL;

	uci_ctrl_handle = file->private_data;
	rc = mhi_ctrl_state_info(&info);
	rc = mhi_ctrl_state_info(MHI_CLIENT_QMI_OUT, &info);
	if (rc)
		return -EINVAL;

@@ -993,6 +1048,8 @@ int mhi_uci_init(void)
		uci_ctxt.cdev_ctrl = NULL;
	}

	uci_ctxt.mhi_uci_class->dev_uevent = mhi_state_uevent;

	return 0;

failed_char_add: