linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: mgross@linux.intel.com
To: markgross@kernel.org, mgross@linux.intel.com, arnd@arndb.de,
	bp@suse.de, damien.lemoal@wdc.com, dragan.cvetic@xilinx.com,
	gregkh@linuxfoundation.org, corbet@lwn.net,
	palmerdabbelt@google.com, paul.walmsley@sifive.com,
	peng.fan@nxp.com, robh+dt@kernel.org, shawnguo@kernel.org,
	jassisinghbrar@gmail.com
Cc: linux-kernel@vger.kernel.org, Seamus Kelly <seamus.kelly@intel.com>
Subject: [PATCH v3 22/34] xlink-core: Enable VPU IP management and runtime control
Date: Mon, 25 Jan 2021 21:40:24 -0800	[thread overview]
Message-ID: <20210126054036.61587-23-mgross@linux.intel.com> (raw)
In-Reply-To: <20210126054036.61587-1-mgross@linux.intel.com>

From: Seamus Kelly <seamus.kelly@intel.com>

Enable VPU management including, enumeration, boot and runtime control.

Add APIs:
	write control data:
		used to transmit small, local data
	start vpu:
			calls boot_device API ( soon to be deprecated )
	stop vpu
			calls reset_device API ( soon to be deprecated )
	reset vpu
			calls reset_device API ( soon to be deprecated )
	get device name:
		Returns the device name for the input device id
		This could be a char device path, for example "/dev/ttyUSB0"
		for a serial device; or it could be a device string
		description, for example, for PCIE "00:00.0 Host bridge: Intel
		Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)"
	get device list:
		Returns the list of software device IDs for all connected
		physical devices
	get device status:
		returns the current state of the input device
			OFF - The device is off (D3cold/Slot power removed).
			BUSY - device is busy and not available (device is booting)
			READY - device is available for use
			ERROR - device HW failure is detected
			RECOVERY - device is in recovery mode, waiting for recovery operations
	boot device:
		When used on the remote host - starts the SOC device by calling
		corresponding function from VPU Driver.
		Takes firmware's 'binary_name' as input.
		For Linux, the firmware image is expected to be located in
		'/lib/firmware' folder or its subfolders.
		For Linux, 'binary_name' is not a path but an image name that
		will be searched in the default Linux search paths ('/lib/firmware').
		When used on the local host - triggers the booting of VPUIP device.
	reset device:
		When used on the remote host - resets the device by calling
		corresponding VPU Driver function.
		When used on the local host - resets the VPUIP device
	get device mode:
		query and returns the current device power mode
	set device mode:
		used for device throttling or entering various power modes


Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Mark Gross <mgross@linux.intel.com>
Signed-off-by: Seamus Kelly <seamus.kelly@intel.com>
---
 drivers/misc/xlink-core/xlink-core.c        | 235 ++++++++++++++++++++
 drivers/misc/xlink-core/xlink-defs.h        |   2 +
 drivers/misc/xlink-core/xlink-ioctl.c       | 214 ++++++++++++++++++
 drivers/misc/xlink-core/xlink-ioctl.h       |   9 +
 drivers/misc/xlink-core/xlink-multiplexer.c |  56 +++++
 drivers/misc/xlink-core/xlink-platform.c    |  86 +++++++
 include/linux/xlink.h                       |  27 +++
 7 files changed, 629 insertions(+)

diff --git a/drivers/misc/xlink-core/xlink-core.c b/drivers/misc/xlink-core/xlink-core.c
index bdbf8c6a99ca..d0a3f98d16af 100644
--- a/drivers/misc/xlink-core/xlink-core.c
+++ b/drivers/misc/xlink-core/xlink-core.c
@@ -73,6 +73,8 @@ struct keembay_xlink_dev {
 	struct mutex lock;  // protect access to xlink_dev
 };
 
+static u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
 /*
  * global variable pointing to our xlink device.
  *
@@ -264,6 +266,9 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case XL_READ_DATA:
 		rc = ioctl_read_data(arg);
 		break;
+	case XL_READ_TO_BUFFER:
+		rc = ioctl_read_to_buffer(arg);
+		break;
 	case XL_WRITE_DATA:
 		rc = ioctl_write_data(arg);
 		break;
@@ -276,9 +281,39 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case XL_CLOSE_CHANNEL:
 		rc = ioctl_close_channel(arg);
 		break;
+	case XL_START_VPU:
+		rc = ioctl_start_vpu(arg);
+		break;
+	case XL_STOP_VPU:
+		rc = xlink_stop_vpu();
+		break;
+	case XL_RESET_VPU:
+		rc = xlink_stop_vpu();
+		break;
 	case XL_DISCONNECT:
 		rc = ioctl_disconnect(arg);
 		break;
+	case XL_GET_DEVICE_NAME:
+		rc = ioctl_get_device_name(arg);
+		break;
+	case XL_GET_DEVICE_LIST:
+		rc = ioctl_get_device_list(arg);
+		break;
+	case XL_GET_DEVICE_STATUS:
+		rc = ioctl_get_device_status(arg);
+		break;
+	case XL_BOOT_DEVICE:
+		rc = ioctl_boot_device(arg);
+		break;
+	case XL_RESET_DEVICE:
+		rc = ioctl_reset_device(arg);
+		break;
+	case XL_GET_DEVICE_MODE:
+		rc = ioctl_get_device_mode(arg);
+		break;
+	case XL_SET_DEVICE_MODE:
+		rc = ioctl_set_device_mode(arg);
+		break;
 	}
 	if (rc)
 		return -EIO;
@@ -289,6 +324,30 @@ static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 /*
  * xlink Kernel API.
  */
+enum xlink_error xlink_stop_vpu(void)
+{
+#ifdef CONFIG_XLINK_LOCAL_HOST
+	int rc;
+
+	rc = xlink_ipc_reset_device(0x0); // stop vpu slice 0
+	if (rc)
+		return X_LINK_ERROR;
+#endif
+	return X_LINK_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(xlink_stop_vpu);
+enum xlink_error xlink_start_vpu(char *filename)
+{
+#ifdef CONFIG_XLINK_LOCAL_HOST
+	int rc;
+
+	rc = xlink_ipc_boot_device(0x0, filename); // start vpu slice 0
+	if (rc)
+		return X_LINK_ERROR;
+#endif
+	return X_LINK_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(xlink_start_vpu);
 
 enum xlink_error xlink_initialize(void)
 {
@@ -527,6 +586,34 @@ enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
 	return rc;
 }
 
+enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
+					  u16 chan, u8 const *pmessage,
+					  u32 size)
+{
+	struct xlink_event *event;
+	struct xlink_link *link;
+	int event_queued = 0;
+	enum xlink_error rc;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	if (size > XLINK_MAX_CONTROL_DATA_SIZE)
+		return X_LINK_ERROR; // TODO: XLink Parameter Error
+	link = get_link_by_sw_device_id(handle->sw_device_id);
+	if (!link)
+		return X_LINK_ERROR;
+	event = xlink_create_event(link->id, XLINK_WRITE_CONTROL_REQ,
+				   &link->handle, chan, size, 0);
+	if (!event)
+		return X_LINK_ERROR;
+	memcpy(event->header.control_data, pmessage, size);
+	rc = xlink_multiplexer_tx(event, &event_queued);
+	if (!event_queued)
+		xlink_destroy_event(event);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_write_control_data);
+
 enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
 				      u16 chan, u8 const *message, u32 size)
 {
@@ -711,6 +798,154 @@ enum xlink_error xlink_disconnect(struct xlink_handle *handle)
 }
 EXPORT_SYMBOL_GPL(xlink_disconnect);
 
