All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lizhi Hou <lizhi.hou@xilinx.com>
To: <linux-kernel@vger.kernel.org>
Cc: Lizhi Hou <lizhi.hou@xilinx.com>, <linux-fpga@vger.kernel.org>,
	<maxz@xilinx.com>, <sonal.santan@xilinx.com>, <yliu@xilinx.com>,
	<michal.simek@xilinx.com>, <stefanos@xilinx.com>,
	<devicetree@vger.kernel.org>, <trix@redhat.com>, <mdf@kernel.org>,
	<robh@kernel.org>, Max Zhen <max.zhen@xilinx.com>
Subject: [PATCH V5 XRT Alveo 10/20] fpga: xrt: main driver for management function device
Date: Tue, 27 Apr 2021 13:54:21 -0700	[thread overview]
Message-ID: <20210427205431.23896-11-lizhi.hou@xilinx.com> (raw)
In-Reply-To: <20210427205431.23896-1-lizhi.hou@xilinx.com>

xrt driver that handles IOCTLs, such as hot reset and xclbin download.

Signed-off-by: Sonal Santan <sonal.santan@xilinx.com>
Signed-off-by: Max Zhen <max.zhen@xilinx.com>
Signed-off-by: Lizhi Hou <lizhi.hou@xilinx.com>
---
 drivers/fpga/xrt/include/xmgnt-main.h |  34 ++
 drivers/fpga/xrt/mgnt/xmgnt-main.c    | 660 ++++++++++++++++++++++++++
 drivers/fpga/xrt/mgnt/xmgnt.h         |  33 ++
 include/uapi/linux/xrt/xmgnt-ioctl.h  |  46 ++
 4 files changed, 773 insertions(+)
 create mode 100644 drivers/fpga/xrt/include/xmgnt-main.h
 create mode 100644 drivers/fpga/xrt/mgnt/xmgnt-main.c
 create mode 100644 drivers/fpga/xrt/mgnt/xmgnt.h
 create mode 100644 include/uapi/linux/xrt/xmgnt-ioctl.h

diff --git a/drivers/fpga/xrt/include/xmgnt-main.h b/drivers/fpga/xrt/include/xmgnt-main.h
new file mode 100644
index 000000000000..b46dac710cd3
--- /dev/null
+++ b/drivers/fpga/xrt/include/xmgnt-main.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 Xilinx, Inc.
+ *
+ * Authors:
+ *	Cheng Zhen <maxz@xilinx.com>
+ */
+
+#ifndef _XMGNT_MAIN_H_
+#define _XMGNT_MAIN_H_
+
+#include <linux/xrt/xclbin.h>
+#include "xleaf.h"
+
+enum xrt_mgnt_main_leaf_cmd {
+	XRT_MGNT_MAIN_GET_AXLF_SECTION = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */
+	XRT_MGNT_MAIN_GET_VBNV,
+};
+
+/* There are three kind of partitions. Each of them is programmed independently. */
+enum provider_kind {
+	XMGNT_BLP, /* Base Logic Partition */
+	XMGNT_PLP, /* Provider Logic Partition */
+	XMGNT_ULP, /* User Logic Partition */
+};
+
+struct xrt_mgnt_main_get_axlf_section {
+	enum provider_kind xmmigas_axlf_kind;
+	enum axlf_section_kind xmmigas_section_kind;
+	void *xmmigas_section;
+	u64 xmmigas_section_size;
+};
+
+#endif	/* _XMGNT_MAIN_H_ */
diff --git a/drivers/fpga/xrt/mgnt/xmgnt-main.c b/drivers/fpga/xrt/mgnt/xmgnt-main.c
new file mode 100644
index 000000000000..a1c6dc34f6c0
--- /dev/null
+++ b/drivers/fpga/xrt/mgnt/xmgnt-main.c
@@ -0,0 +1,660 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Alveo FPGA MGNT PF entry point driver
+ *
+ * Copyright (C) 2020-2021 Xilinx, Inc.
+ *
+ * Authors:
+ *	Sonal Santan <sonals@xilinx.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include "xclbin-helper.h"
+#include "metadata.h"
+#include "xleaf.h"
+#include <linux/xrt/xmgnt-ioctl.h>
+#include "xleaf/devctl.h"
+#include "xmgnt-main.h"
+#include "xrt-mgr.h"
+#include "xleaf/icap.h"
+#include "xleaf/axigate.h"
+#include "xmgnt.h"
+
+#define XMGNT_MAIN "xmgnt_main"
+#define XMGNT_SUPP_XCLBIN_MAJOR 2
+
+#define XMGNT_FLAG_FLASH_READY	1
+#define XMGNT_FLAG_DEVCTL_READY	2
+
+#define XMGNT_UUID_STR_LEN	(UUID_SIZE * 2 + 1)
+
+struct xmgnt_main {
+	struct xrt_device *xdev;
+	struct axlf *firmware_blp;
+	struct axlf *firmware_plp;
+	struct axlf *firmware_ulp;
+	u32 flags;
+	struct fpga_manager *fmgr;
+	struct mutex lock; /* busy lock */
+	uuid_t *blp_interface_uuids;
+	u32 blp_interface_uuid_num;
+};
+
+/*
+ * VBNV stands for Vendor, BoardID, Name, Version. It is a string
+ * which describes board and shell.
+ *
+ * Caller is responsible for freeing the returned string.
+ */
+char *xmgnt_get_vbnv(struct xrt_device *xdev)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	const char *vbnv;
+	char *ret;
+	int i;
+
+	if (xmm->firmware_plp)
+		vbnv = xmm->firmware_plp->header.platform_vbnv;
+	else if (xmm->firmware_blp)
+		vbnv = xmm->firmware_blp->header.platform_vbnv;
+	else
+		return NULL;
+
+	ret = kstrdup(vbnv, GFP_KERNEL);
+	if (!ret)
+		return NULL;
+
+	for (i = 0; i < strlen(ret); i++) {
+		if (ret[i] == ':' || ret[i] == '.')
+			ret[i] = '_';
+	}
+	return ret;
+}
+
+static int get_dev_uuid(struct xrt_device *xdev, char *uuidstr, size_t len)
+{
+	struct xrt_devctl_rw devctl_arg = { 0 };
+	struct xrt_device *devctl_leaf;
+	char uuid_buf[UUID_SIZE];
+	uuid_t uuid;
+	int err;
+
+	devctl_leaf = xleaf_get_leaf_by_epname(xdev, XRT_MD_NODE_BLP_ROM);
+	if (!devctl_leaf) {
+		xrt_err(xdev, "can not get %s", XRT_MD_NODE_BLP_ROM);
+		return -EINVAL;
+	}
+
+	devctl_arg.xdr_id = XRT_DEVCTL_ROM_UUID;
+	devctl_arg.xdr_buf = uuid_buf;
+	devctl_arg.xdr_len = sizeof(uuid_buf);
+	devctl_arg.xdr_offset = 0;
+	err = xleaf_call(devctl_leaf, XRT_DEVCTL_READ, &devctl_arg);
+	xleaf_put_leaf(xdev, devctl_leaf);
+	if (err) {
+		xrt_err(xdev, "can not get uuid: %d", err);
+		return err;
+	}
+	import_uuid(&uuid, uuid_buf);
+	xrt_md_trans_uuid2str(&uuid, uuidstr);
+
+	return 0;
+}
+
+int xmgnt_hot_reset(struct xrt_device *xdev)
+{
+	int ret = xleaf_broadcast_event(xdev, XRT_EVENT_PRE_HOT_RESET, false);
+
+	if (ret) {
+		xrt_err(xdev, "offline failed, hot reset is canceled");
+		return ret;
+	}
+
+	xleaf_hot_reset(xdev);
+	xleaf_broadcast_event(xdev, XRT_EVENT_POST_HOT_RESET, false);
+	return 0;
+}
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
+{
+	struct xrt_device *xdev = to_xrt_dev(dev);
+
+	xmgnt_hot_reset(xdev);
+	return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static ssize_t VBNV_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct xrt_device *xdev = to_xrt_dev(dev);
+	ssize_t ret;
+	char *vbnv;
+
+	vbnv = xmgnt_get_vbnv(xdev);
+	if (!vbnv)
+		return -EINVAL;
+	ret = sprintf(buf, "%s\n", vbnv);
+	kfree(vbnv);
+	return ret;
+}
+static DEVICE_ATTR_RO(VBNV);
+
+/* logic uuid is the uuid uniquely identfy the partition */
+static ssize_t logic_uuids_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct xrt_device *xdev = to_xrt_dev(dev);
+	char uuid[XMGNT_UUID_STR_LEN];
+	ssize_t ret;
+
+	/* Getting UUID pointed to by VSEC, should be the same as logic UUID of BLP. */
+	ret = get_dev_uuid(xdev, uuid, sizeof(uuid));
+	if (ret)
+		return ret;
+	ret = sprintf(buf, "%s\n", uuid);
+	return ret;
+}
+static DEVICE_ATTR_RO(logic_uuids);
+
+static ssize_t interface_uuids_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct xrt_device *xdev = to_xrt_dev(dev);
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	ssize_t ret = 0;
+	u32 i;
+
+	for (i = 0; i < xmm->blp_interface_uuid_num; i++) {
+		char uuidstr[XMGNT_UUID_STR_LEN];
+
+		xrt_md_trans_uuid2str(&xmm->blp_interface_uuids[i], uuidstr);
+		ret += sprintf(buf + ret, "%s\n", uuidstr);
+	}
+	return ret;
+}
+static DEVICE_ATTR_RO(interface_uuids);
+
+static struct attribute *xmgnt_main_attrs[] = {
+	&dev_attr_reset.attr,
+	&dev_attr_VBNV.attr,
+	&dev_attr_logic_uuids.attr,
+	&dev_attr_interface_uuids.attr,
+	NULL,
+};
+
+static const struct attribute_group xmgnt_main_attrgroup = {
+	.attrs = xmgnt_main_attrs,
+};
+
+static int load_firmware_from_disk(struct xrt_device *xdev, struct axlf **fw_buf, size_t *len)
+{
+	char uuid[XMGNT_UUID_STR_LEN];
+	const struct firmware *fw;
+	char fw_name[256];
+	int err = 0;
+
+	*len = 0;
+	err = get_dev_uuid(xdev, uuid, sizeof(uuid));
+	if (err)
+		return err;
+
+	snprintf(fw_name, sizeof(fw_name), "xilinx/%s/partition.xsabin", uuid);
+	xrt_info(xdev, "try loading fw: %s", fw_name);
+
+	err = request_firmware(&fw, fw_name, DEV(xdev));
+	if (err)
+		return err;
+
+	*fw_buf = vmalloc(fw->size);
+	if (!*fw_buf) {
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	*len = fw->size;
+	memcpy(*fw_buf, fw->data, fw->size);
+
+	release_firmware(fw);
+	return 0;
+}
+
+static const struct axlf *xmgnt_get_axlf_firmware(struct xmgnt_main *xmm, enum provider_kind kind)
+{
+	switch (kind) {
+	case XMGNT_BLP:
+		return xmm->firmware_blp;
+	case XMGNT_PLP:
+		return xmm->firmware_plp;
+	case XMGNT_ULP:
+		return xmm->firmware_ulp;
+	default:
+		xrt_err(xmm->xdev, "unknown axlf kind: %d", kind);
+		return NULL;
+	}
+}
+
+/* The caller needs to free the returned dtb buffer */
+char *xmgnt_get_dtb(struct xrt_device *xdev, enum provider_kind kind)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	const struct axlf *provider;
+	char *dtb = NULL;
+	int rc;
+
+	provider = xmgnt_get_axlf_firmware(xmm, kind);
+	if (!provider)
+		return dtb;
+
+	rc = xrt_xclbin_get_metadata(DEV(xdev), provider, &dtb);
+	if (rc)
+		xrt_err(xdev, "failed to find dtb: %d", rc);
+	return dtb;
+}
+
+/* The caller needs to free the returned uuid buffer */
+static const char *get_uuid_from_firmware(struct xrt_device *xdev, const struct axlf *xclbin)
+{
+	const void *uuiddup = NULL;
+	const void *uuid = NULL;
+	void *dtb = NULL;
+	int rc;
+
+	rc = xrt_xclbin_get_section(DEV(xdev), xclbin, PARTITION_METADATA, &dtb, NULL);
+	if (rc)
+		return NULL;
+
+	rc = xrt_md_get_prop(DEV(xdev), dtb, NULL, NULL, XRT_MD_PROP_LOGIC_UUID, &uuid, NULL);
+	if (!rc)
+		uuiddup = kstrdup(uuid, GFP_KERNEL);
+	vfree(dtb);
+	return uuiddup;
+}
+
+static bool is_valid_firmware(struct xrt_device *xdev,
+			      const struct axlf *xclbin, size_t fw_len)
+{
+	const char *fw_buf = (const char *)xclbin;
+	size_t axlflen = xclbin->header.length;
+	char dev_uuid[XMGNT_UUID_STR_LEN];
+	const char *fw_uuid;
+	int err;
+
+	err = get_dev_uuid(xdev, dev_uuid, sizeof(dev_uuid));
+	if (err)
+		return false;
+
+	if (memcmp(fw_buf, XCLBIN_VERSION2, sizeof(XCLBIN_VERSION2)) != 0) {
+		xrt_err(xdev, "unknown fw format");
+		return false;
+	}
+
+	if (axlflen > fw_len) {
+		xrt_err(xdev, "truncated fw, length: %zu, expect: %zu", fw_len, axlflen);
+		return false;
+	}
+
+	if (xclbin->header.version_major != XMGNT_SUPP_XCLBIN_MAJOR) {
+		xrt_err(xdev, "firmware is not supported");
+		return false;
+	}
+
+	fw_uuid = get_uuid_from_firmware(xdev, xclbin);
+	if (!fw_uuid || strncmp(fw_uuid, dev_uuid, sizeof(dev_uuid)) != 0) {
+		xrt_err(xdev, "bad fw UUID: %s, expect: %s",
+			fw_uuid ? fw_uuid : "<none>", dev_uuid);
+		kfree(fw_uuid);
+		return false;
+	}
+
+	kfree(fw_uuid);
+	return true;
+}
+
+int xmgnt_get_provider_uuid(struct xrt_device *xdev, enum provider_kind kind, uuid_t *uuid)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	const struct axlf *fwbuf;
+	const char *fw_uuid;
+	int rc = -ENOENT;
+
+	mutex_lock(&xmm->lock);
+
+	fwbuf = xmgnt_get_axlf_firmware(xmm, kind);
+	if (!fwbuf)
+		goto done;
+
+	fw_uuid = get_uuid_from_firmware(xdev, fwbuf);
+	if (!fw_uuid)
+		goto done;
+
+	rc = xrt_md_trans_str2uuid(DEV(xdev), fw_uuid, uuid);
+	kfree(fw_uuid);
+
+done:
+	mutex_unlock(&xmm->lock);
+	return rc;
+}
+
+static int xmgnt_create_blp(struct xmgnt_main *xmm)
+{
+	const struct axlf *provider = xmgnt_get_axlf_firmware(xmm, XMGNT_BLP);
+	struct xrt_device *xdev = xmm->xdev;
+	int rc = 0;
+	char *dtb = NULL;
+
+	dtb = xmgnt_get_dtb(xdev, XMGNT_BLP);
+	if (!dtb) {
+		xrt_err(xdev, "did not get BLP metadata");
+		return -EINVAL;
+	}
+
+	rc = xmgnt_process_xclbin(xmm->xdev, xmm->fmgr, provider, XMGNT_BLP);
+	if (rc) {
+		xrt_err(xdev, "failed to process BLP: %d", rc);
+		goto failed;
+	}
+
+	rc = xleaf_create_group(xdev, dtb);
+	if (rc < 0)
+		xrt_err(xdev, "failed to create BLP group: %d", rc);
+	else
+		rc = 0;
+
+	WARN_ON(xmm->blp_interface_uuids);
+	rc = xrt_md_get_interface_uuids(&xdev->dev, dtb, 0, NULL);
+	if (rc > 0) {
+		xmm->blp_interface_uuid_num = rc;
+		xmm->blp_interface_uuids =
+			kcalloc(xmm->blp_interface_uuid_num, sizeof(uuid_t), GFP_KERNEL);
+		if (!xmm->blp_interface_uuids) {
+			rc = -ENOMEM;
+			goto failed;
+		}
+		xrt_md_get_interface_uuids(&xdev->dev, dtb, xmm->blp_interface_uuid_num,
+					   xmm->blp_interface_uuids);
+	}
+
+failed:
+	vfree(dtb);
+	return rc;
+}
+
+static int xmgnt_load_firmware(struct xmgnt_main *xmm)
+{
+	struct xrt_device *xdev = xmm->xdev;
+	size_t fwlen;
+	int rc;
+
+	rc = load_firmware_from_disk(xdev, &xmm->firmware_blp, &fwlen);
+	if (!rc && is_valid_firmware(xdev, xmm->firmware_blp, fwlen))
+		xmgnt_create_blp(xmm);
+	else
+		xrt_err(xdev, "failed to find firmware, giving up: %d", rc);
+	return rc;
+}
+
+static void xmgnt_main_event_cb(struct xrt_device *xdev, void *arg)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	struct xrt_event *evt = (struct xrt_event *)arg;
+	enum xrt_events e = evt->xe_evt;
+	struct xrt_device *leaf;
+	enum xrt_subdev_id id;
+
+	id = evt->xe_subdev.xevt_subdev_id;
+	switch (e) {
+	case XRT_EVENT_POST_CREATION: {
+		if (id == XRT_SUBDEV_DEVCTL && !(xmm->flags & XMGNT_FLAG_DEVCTL_READY)) {
+			leaf = xleaf_get_leaf_by_epname(xdev, XRT_MD_NODE_BLP_ROM);
+			if (leaf) {
+				xmm->flags |= XMGNT_FLAG_DEVCTL_READY;
+				xleaf_put_leaf(xdev, leaf);
+			}
+		} else if (id == XRT_SUBDEV_QSPI && !(xmm->flags & XMGNT_FLAG_FLASH_READY)) {
+			xmm->flags |= XMGNT_FLAG_FLASH_READY;
+		} else {
+			break;
+		}
+
+		if (xmm->flags & XMGNT_FLAG_DEVCTL_READY)
+			xmgnt_load_firmware(xmm);
+		break;
+	}
+	case XRT_EVENT_PRE_REMOVAL:
+		break;
+	default:
+		xrt_dbg(xdev, "ignored event %d", e);
+		break;
+	}
+}
+
+static int xmgnt_main_probe(struct xrt_device *xdev)
+{
+	struct xmgnt_main *xmm;
+
+	xrt_info(xdev, "probing...");
+
+	xmm = devm_kzalloc(DEV(xdev), sizeof(*xmm), GFP_KERNEL);
+	if (!xmm)
+		return -ENOMEM;
+
+	xmm->xdev = xdev;
+	xmm->fmgr = xmgnt_fmgr_probe(xdev);
+	if (IS_ERR(xmm->fmgr))
+		return PTR_ERR(xmm->fmgr);
+
+	xrt_set_drvdata(xdev, xmm);
+	mutex_init(&xmm->lock);
+
+	/* Ready to handle req thru sysfs nodes. */
+	if (sysfs_create_group(&DEV(xdev)->kobj, &xmgnt_main_attrgroup))
+		xrt_err(xdev, "failed to create sysfs group");
+	return 0;
+}
+
+static void xmgnt_main_remove(struct xrt_device *xdev)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+
+	/* By now, group driver should prevent any inter-leaf call. */
+
+	xrt_info(xdev, "leaving...");
+
+	kfree(xmm->blp_interface_uuids);
+	vfree(xmm->firmware_blp);
+	vfree(xmm->firmware_plp);
+	vfree(xmm->firmware_ulp);
+	xmgnt_region_cleanup_all(xdev);
+	xmgnt_fmgr_remove(xmm->fmgr);
+	sysfs_remove_group(&DEV(xdev)->kobj, &xmgnt_main_attrgroup);
+}
+
+static int
+xmgnt_mainleaf_call(struct xrt_device *xdev, u32 cmd, void *arg)
+{
+	struct xmgnt_main *xmm = xrt_get_drvdata(xdev);
+	int ret = 0;
+
+	switch (cmd) {
+	case XRT_XLEAF_EVENT:
+		xmgnt_main_event_cb(xdev, arg);
+		break;
+	case XRT_MGNT_MAIN_GET_AXLF_SECTION: {
+		struct xrt_mgnt_main_get_axlf_section *get =
+			(struct xrt_mgnt_main_get_axlf_section *)arg;
+		const struct axlf *firmware = xmgnt_get_axlf_firmware(xmm, get->xmmigas_axlf_kind);
+
+		if (!firmware) {
+			ret = -ENOENT;
+		} else {
+			ret = xrt_xclbin_get_section(DEV(xdev), firmware,
+						     get->xmmigas_section_kind,
+						     &get->xmmigas_section,
+						     &get->xmmigas_section_size);
+		}
+		break;
+	}
+	case XRT_MGNT_MAIN_GET_VBNV: {
+		char **vbnv_p = (char **)arg;
+
+		*vbnv_p = xmgnt_get_vbnv(xdev);
+		if (!*vbnv_p)
+			ret = -EINVAL;
+		break;
+	}
+	default:
+		xrt_err(xdev, "unknown cmd: %d", cmd);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int xmgnt_main_open(struct inode *inode, struct file *file)
+{
+	struct xrt_device *xdev = xleaf_devnode_open(inode);
+
+	/* Device may have gone already when we get here. */
+	if (!xdev)
+		return -ENODEV;
+
+	xrt_info(xdev, "opened");
+	file->private_data = xrt_get_drvdata(xdev);
+	return 0;
+}
+
+static int xmgnt_main_close(struct inode *inode, struct file *file)
+{
+	struct xmgnt_main *xmm = file->private_data;
+
+	xleaf_devnode_close(inode);
+
+	xrt_info(xmm->xdev, "closed");
+	return 0;
+}
+
+/*
+ * Called for xclbin download xclbin load ioctl.
+ */
+static int xmgnt_bitstream_axlf_fpga_mgr(struct xmgnt_main *xmm, void *axlf, size_t size)
+{
+	int ret;
+
+	WARN_ON(!mutex_is_locked(&xmm->lock));
+
+	/*
+	 * Should any error happens during download, we can't trust
+	 * the cached xclbin any more.
+	 */
+	vfree(xmm->firmware_ulp);
+	xmm->firmware_ulp = NULL;
+
+	ret = xmgnt_process_xclbin(xmm->xdev, xmm->fmgr, axlf, XMGNT_ULP);
+	if (ret == 0)
+		xmm->firmware_ulp = axlf;
+
+	return ret;
+}
+
+static int bitstream_axlf_ioctl(struct xmgnt_main *xmm, const void __user *arg)
+{
+	struct xmgnt_ioc_bitstream_axlf ioc_obj = { 0 };
+	struct axlf xclbin_obj = { {0} };
+	size_t copy_buffer_size = 0;
+	void *copy_buffer = NULL;
+	int ret = 0;
+
+	if (copy_from_user((void *)&ioc_obj, arg, sizeof(ioc_obj)))
+		return -EFAULT;
+	if (copy_from_user((void *)&xclbin_obj, ioc_obj.xclbin, sizeof(xclbin_obj)))
+		return -EFAULT;
+	if (memcmp(xclbin_obj.magic, XCLBIN_VERSION2, sizeof(XCLBIN_VERSION2)))
+		return -EINVAL;
+
+	copy_buffer_size = xclbin_obj.header.length;
+	if (copy_buffer_size > XCLBIN_MAX_SIZE || copy_buffer_size < sizeof(xclbin_obj))
+		return -EINVAL;
+	if (xclbin_obj.header.version_major != XMGNT_SUPP_XCLBIN_MAJOR)
+		return -EINVAL;
+
+	copy_buffer = vmalloc(copy_buffer_size);
+	if (!copy_buffer)
+		return -ENOMEM;
+
+	if (copy_from_user(copy_buffer, ioc_obj.xclbin, copy_buffer_size)) {
+		vfree(copy_buffer);
+		return -EFAULT;
+	}
+
+	ret = xmgnt_bitstream_axlf_fpga_mgr(xmm, copy_buffer, copy_buffer_size);
+	if (ret)
+		vfree(copy_buffer);
+
+	return ret;
+}
+
+static long xmgnt_main_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct xmgnt_main *xmm = filp->private_data;
+	long result = 0;
+
+	if (_IOC_TYPE(cmd) != XMGNT_IOC_MAGIC)
+		return -ENOTTY;
+
+	mutex_lock(&xmm->lock);
+
+	xrt_info(xmm->xdev, "ioctl cmd %d, arg %ld", cmd, arg);
+	switch (cmd) {
+	case XMGNT_IOCICAPDOWNLOAD_AXLF:
+		result = bitstream_axlf_ioctl(xmm, (const void __user *)arg);
+		break;
+	default:
+		result = -ENOTTY;
+		break;
+	}
+
+	mutex_unlock(&xmm->lock);
+	return result;
+}
+
+static struct xrt_dev_endpoints xrt_mgnt_main_endpoints[] = {
+	{
+		.xse_names = (struct xrt_dev_ep_names []){
+			{ .ep_name = XRT_MD_NODE_MGNT_MAIN },
+			{ NULL },
+		},
+		.xse_min_ep = 1,
+	},
+	{ 0 },
+};
+
+static struct xrt_driver xmgnt_main_driver = {
+	.driver	= {
+		.name = XMGNT_MAIN,
+	},
+	.file_ops = {
+		.xsf_ops = {
+			.owner = THIS_MODULE,
+			.open = xmgnt_main_open,
+			.release = xmgnt_main_close,
+			.unlocked_ioctl = xmgnt_main_ioctl,
+		},
+		.xsf_dev_name = "xmgnt",
+	},
+	.subdev_id = XRT_SUBDEV_MGNT_MAIN,
+	.endpoints = xrt_mgnt_main_endpoints,
+	.probe = xmgnt_main_probe,
+	.remove = xmgnt_main_remove,
+	.leaf_call = xmgnt_mainleaf_call,
+};
+
+int xmgnt_register_leaf(void)
+{
+	return xrt_register_driver(&xmgnt_main_driver);
+}
+
+void xmgnt_unregister_leaf(void)
+{
+	xrt_unregister_driver(&xmgnt_main_driver);
+}
diff --git a/drivers/fpga/xrt/mgnt/xmgnt.h b/drivers/fpga/xrt/mgnt/xmgnt.h
new file mode 100644
index 000000000000..c8159903de4a
--- /dev/null
+++ b/drivers/fpga/xrt/mgnt/xmgnt.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2021 Xilinx, Inc.
+ *
+ * Authors:
+ *	Lizhi Hou <Lizhi.Hou@xilinx.com>
+ *	Cheng Zhen <maxz@xilinx.com>
+ */
+
+#ifndef _XMGNT_H_
+#define _XMGNT_H_
+
+#include "xmgnt-main.h"
+
+struct fpga_manager;
+int xmgnt_process_xclbin(struct xrt_device *xdev,
+			 struct fpga_manager *fmgr,
+			 const struct axlf *xclbin,
+			 enum provider_kind kind);
+void xmgnt_region_cleanup_all(struct xrt_device *xdev);
+
+int xmgnt_hot_reset(struct xrt_device *xdev);
+
+/* Getting dtb for specified group. Caller should vfree returned dtb. */
+char *xmgnt_get_dtb(struct xrt_device *xdev, enum provider_kind kind);
+char *xmgnt_get_vbnv(struct xrt_device *xdev);
+int xmgnt_get_provider_uuid(struct xrt_device *xdev,
+			    enum provider_kind kind, uuid_t *uuid);
+
+int xmgnt_register_leaf(void);
+void xmgnt_unregister_leaf(void);
+
+#endif	/* _XMGNT_H_ */
diff --git a/include/uapi/linux/xrt/xmgnt-ioctl.h b/include/uapi/linux/xrt/xmgnt-ioctl.h
new file mode 100644
index 000000000000..e4ba5335fa3f
--- /dev/null
+++ b/include/uapi/linux/xrt/xmgnt-ioctl.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ *  Copyright (C) 2015-2021, Xilinx Inc
+ *
+ */
+
+/**
+ * DOC: PCIe Kernel Driver for Management Physical Function
+ * Interfaces exposed by *xrt-mgnt* driver are defined in file, *xmgnt-ioctl.h*.
+ * Core functionality provided by *xrt-mgnt* driver is described in the following table:
+ *
+ * =========== ============================== ==================================
+ * Functionality           ioctl request code           data format
+ * =========== ============================== ==================================
+ * 1 FPGA image download   XMGNT_IOCICAPDOWNLOAD_AXLF xmgnt_ioc_bitstream_axlf
+ * =========== ============================== ==================================
+ */
+
+#ifndef _XMGNT_IOCTL_H_
+#define _XMGNT_IOCTL_H_
+
+#include <linux/ioctl.h>
+
+#define XMGNT_IOC_MAGIC	'X'
+#define XMGNT_IOC_ICAP_DOWNLOAD_AXLF 0x6
+
+/**
+ * struct xmgnt_ioc_bitstream_axlf - load xclbin (AXLF) device image
+ * used with XMGNT_IOCICAPDOWNLOAD_AXLF ioctl
+ *
+ * @xclbin:	Pointer to user's xclbin structure in memory
+ */
+struct xmgnt_ioc_bitstream_axlf {
+	struct axlf *xclbin;
+};
+
+#define XMGNT_IOCICAPDOWNLOAD_AXLF				\
+	_IOW(XMGNT_IOC_MAGIC, XMGNT_IOC_ICAP_DOWNLOAD_AXLF, struct xmgnt_ioc_bitstream_axlf)
+
+/*
+ * The following definitions are for binary compatibility with classic XRT management driver
+ */
+#define XCLMGNT_IOCICAPDOWNLOAD_AXLF XMGNT_IOCICAPDOWNLOAD_AXLF
+#define xclmgnt_ioc_bitstream_axlf xmgnt_ioc_bitstream_axlf
+
+#endif
-- 
2.27.0


  parent reply	other threads:[~2021-04-27 21:00 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-27 20:54 [PATCH V5 XRT Alveo 00/20] XRT Alveo driver overview Lizhi Hou
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 01/20] Documentation: fpga: Add a document describing XRT Alveo drivers Lizhi Hou
2021-04-28 19:40   ` Tom Rix
2021-05-03 23:00   ` Moritz Fischer
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 02/20] fpga: xrt: driver metadata helper functions Lizhi Hou
2021-05-01 20:19   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 03/20] fpga: xrt: xclbin file " Lizhi Hou
2021-05-03 13:00   ` Tom Rix
2021-05-03 23:19   ` Moritz Fischer
2021-05-05 17:21     ` Lizhi Hou
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 04/20] fpga: xrt: xrt-lib driver manager Lizhi Hou
2021-05-03 13:06   ` Tom Rix
2021-05-03 21:51     ` Lizhi Hou
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 05/20] fpga: xrt: group driver Lizhi Hou
2021-05-03 13:10   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 06/20] fpga: xrt: char dev node helper functions Lizhi Hou
2021-05-03 13:27   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 07/20] fpga: xrt: root driver infrastructure Lizhi Hou
2021-05-03 13:37   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 08/20] fpga: xrt: " Lizhi Hou
2021-05-03 13:46   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 09/20] fpga: xrt: management physical function driver (root) Lizhi Hou
2021-05-03 13:49   ` Tom Rix
2021-04-27 20:54 ` Lizhi Hou [this message]
2021-05-04 13:50   ` [PATCH V5 XRT Alveo 10/20] fpga: xrt: main driver for management function device Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 11/20] fpga: xrt: fpga-mgr and region implementation for xclbin download Lizhi Hou
2021-05-04 13:56   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 12/20] fpga: xrt: VSEC driver Lizhi Hou
2021-05-04 14:00   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 13/20] fpga: xrt: User Clock Subsystem driver Lizhi Hou
2021-05-04 14:03   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 14/20] fpga: xrt: ICAP driver Lizhi Hou
2021-05-04 14:05   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 15/20] fpga: xrt: devctl xrt driver Lizhi Hou
2021-05-04 14:07   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 16/20] fpga: xrt: clock driver Lizhi Hou
2021-05-04 14:08   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 17/20] fpga: xrt: clock frequency counter driver Lizhi Hou
2021-05-04 14:10   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 18/20] fpga: xrt: DDR calibration driver Lizhi Hou
2021-05-04 14:11   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 19/20] fpga: xrt: partition isolation driver Lizhi Hou
2021-05-04 14:13   ` Tom Rix
2021-04-27 20:54 ` [PATCH V5 XRT Alveo 20/20] fpga: xrt: Kconfig and Makefile updates for XRT drivers Lizhi Hou
2021-04-27 23:53   ` kernel test robot
2021-04-27 23:53     ` kernel test robot
2021-04-28  3:12   ` kernel test robot
2021-04-28  3:12     ` kernel test robot
2021-04-28  3:12   ` [RFC PATCH] fpga: xrt: xmgnt_bridge_ops can be static kernel test robot
2021-04-28  3:12     ` kernel test robot
2021-05-04 14:18   ` [PATCH V5 XRT Alveo 20/20] fpga: xrt: Kconfig and Makefile updates for XRT drivers Tom Rix
2021-04-28 17:36 ` [PATCH V5 XRT Alveo 00/20] XRT Alveo driver overview Tom Rix

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=20210427205431.23896-11-lizhi.hou@xilinx.com \
    --to=lizhi.hou@xilinx.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-fpga@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=max.zhen@xilinx.com \
    --cc=maxz@xilinx.com \
    --cc=mdf@kernel.org \
    --cc=michal.simek@xilinx.com \
    --cc=robh@kernel.org \
    --cc=sonal.santan@xilinx.com \
    --cc=stefanos@xilinx.com \
    --cc=trix@redhat.com \
    --cc=yliu@xilinx.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.