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

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

Merge "msm: mhi_dev: Add uevent support"

parents c89dc3d0 4a695f22
Loading
Loading
Loading
Loading
+42 −14
Original line number Diff line number Diff line
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -72,11 +72,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
@@ -466,7 +467,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);
@@ -927,6 +928,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",
@@ -992,6 +995,10 @@ send_start_completion_event:
		if (rc)
			pr_err("Error sending command completion event\n");

		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) {
@@ -1046,6 +1053,10 @@ send_start_completion_event:
				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:
@@ -1119,6 +1130,10 @@ send_start_completion_event:
			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:
@@ -1300,7 +1315,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);
@@ -1781,7 +1796,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);

@@ -2338,7 +2353,8 @@ 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)
@@ -2353,25 +2369,36 @@ static void mhi_ring_init_cb(void *data)
	queue_work(mhi->ring_init_wq, &mhi->ring_init_cb_work);
}

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;

	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)
int mhi_ctrl_state_info(uint32_t idx, uint32_t *info)
{
	if (!info) {
		pr_err("Invalid info\n");
		return -EINVAL;
	}

	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;
}
@@ -2866,7 +2893,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);
+25 −3
Original line number Diff line number Diff line
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -273,7 +273,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

@@ -603,6 +603,8 @@ struct mhi_dev {

	/*Register for interrupt*/
	bool				mhi_int;

	struct kobj_uevent_env		kobj_env;
};

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

/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 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;
@@ -1221,7 +1231,19 @@ int mhi_dev_net_interface_init(void);

void mhi_dev_notify_a7_event(struct mhi_dev *mhi);

int mhi_ctrl_state_info(uint32_t *info);
/**
 * 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.
 *		MHI_STATE=DISCONNECTED - MHI device has its pipes suspended.
 *		exposes device nodes for the supported MHI software
 *		channels.
 */
int mhi_ctrl_state_info(uint32_t idx, uint32_t *info);

void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason);

+59 −2
Original line number Diff line number Diff line
/* Copyright (c) 2015,2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015,2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -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;

@@ -983,6 +1038,8 @@ int mhi_uci_init(void)
		cdev_del(&uci_ctxt.cdev_ctrl);
	}

	uci_ctxt.mhi_uci_class->dev_uevent = mhi_state_uevent;

	return 0;

failed_char_add: