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

Commit 501b1afa 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 support to identify mhi control state"

parents 25f137ab 3a1d8194
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ 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);

void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer)
{
@@ -383,6 +384,8 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event,
			pr_err("Failed to enable command db\n");
			return;
		}

		mhi_update_state_info(MHI_STATE_CONNECTED);
		break;
	case IPA_MHI_EVENT_DATA_AVAILABLE:
		rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP);
@@ -1360,6 +1363,7 @@ int mhi_dev_suspend(struct mhi_dev *mhi)
		mhi_dev_write_to_host(mhi, &data_transfer);

	}
	mhi_update_state_info(MHI_STATE_DISCONNECTED);

	atomic_set(&mhi->mhi_dev_wake, 0);
	pm_relax(mhi->dev);
@@ -1398,6 +1402,7 @@ int mhi_dev_resume(struct mhi_dev *mhi)
		/* update the channel state in the host */
		mhi_dev_write_to_host(mhi, &data_transfer);
	}
	mhi_update_state_info(MHI_STATE_CONNECTED);

	atomic_set(&mhi->is_suspended, 0);

@@ -1843,7 +1848,6 @@ static void mhi_dev_enable(struct work_struct *work)
		return;
	}

	mhi_uci_init();
	/*Enable MHI dev network stack Interface*/
	rc = mhi_dev_net_interface_init();
	if (rc)
@@ -1911,6 +1915,8 @@ static void mhi_dev_enable(struct work_struct *work)

	if (mhi_ctx->config_iatu)
		enable_irq(mhi_ctx->mhi_irq);

	mhi_update_state_info(MHI_STATE_CONNECTED);
}

static void mhi_ring_init_cb(void *data)
@@ -1925,6 +1931,30 @@ 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)
{
	struct mhi_dev_client_cb_reason reason;

	mhi_ctx->ctrl_info = info;

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

	*info = mhi_ctx->ctrl_info;
	mhi_log(MHI_MSG_VERBOSE, "ctrl:%d", mhi_ctx->ctrl_info);

	return 0;
}
EXPORT_SYMBOL(mhi_ctrl_state_info);

static int get_device_tree_data(struct platform_device *pdev)
{
	struct mhi_dev *mhi;
@@ -2238,6 +2268,8 @@ static int mhi_dev_probe(struct platform_device *pdev)
			pr_err("Error reading MHI Dev DT\n");
			return rc;
		}
		mhi_uci_init();
		mhi_update_state_info(MHI_STATE_CONFIGURED);
	}

	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
+16 −0
Original line number Diff line number Diff line
@@ -273,6 +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

/* Possible ring element types */
union mhi_dev_ring_element_type {
@@ -350,6 +351,13 @@ enum mhi_dev_ch_operation {
	MHI_DEV_POLL,
};

enum mhi_ctrl_info {
	MHI_STATE_CONFIGURED = 0,
	MHI_STATE_CONNECTED = 1,
	MHI_STATE_DISCONNECTED = 2,
	MHI_STATE_INVAL,
};

struct mhi_dev_channel;

struct mhi_dev_ring {
@@ -395,6 +403,7 @@ static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring,

enum cb_reason {
	MHI_DEV_TRE_AVAILABLE = 0,
	MHI_DEV_CTRL_UPDATE,
};

struct mhi_dev_client_cb_reason {
@@ -545,6 +554,9 @@ struct mhi_dev {

	/* iATU is required to map control and data region */
	bool				config_iatu;

	/* MHI state info */
	enum mhi_ctrl_info		ctrl_info;
};

enum mhi_msg_level {
@@ -1143,4 +1155,8 @@ 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);

void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason);

#endif /* _MHI_H_ */
+156 −2
Original line number Diff line number Diff line
@@ -73,6 +73,12 @@ struct chan_attr {
	u32 uci_ownership;
};

struct uci_ctrl {
	wait_queue_head_t	ctrl_wq;
	struct mhi_uci_ctxt_t	*uci_ctxt;
	atomic_t		ctrl_data_update;
};

struct uci_client {
	u32 client_index;
	/* write channel - always odd*/
@@ -100,9 +106,13 @@ struct uci_client {
struct mhi_uci_ctxt_t {
	struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS];
	struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
	struct uci_ctrl ctrl_handle;
	void (*event_notifier)(struct mhi_dev_client_cb_reason *cb);
	dev_t start_ctrl_nr;
	struct cdev cdev[MHI_MAX_SOFTWARE_CHANNELS];
	dev_t ctrl_nr;
	struct cdev cdev_ctrl;
	struct device *dev;
	struct class *mhi_uci_class;
	atomic_t mhi_disabled;
	atomic_t mhi_enable_notif_wq_active;
@@ -129,12 +139,16 @@ MODULE_PARM_DESC(mhi_uci_ipc_log_lvl, "ipc dbg lvl");

static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
		size_t count, loff_t *offp);
static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf,
		size_t count, loff_t *offp);
static ssize_t mhi_uci_client_write(struct file *file,
		const char __user *buf, size_t count, loff_t *offp);
static int mhi_uci_client_open(struct inode *mhi_inode, struct file*);
static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*);
static int mhi_uci_client_release(struct inode *mhi_inode,
		struct file *file_handle);
static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait);
static struct mhi_uci_ctxt_t uci_ctxt;