+enum xlink_error xlink_get_device_list(u32 *sw_device_id_list,
+				       u32 *num_devices)
+{
+	u32 interface_nmb_devices = 0;
+	enum xlink_error rc;
+	int i;
+
+	if (!xlink)
+		return X_LINK_ERROR;
+	if (!sw_device_id_list || !num_devices)
+		return X_LINK_ERROR;
+	/* loop through each interface and combine the lists */
+	for (i = 0; i < NMB_OF_INTERFACES; i++) {
+		rc = xlink_platform_get_device_list(i, sw_device_id_list,
+						    &interface_nmb_devices);
+		if (!rc) {
+			*num_devices += interface_nmb_devices;
+			sw_device_id_list += interface_nmb_devices;
+		}
+		interface_nmb_devices = 0;
+	}
+	return X_LINK_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(xlink_get_device_list);
+enum xlink_error xlink_get_device_name(struct xlink_handle *handle, char *name,
+				       size_t name_size)
+{
+	enum xlink_error rc;
+	int interface;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	if (!name || !name_size)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_get_device_name(interface, handle->sw_device_id,
+					    name, name_size);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_get_device_name);
+enum xlink_error xlink_get_device_status(struct xlink_handle *handle,
+					 u32 *device_status)
+{
+	enum xlink_error rc;
+	u32 interface;
+
+	if (!xlink)
+		return X_LINK_ERROR;
+	if (!device_status)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_get_device_status(interface, handle->sw_device_id,
+					      device_status);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_get_device_status);
+enum xlink_error xlink_boot_device(struct xlink_handle *handle,
+				   const char *binary_name)
+{
+	enum xlink_error rc;
+	u32 interface;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	if (!binary_name)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_boot_device(interface, handle->sw_device_id,
+					binary_name);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_boot_device);
+enum xlink_error xlink_reset_device(struct xlink_handle *handle)
+{
+	enum xlink_error rc;
+	u32 interface;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_reset_device(interface, handle->sw_device_id);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_reset_device);
+enum xlink_error xlink_set_device_mode(struct xlink_handle *handle,
+				       enum xlink_device_power_mode power_mode)
+{
+	enum xlink_error rc;
+	u32 interface;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_set_device_mode(interface, handle->sw_device_id,
+					    power_mode);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_set_device_mode);
+enum xlink_error xlink_get_device_mode(struct xlink_handle *handle,
+				       enum xlink_device_power_mode *power_mode)
+{
+	enum xlink_error rc;
+	u32 interface;
+
+	if (!xlink || !handle)
+		return X_LINK_ERROR;
+	interface = get_interface_from_sw_device_id(handle->sw_device_id);
+	if (interface == NULL_INTERFACE)
+		return X_LINK_ERROR;
+	rc = xlink_platform_get_device_mode(interface, handle->sw_device_id,
+					    power_mode);
+	if (rc)
+		rc = X_LINK_ERROR;
+	else
+		rc = X_LINK_SUCCESS;
+	return rc;
+}
+EXPORT_SYMBOL_GPL(xlink_get_device_mode);
 /* Device tree driver match. */
 static const struct of_device_id kmb_xlink_of_match[] = {
 	{
diff --git a/drivers/misc/xlink-core/xlink-defs.h b/drivers/misc/xlink-core/xlink-defs.h
index 09aee36d5542..8985f6631175 100644
--- a/drivers/misc/xlink-core/xlink-defs.h
+++ b/drivers/misc/xlink-core/xlink-defs.h
@@ -101,6 +101,7 @@ enum xlink_event_type {
 	XLINK_OPEN_CHANNEL_REQ,
 	XLINK_CLOSE_CHANNEL_REQ,
 	XLINK_PING_REQ,
+	XLINK_WRITE_CONTROL_REQ,
 	XLINK_REQ_LAST,
 	// response events
 	XLINK_WRITE_RESP = 0x10,
@@ -111,6 +112,7 @@ enum xlink_event_type {
 	XLINK_OPEN_CHANNEL_RESP,
 	XLINK_CLOSE_CHANNEL_RESP,
 	XLINK_PING_RESP,
+	XLINK_WRITE_CONTROL_RESP,
 	XLINK_RESP_LAST,
 };
 
diff --git a/drivers/misc/xlink-core/xlink-ioctl.c b/drivers/misc/xlink-core/xlink-ioctl.c
index 1f75ad38137b..90947bbccfed 100644
--- a/drivers/misc/xlink-core/xlink-ioctl.c
+++ b/drivers/misc/xlink-core/xlink-ioctl.c
@@ -111,6 +111,34 @@ int ioctl_read_data(unsigned long arg)
 	return copy_result_to_user(rd.return_code, rc);
 }
 
+int ioctl_read_to_buffer(unsigned long arg)
+{
+	struct xlink_handle		devh	= {};
+	struct xlinkreadtobuffer	rdtobuf = {};
+	int rc = 0;
+	u32 size;
+	u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
+	if (copy_from_user(&rdtobuf, (void __user *)arg,
+			   sizeof(struct xlinkreadtobuffer)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
+				       (u8 *)volbuf, &size);
+	if (!rc) {
+		if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
+				 size))
+			return -EFAULT;
+		if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
+				 sizeof(size)))
+			return -EFAULT;
+	}
+
+	return copy_result_to_user(rdtobuf.return_code, rc);
+}
+
 int ioctl_write_data(unsigned long arg)
 {
 	struct xlink_handle	devh	= {};
@@ -194,6 +222,26 @@ int ioctl_close_channel(unsigned long arg)
 	return copy_result_to_user(op.return_code, rc);
 }
 
+int ioctl_start_vpu(unsigned long arg)
+{
+	struct xlinkstartvpu	startvpu = {};
+	char filename[64];
+	int rc = 0;
+
+	if (copy_from_user(&startvpu, (void __user *)arg,
+			   sizeof(struct xlinkstartvpu)))
+		return -EFAULT;
+	if (startvpu.namesize > sizeof(filename))
+		return -EINVAL;
+	memset(filename, 0, sizeof(filename));
+	if (copy_from_user(filename, (void __user *)startvpu.filename,
+			   startvpu.namesize))
+		return -EFAULT;
+	rc = xlink_start_vpu(filename);
+
+	return copy_result_to_user(startvpu.return_code, rc);
+}
+
 int ioctl_disconnect(unsigned long arg)
 {
 	struct xlink_handle	devh	= {};
@@ -210,3 +258,169 @@ int ioctl_disconnect(unsigned long arg)
 
 	return copy_result_to_user(con.return_code, rc);
 }
+
+int ioctl_get_device_name(unsigned long arg)
+{
+	struct xlink_handle		devh	= {};
+	struct xlinkgetdevicename	devn	= {};
+	char name[XLINK_MAX_DEVICE_NAME_SIZE];
+	int rc = 0;
+
+	if (copy_from_user(&devn, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicename)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devn.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
+		rc = xlink_get_device_name(&devh, name, devn.name_size);
+		if (!rc) {
+			if (copy_to_user((void __user *)devn.name, (void *)name,
+					 devn.name_size))
+				return -EFAULT;
+		}
+	} else {
+		rc = X_LINK_ERROR;
+	}
+
+	return copy_result_to_user(devn.return_code, rc);
+}
+
+int ioctl_get_device_list(unsigned long arg)
+{
+	struct xlinkgetdevicelist	devl	= {};
+	u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
+	u32 num_devices = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devl, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicelist)))
+		return -EFAULT;
+	rc = xlink_get_device_list(sw_device_id_list, &num_devices);
+	if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
+		/* TODO: this next copy is dangerous! we have no idea
+		 * how large the devl.sw_device_id_list buffer is
+		 * provided by the user. if num_devices is too large,
+		 * the copy will overflow the buffer.
+		 */
+		if (copy_to_user((void __user *)devl.sw_device_id_list,
+				 (void *)sw_device_id_list,
+				 (sizeof(*sw_device_id_list)
+				 * num_devices)))
+			return -EFAULT;
+		if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
+				 (sizeof(num_devices))))
+			return -EFAULT;
+	}
+
+	return copy_result_to_user(devl.return_code, rc);
+}
+
+int ioctl_get_device_status(unsigned long arg)
+{
+	struct xlink_handle		devh	= {};
+	struct xlinkgetdevicestatus	devs	= {};
+	u32 device_status = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devs, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicestatus)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devs.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_get_device_status(&devh, &device_status);
+	if (!rc) {
+		if (copy_to_user((void __user *)devs.device_status,
+				 (void *)&device_status,
+				 sizeof(device_status)))
+			return -EFAULT;
+	}
+
+	return copy_result_to_user(devs.return_code, rc);
+}
+
+int ioctl_boot_device(unsigned long arg)
+{
+	struct xlink_handle		devh	= {};
+	struct xlinkbootdevice		boot	= {};
+	char filename[64];
+	int rc = 0;
+
+	if (copy_from_user(&boot, (void __user *)arg,
+			   sizeof(struct xlinkbootdevice)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)boot.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (boot.binary_name_size > sizeof(filename))
+		return -EINVAL;
+	memset(filename, 0, sizeof(filename));
+	if (copy_from_user(filename, (void __user *)boot.binary_name,
+			   boot.binary_name_size))
+		return -EFAULT;
+	rc = xlink_boot_device(&devh, filename);
+
+	return copy_result_to_user(boot.return_code, rc);
+}
+
+int ioctl_reset_device(unsigned long arg)
+{
+	struct xlink_handle		devh	= {};
+	struct xlinkresetdevice		res	= {};
+	int rc = 0;
+
+	if (copy_from_user(&res, (void __user *)arg,
+			   sizeof(struct xlinkresetdevice)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)res.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_reset_device(&devh);
+
+	return copy_result_to_user(res.return_code, rc);
+}
+
+int ioctl_get_device_mode(unsigned long arg)
+{
+	struct xlink_handle	devh	= {};
+	struct xlinkdevmode	devm	= {};
+	u32 device_mode = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devm, (void __user *)arg,
+			   sizeof(struct xlinkdevmode)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devm.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_get_device_mode(&devh, &device_mode);
+	if (!rc) {
+		if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
+				 sizeof(device_mode)))
+			return -EFAULT;
+	}
+
+	return copy_result_to_user(devm.return_code, rc);
+}
+
+int ioctl_set_device_mode(unsigned long arg)
+{
+	struct xlink_handle	devh	= {};
+	struct xlinkdevmode	devm	= {};
+	u32 device_mode = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devm, (void __user *)arg,
+			   sizeof(struct xlinkdevmode)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devm.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
+			   sizeof(device_mode)))
+		return -EFAULT;
+	rc = xlink_set_device_mode(&devh, device_mode);
+
+	return copy_result_to_user(devm.return_code, rc);
+}
diff --git a/drivers/misc/xlink-core/xlink-ioctl.h b/drivers/misc/xlink-core/xlink-ioctl.h
index 0f317c6c2b94..d016d8418f30 100644
--- a/drivers/misc/xlink-core/xlink-ioctl.h
+++ b/drivers/misc/xlink-core/xlink-ioctl.h
@@ -12,10 +12,19 @@
 int ioctl_connect(unsigned long arg);
 int ioctl_open_channel(unsigned long arg);
 int ioctl_read_data(unsigned long arg);
+int ioctl_read_to_buffer(unsigned long arg);
 int ioctl_write_data(unsigned long arg);
 int ioctl_write_volatile_data(unsigned long arg);
 int ioctl_release_data(unsigned long arg);
 int ioctl_close_channel(unsigned long arg);
+int ioctl_start_vpu(unsigned long arg);
 int ioctl_disconnect(unsigned long arg);
+int ioctl_get_device_name(unsigned long arg);
+int ioctl_get_device_list(unsigned long arg);
+int ioctl_get_device_status(unsigned long arg);
+int ioctl_boot_device(unsigned long arg);
+int ioctl_reset_device(unsigned long arg);
+int ioctl_get_device_mode(unsigned long arg);
+int ioctl_set_device_mode(unsigned long arg);
 
 #endif /* XLINK_IOCTL_H_ */
diff --git a/drivers/misc/xlink-core/xlink-multiplexer.c b/drivers/misc/xlink-core/xlink-multiplexer.c
index 339734826f3e..48451dc30712 100644
--- a/drivers/misc/xlink-core/xlink-multiplexer.c
+++ b/drivers/misc/xlink-core/xlink-multiplexer.c
@@ -491,6 +491,7 @@ enum xlink_error xlink_multiplexer_tx(struct xlink_event *event,
 	switch (event->header.type) {
 	case XLINK_WRITE_REQ:
 	case XLINK_WRITE_VOLATILE_REQ:
+	case XLINK_WRITE_CONTROL_REQ:
 		opchan = get_channel(link_id, chan);
 		if (!opchan || opchan->chan->status != CHAN_OPEN) {
 			rc = X_LINK_COMMUNICATION_FAIL;
@@ -657,6 +658,7 @@ enum xlink_error xlink_multiplexer_tx(struct xlink_event *event,
 		break;
 	case XLINK_WRITE_RESP:
 	case XLINK_WRITE_VOLATILE_RESP:
+	case XLINK_WRITE_CONTROL_RESP:
 	case XLINK_READ_RESP:
 	case XLINK_READ_TO_BUFFER_RESP:
 	case XLINK_RELEASE_RESP:
@@ -759,6 +761,46 @@ enum xlink_error xlink_multiplexer_rx(struct xlink_event *event)
 		}
 		release_channel(opchan);
 		break;
+	case XLINK_WRITE_CONTROL_REQ:
+		opchan = get_channel(link_id, chan);
+		if (!opchan) {
+			rc = X_LINK_COMMUNICATION_FAIL;
+		} else {
+			event->header.timeout = opchan->chan->timeout;
+			buffer = xlink_platform_allocate(xmux->dev, &paddr,
+							 event->header.size,
+							 XLINK_PACKET_ALIGNMENT,
+							 XLINK_NORMAL_MEMORY);
+			if (buffer) {
+				size = event->header.size;
+				memcpy(buffer, event->header.control_data, size);
+				event->paddr = paddr;
+				event->data = buffer;
+				if (add_packet_to_channel(opchan,
+							  &opchan->rx_queue,
+							  event->data,
+							  event->header.size,
+							  paddr)) {
+					xlink_platform_deallocate(xmux->dev,
+								  buffer, paddr,
+								  event->header.size,
+								  XLINK_PACKET_ALIGNMENT,
+								  XLINK_NORMAL_MEMORY);
+					rc = X_LINK_ERROR;
+					release_channel(opchan);
+					break;
+				}
+				event->header.type = XLINK_WRITE_CONTROL_RESP;
+				xlink_dispatcher_event_add(EVENT_RX, event);
+				// channel blocking, notify waiting threads of available packet
+				complete(&opchan->pkt_available);
+			} else {
+				// failed to allocate buffer
+				rc = X_LINK_ERROR;
+			}
+		}
+		release_channel(opchan);
+		break;
 	case XLINK_READ_REQ:
 	case XLINK_READ_TO_BUFFER_REQ:
 		opchan = get_channel(link_id, chan);
@@ -848,6 +890,7 @@ enum xlink_error xlink_multiplexer_rx(struct xlink_event *event)
 		break;
 	case XLINK_WRITE_RESP:
 	case XLINK_WRITE_VOLATILE_RESP:
+	case XLINK_WRITE_CONTROL_RESP:
 		opchan = get_channel(link_id, chan);
 		if (!opchan)
 			rc = X_LINK_COMMUNICATION_FAIL;
@@ -929,6 +972,18 @@ enum xlink_error xlink_passthrough(struct xlink_event *event)
 			rc = X_LINK_ERROR;
 		}
 		break;
+	case XLINK_WRITE_CONTROL_REQ:
+		if (xmux->channels[link_id][chan].ipc_status == CHAN_OPEN) {
+			ipc.is_volatile = 1;
+			rc = xlink_platform_write(IPC_INTERFACE,
+						  event->handle->sw_device_id,
+						  event->header.control_data,
+						  &event->header.size, 0, &ipc);
+		} else {
+			/* channel not open */
+			rc = X_LINK_ERROR;
+		}
+		break;
 	case XLINK_READ_REQ:
 		if (xmux->channels[link_id][chan].ipc_status == CHAN_OPEN) {
 			/* if channel has receive blocking set,
@@ -1013,6 +1068,7 @@ enum xlink_error xlink_passthrough(struct xlink_event *event)
 	case XLINK_PING_REQ:
 	case XLINK_WRITE_RESP:
 	case XLINK_WRITE_VOLATILE_RESP:
+	case XLINK_WRITE_CONTROL_RESP:
 	case XLINK_READ_RESP:
 	case XLINK_READ_TO_BUFFER_RESP:
 	case XLINK_RELEASE_RESP:
diff --git a/drivers/misc/xlink-core/xlink-platform.c b/drivers/misc/xlink-core/xlink-platform.c
index c34b69ee206b..56eb8da28a5f 100644
--- a/drivers/misc/xlink-core/xlink-platform.c
+++ b/drivers/misc/xlink-core/xlink-platform.c
@@ -34,6 +34,20 @@ static inline int xlink_ipc_read(u32 sw_device_id, void *data,
 				 size_t * const size, u32 timeout, void *context)
 { return -1; }
 
+static inline int xlink_ipc_get_device_list(u32 *sw_device_id_list,
+					    u32 *num_devices)
+{ return -1; }
+static inline int xlink_ipc_get_device_name(u32 sw_device_id,
+					    char *device_name, size_t name_size)
+{ return -1; }
+static inline int xlink_ipc_get_device_status(u32 sw_device_id,
+					      u32 *device_status)
+{ return -1; }
+static inline int xlink_ipc_boot_device(u32 sw_device_id,
+					const char *binary_path)
+{ return -1; }
+static inline int xlink_ipc_reset_device(u32 sw_device_id)
+{ return -1; }
 static inline int xlink_ipc_open_channel(u32 sw_device_id,
 					 u32 channel)
 { return -1; }
@@ -59,6 +73,23 @@ static int (*write_fcts[NMB_OF_INTERFACES])(u32, void *, size_t * const, u32) =
 static int (*read_fcts[NMB_OF_INTERFACES])(u32, void *, size_t * const, u32) = {
 		NULL, xlink_pcie_read, NULL, NULL};
 
+static int (*reset_fcts[NMB_OF_INTERFACES])(u32) = {
+		xlink_ipc_reset_device, xlink_pcie_reset_device, NULL, NULL};
+static int (*boot_fcts[NMB_OF_INTERFACES])(u32, const char *) = {
+		xlink_ipc_boot_device, xlink_pcie_boot_device, NULL, NULL};
+static int (*dev_name_fcts[NMB_OF_INTERFACES])(u32, char *, size_t) = {
+		xlink_ipc_get_device_name, xlink_pcie_get_device_name,
+		NULL, NULL};
+static int (*dev_list_fcts[NMB_OF_INTERFACES])(u32 *, u32 *) = {
+		xlink_ipc_get_device_list, xlink_pcie_get_device_list,
+		NULL, NULL};
+static int (*dev_status_fcts[NMB_OF_INTERFACES])(u32, u32 *) = {
+		xlink_ipc_get_device_status, xlink_pcie_get_device_status,
+		NULL, NULL};
+static int (*dev_set_mode_fcts[NMB_OF_INTERFACES])(u32, u32) = {
+		NULL, NULL, NULL, NULL};
+static int (*dev_get_mode_fcts[NMB_OF_INTERFACES])(u32, u32 *) = {
+		NULL, NULL, NULL, NULL};
 static int (*open_chan_fcts[NMB_OF_INTERFACES])(u32, u32) = {
 		xlink_ipc_open_channel, NULL, NULL, NULL};
 
@@ -103,6 +134,61 @@ int xlink_platform_read(u32 interface, u32 sw_device_id, void *data,
 	return read_fcts[interface](sw_device_id, data, size, timeout);
 }
 
+int xlink_platform_reset_device(u32 interface, u32 sw_device_id)
+{
+	if (interface >= NMB_OF_INTERFACES || !reset_fcts[interface])
+		return -1;
+	return reset_fcts[interface](sw_device_id);
+}
+
+int xlink_platform_boot_device(u32 interface, u32 sw_device_id,
+			       const char *binary_name)
+{
+	if (interface >= NMB_OF_INTERFACES || !boot_fcts[interface])
+		return -1;
+	return boot_fcts[interface](sw_device_id, binary_name);
+}
+
+int xlink_platform_get_device_name(u32 interface, u32 sw_device_id,
+				   char *device_name, size_t name_size)
+{
+	if (interface >= NMB_OF_INTERFACES || !dev_name_fcts[interface])
+		return -1;
+	return dev_name_fcts[interface](sw_device_id, device_name, name_size);
+}
+
+int xlink_platform_get_device_list(u32 interface,
+				   u32 *sw_device_id_list, u32 *num_devices)
+{
+	if (interface >= NMB_OF_INTERFACES || !dev_list_fcts[interface])
+		return -1;
+	return dev_list_fcts[interface](sw_device_id_list, num_devices);
+}
+
+int xlink_platform_get_device_status(u32 interface, u32 sw_device_id,
+				     u32 *device_status)
+{
+	if (interface >= NMB_OF_INTERFACES || !dev_status_fcts[interface])
+		return -1;
+	return dev_status_fcts[interface](sw_device_id, device_status);
+}
+
+int xlink_platform_set_device_mode(u32 interface, u32 sw_device_id,
+				   u32 power_mode)
+{
+	if (interface >= NMB_OF_INTERFACES || !dev_set_mode_fcts[interface])
+		return -1;
+	return dev_set_mode_fcts[interface](sw_device_id, power_mode);
+}
+
+int xlink_platform_get_device_mode(u32 interface, u32 sw_device_id,
+				   u32 *power_mode)
+{
+	if (interface >= NMB_OF_INTERFACES || !dev_get_mode_fcts[interface])
+		return -1;
+	return dev_get_mode_fcts[interface](sw_device_id, power_mode);
+}
+
 int xlink_platform_open_channel(u32 interface, u32 sw_device_id,
 				u32 channel)
 {
diff --git a/include/linux/xlink.h b/include/linux/xlink.h
index c22439d5aade..b00dbc719530 100644
--- a/include/linux/xlink.h
+++ b/include/linux/xlink.h
@@ -78,6 +78,10 @@ enum xlink_error xlink_write_data(struct xlink_handle *handle,
 enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
 				      u16 chan, u8 const *message, u32 size);
 
+enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
+					  u16 chan, u8 const *message,
+					  u32 size);
+
 enum xlink_error xlink_read_data(struct xlink_handle *handle,
 				 u16 chan, u8 **message, u32 *size);
 
@@ -90,6 +94,29 @@ enum xlink_error xlink_release_data(struct xlink_handle *handle,
 
 enum xlink_error xlink_disconnect(struct xlink_handle *handle);
 
+enum xlink_error xlink_get_device_list(u32 *sw_device_id_list, u32 *num_devices);
+
+enum xlink_error xlink_get_device_name(struct xlink_handle *handle, char *name,
+				       size_t name_size);
+
+enum xlink_error xlink_get_device_status(struct xlink_handle *handle,
+					 u32 *device_status);
+
+enum xlink_error xlink_boot_device(struct xlink_handle *handle,
+				   const char *binary_name);
+
+enum xlink_error xlink_reset_device(struct xlink_handle *handle);
+
+enum xlink_error xlink_set_device_mode(struct xlink_handle *handle,
+				       enum xlink_device_power_mode power_mode);
+
+enum xlink_error xlink_get_device_mode(struct xlink_handle *handle,
+				       enum xlink_device_power_mode *power_mode);
+
+enum xlink_error xlink_start_vpu(char *filename); /* depreciated */
+
+enum xlink_error xlink_stop_vpu(void); /* depreciated */
+
 /* API functions to be implemented
  *
  * enum xlink_error xlink_write_crc_data(struct xlink_handle *handle,
-- 
2.17.1


  parent reply	other threads:[~2021-01-26 23:31 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-26  5:40 [PATCH v3 00/34] Intel Vision Processing base enabling mgross
2021-01-26  5:40 ` [PATCH v3 01/34] Add Vision Processing Unit (VPU) documentation mgross
2021-01-26  5:40 ` [PATCH v3 02/34] dt-bindings: mailbox: Add Intel VPU IPC mailbox bindings mgross
2021-01-26 13:44   ` Rob Herring
2021-01-26 14:47     ` Gross, Mark
2021-01-28 21:42       ` mark gross
2021-01-26  5:40 ` [PATCH v3 03/34] mailbox: vpu-ipc-mailbox: Add support for Intel VPU IPC mailbox mgross
2021-01-26  5:40 ` [PATCH v3 04/34] dt-bindings: Add bindings for Keem Bay IPC driver mgross
2021-01-26  5:40 ` [PATCH v3 05/34] keembay-ipc: Add Keem Bay IPC module mgross
2021-01-26  5:40 ` [PATCH v3 06/34] dt-bindings: Add bindings for Keem Bay VPU IPC driver mgross
2021-01-27 14:00   ` Rob Herring
2021-01-30  2:02     ` mark gross
2021-01-26  5:40 ` [PATCH v3 07/34] keembay-vpu-ipc: Add Keem Bay VPU IPC module mgross
2021-01-26  5:40 ` [PATCH v3 08/34] misc: xlink-pcie: Add documentation for XLink PCIe driver mgross
2021-01-26  5:40 ` [PATCH v3 09/34] misc: xlink-pcie: lh: Add PCIe EPF driver for Local Host mgross
2021-01-26  5:40 ` [PATCH v3 10/34] misc: xlink-pcie: lh: Add PCIe EP DMA functionality mgross
2021-01-26  5:40 ` [PATCH v3 11/34] misc: xlink-pcie: lh: Add core communication logic mgross
2021-01-26  5:40 ` [PATCH v3 12/34] misc: xlink-pcie: lh: Prepare changes for adding remote host driver mgross
2021-01-26  5:40 ` [PATCH v3 13/34] misc: xlink-pcie: rh: Add PCIe EP driver for Remote Host mgross
2021-01-26  5:40 ` [PATCH v3 14/34] misc: xlink-pcie: rh: Add core communication logic mgross
2021-01-26  5:40 ` [PATCH v3 15/34] misc: xlink-pcie: Add XLink API interface mgross
2021-01-26  5:40 ` [PATCH v3 16/34] misc: xlink-pcie: Add asynchronous event notification support for XLink mgross
2021-01-26  5:40 ` [PATCH v3 17/34] xlink-ipc: Add xlink ipc device tree bindings mgross
2021-01-27 14:00   ` Rob Herring
2021-01-26  5:40 ` [PATCH v3 18/34] xlink-ipc: Add xlink ipc driver mgross
2021-01-26  5:40 ` [PATCH v3 19/34] xlink-core: Add xlink core device tree bindings mgross
2021-01-27 14:00   ` Rob Herring
2021-01-26  5:40 ` [PATCH v3 20/34] xlink-core: Add xlink core driver xLink mgross
2021-01-26  5:40 ` [PATCH v3 21/34] xlink-core: Enable xlink protocol over pcie mgross
2021-01-26  5:40 ` mgross [this message]
2021-01-26  5:40 ` [PATCH v3 23/34] xlink-core: add async channel and events mgross
2021-01-26  5:40 ` [PATCH v3 24/34] dt-bindings: misc: Add Keem Bay vpumgr mgross
2021-01-26  5:40 ` [PATCH v3 25/34] misc: Add Keem Bay VPU manager mgross
2021-01-27  4:31   ` Randy Dunlap
2021-01-26  5:40 ` [PATCH v3 26/34] dt-bindings: misc: intel_tsens: Add tsens thermal bindings documentation mgross
2021-01-26  5:40 ` [PATCH v3 27/34] misc: Tsens ARM host thermal driver mgross
2021-01-26  5:40 ` [PATCH v3 28/34] misc: Intel tsens IA host driver mgross
2021-01-26  5:40 ` [PATCH v3 29/34] Intel tsens i2c slave driver mgross
2021-01-27  4:36   ` Randy Dunlap
2021-01-26  5:40 ` [PATCH v3 30/34] misc:intel_tsens: Intel Keem Bay tsens driver mgross
2021-01-26  5:40 ` [PATCH v3 31/34] Intel Keem Bay XLink SMBus driver mgross
2021-01-27  4:29   ` Randy Dunlap
2021-01-26  5:40 ` [PATCH v3 32/34] dt-bindings: misc: hddl_dev: Add hddl device management documentation mgross
2021-01-26  5:40 ` [PATCH v3 33/34] misc: Hddl device management for local host mgross
2021-01-27  4:34   ` Randy Dunlap
2021-01-26  5:40 ` [PATCH v3 34/34] misc: HDDL device management for IA host mgross
2021-01-27  4:26   ` Randy Dunlap
2021-01-30  2:20 [PATCH v3 00/34] Intel Vision Processing base enabling mgross
2021-01-30  2:20 ` [PATCH v3 22/34] xlink-core: Enable VPU IP management and runtime control mgross

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210126054036.61587-23-mgross@linux.intel.com \
    --to=mgross@linux.intel.com \
    --cc=arnd@arndb.de \
    --cc=bp@suse.de \
    --cc=corbet@lwn.net \
    --cc=damien.lemoal@wdc.com \
    --cc=dragan.cvetic@xilinx.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jassisinghbrar@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=markgross@kernel.org \
    --cc=palmerdabbelt@google.com \
    --cc=paul.walmsley@sifive.com \
    --cc=peng.fan@nxp.com \
    --cc=robh+dt@kernel.org \
    --cc=seamus.kelly@intel.com \
    --cc=shawnguo@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).