static int mhi_init_read_chan(struct uci_client *client_handle,
@@ -215,6 +229,30 @@ error_memcpy:
	return data_inserted_so_far;
}

static unsigned int mhi_uci_ctrl_poll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
	struct uci_ctrl *uci_ctrl_handle;

	uci_ctrl_handle = file->private_data;

	if (!uci_ctrl_handle)
		return -ENODEV;

	poll_wait(file, &uci_ctrl_handle->ctrl_wq, wait);
	if (!atomic_read(&uci_ctxt.mhi_disabled) &&
		atomic_read(&uci_ctrl_handle->ctrl_data_update)) {
		uci_log(UCI_DBG_VERBOSE, "Client can read ctrl_state");
		mask |= POLLIN | POLLRDNORM;
	}

	uci_log(UCI_DBG_VERBOSE,
		"Client attempted to poll ctrl returning mask 0x%x\n",
		mask);

	return mask;
}

static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
@@ -297,6 +335,22 @@ handle_not_rdy_err:
	return rc;
}

static int mhi_uci_ctrl_open(struct inode *inode,
			struct file *file_handle)
{
	struct uci_ctrl *uci_ctrl_handle;

	uci_log(UCI_DBG_DBG, "Client opened ctrl file device node\n");

	uci_ctrl_handle = &uci_ctxt.ctrl_handle;
	if (!uci_ctrl_handle)
		return -EINVAL;

	file_handle->private_data = uci_ctrl_handle;

	return 0;
}

static int mhi_uci_client_open(struct inode *mhi_inode,
				struct file *file_handle)
{
@@ -381,6 +435,53 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
	return rc;
}

static ssize_t mhi_uci_ctrl_client_read(struct file *file,
		char __user *user_buf,
		size_t count, loff_t *offp)
{
	uint32_t rc = 0, info;
	int nbytes, size;
	char buf[MHI_CTRL_STATE];
	struct uci_ctrl *uci_ctrl_handle = NULL;

	if (!file || !user_buf || !count ||
		(count < MHI_CTRL_STATE) || !file->private_data)
		return -EINVAL;

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

	switch (info) {
	case MHI_STATE_CONFIGURED:
		nbytes = scnprintf(buf, sizeof(buf),
			"MHI_STATE=CONFIGURED");
		break;
	case MHI_STATE_CONNECTED:
		nbytes = scnprintf(buf, sizeof(buf),
			"MHI_STATE=CONNECTED");
		break;
	case MHI_STATE_DISCONNECTED:
		nbytes = scnprintf(buf, sizeof(buf),
			"MHI_STATE=DISCONNECTED");
		break;
	default:
		pr_err("invalid info:%d\n", info);
		return -EINVAL;
	}


	size = simple_read_from_buffer(user_buf, count, offp, buf, nbytes);

	atomic_set(&uci_ctrl_handle->ctrl_data_update, 0);

	if (size == 0)
		*offp = 0;

	return size;
}

static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
		size_t uspace_buf_size, loff_t *bytes_pending)
{
@@ -636,6 +737,23 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt)
	return 0;
}

void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason)
{
	struct uci_ctrl *uci_ctrl_handle = NULL;

	if (reason->reason == MHI_DEV_CTRL_UPDATE) {
		uci_ctrl_handle = &uci_ctxt.ctrl_handle;
		if (!uci_ctrl_handle) {
			pr_err("Invalid uci ctrl handle\n");
			return;
		}

		uci_log(UCI_DBG_DBG, "received state change update\n");
		wake_up(&uci_ctrl_handle->ctrl_wq);
		atomic_set(&uci_ctrl_handle->ctrl_data_update, 1);
	}
}
EXPORT_SYMBOL(uci_ctrl_update);

static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason)
{
@@ -720,6 +838,12 @@ static long mhi_uci_client_ioctl(struct file *file, unsigned cmd,
	return rc;
}

static const struct file_operations mhi_uci_ctrl_client_fops = {
	.open = mhi_uci_ctrl_open,
	.read = mhi_uci_ctrl_client_read,
	.poll = mhi_uci_ctrl_poll,
};

static const struct file_operations mhi_uci_client_fops = {
	.read = mhi_uci_client_read,
	.write = mhi_uci_client_write,
@@ -772,16 +896,25 @@ int mhi_uci_init(void)
			}
		}
	}

	init_waitqueue_head(&uci_ctxt.ctrl_handle.ctrl_wq);
	uci_log(UCI_DBG_INFO, "Allocating char devices.\n");
	r = alloc_chrdev_region(&uci_ctxt.start_ctrl_nr,
			0, MHI_MAX_SOFTWARE_CHANNELS,
			DEVICE_NAME);

	if (IS_ERR_VALUE(r)) {
		uci_log(UCI_DBG_ERROR,
				"Failed to alloc char devs, ret 0x%x\n", r);
		goto failed_char_alloc;
	}

	r = alloc_chrdev_region(&uci_ctxt.ctrl_nr, 0, 1, DEVICE_NAME);
	if (IS_ERR_VALUE(r)) {
		uci_log(UCI_DBG_ERROR,
				"Failed to alloc char ctrl devs, 0x%x\n", r);
		goto failed_char_alloc;
	}

	uci_log(UCI_DBG_INFO, "Creating class\n");
	uci_ctxt.mhi_uci_class = class_create(THIS_MODULE,
						DEVICE_NAME);
@@ -805,12 +938,12 @@ int mhi_uci_init(void)
					i, r);
				goto failed_char_add;
			}

			uci_ctxt.client_handles[i].dev =
				device_create(uci_ctxt.mhi_uci_class, NULL,
						uci_ctxt.start_ctrl_nr + i,
						NULL, DEVICE_NAME "_pipe_%d",
						i * 2);

			if (IS_ERR(uci_ctxt.client_handles[i].dev)) {
				uci_log(UCI_DBG_ERROR,
						"Failed to add cdev %d\n", i);
@@ -819,6 +952,27 @@ int mhi_uci_init(void)
			}
		}
	}

	/* Control node */
	cdev_init(&uci_ctxt.cdev_ctrl, &mhi_uci_ctrl_client_fops);
	uci_ctxt.cdev_ctrl.owner = THIS_MODULE;
	r = cdev_add(&uci_ctxt.cdev_ctrl, uci_ctxt.ctrl_nr , 1);
	if (IS_ERR_VALUE(r)) {
		uci_log(UCI_DBG_ERROR,
		"Failed to add ctrl cdev %d, ret 0x%x\n", i, r);
		goto failed_char_add;
	}

	uci_ctxt.dev =
		device_create(uci_ctxt.mhi_uci_class, NULL,
				uci_ctxt.ctrl_nr,
				NULL, DEVICE_NAME "_ctrl");
	if (IS_ERR(uci_ctxt.dev)) {
		uci_log(UCI_DBG_ERROR,
				"Failed to add ctrl cdev %d\n", i);
		cdev_del(&uci_ctxt.cdev_ctrl);
	}

	return 0;

failed_char_add: