diff mbox series

[V4,XRT,Alveo,10/20] fpga: xrt: main platform driver for management function device

Message ID 20210324052947.27889-11-lizhi.hou@xilinx.com (mailing list archive)
State New
Headers show
Series XRT Alveo driver overview | expand

Commit Message

Lizhi Hou March 24, 2021, 5:29 a.m. UTC
platform 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/xmgmt-main.h |  34 ++
 drivers/fpga/xrt/mgmt/main.c          | 670 ++++++++++++++++++++++++++
 drivers/fpga/xrt/mgmt/xmgnt.h         |  34 ++
 include/uapi/linux/xrt/xmgmt-ioctl.h  |  46 ++
 4 files changed, 784 insertions(+)
 create mode 100644 drivers/fpga/xrt/include/xmgmt-main.h
 create mode 100644 drivers/fpga/xrt/mgmt/main.c
 create mode 100644 drivers/fpga/xrt/mgmt/xmgnt.h
 create mode 100644 include/uapi/linux/xrt/xmgmt-ioctl.h

Comments

Tom Rix April 1, 2021, 2:07 p.m. UTC | #1
On 3/23/21 10:29 PM, Lizhi Hou wrote:
> platform 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/xmgmt-main.h |  34 ++
>  drivers/fpga/xrt/mgmt/main.c          | 670 ++++++++++++++++++++++++++
>  drivers/fpga/xrt/mgmt/xmgnt.h         |  34 ++
>  include/uapi/linux/xrt/xmgmt-ioctl.h  |  46 ++
>  4 files changed, 784 insertions(+)
>  create mode 100644 drivers/fpga/xrt/include/xmgmt-main.h
>  create mode 100644 drivers/fpga/xrt/mgmt/main.c
'main' is generic, how about xmgnt-main ?
>  create mode 100644 drivers/fpga/xrt/mgmt/xmgnt.h
>  create mode 100644 include/uapi/linux/xrt/xmgmt-ioctl.h
>
> diff --git a/drivers/fpga/xrt/include/xmgmt-main.h b/drivers/fpga/xrt/include/xmgmt-main.h
> new file mode 100644
> index 000000000000..dce9f0d1a0dc
> --- /dev/null
> +++ b/drivers/fpga/xrt/include/xmgmt-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 _XMGMT_MAIN_H_
> +#define _XMGMT_MAIN_H_
> +
> +#include <linux/xrt/xclbin.h>
> +#include "xleaf.h"
> +
> +enum xrt_mgmt_main_leaf_cmd {
> +	XRT_MGMT_MAIN_GET_AXLF_SECTION = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */
> +	XRT_MGMT_MAIN_GET_VBNV,
> +};
> +
> +/* There are three kind of partitions. Each of them is programmed independently. */
> +enum provider_kind {
> +	XMGMT_BLP, /* Base Logic Partition */
> +	XMGMT_PLP, /* Provider Logic Partition */
> +	XMGMT_ULP, /* User Logic Partition */
ok
> +};
> +
> +struct xrt_mgmt_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	/* _XMGMT_MAIN_H_ */
> diff --git a/drivers/fpga/xrt/mgmt/main.c b/drivers/fpga/xrt/mgmt/main.c
> new file mode 100644
> index 000000000000..f3b46e1fd78b
> --- /dev/null
> +++ b/drivers/fpga/xrt/mgmt/main.c
> @@ -0,0 +1,670 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Xilinx Alveo FPGA MGMT 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 "xclbin-helper.h"
> +#include "metadata.h"
> +#include "xleaf.h"
> +#include <linux/xrt/xmgmt-ioctl.h>
> +#include "xleaf/devctl.h"
> +#include "xmgmt-main.h"
> +#include "fmgr.h"
> +#include "xleaf/icap.h"
> +#include "xleaf/axigate.h"
> +#include "xmgnt.h"
> +
> +#define XMGMT_MAIN "xmgmt_main"
> +#define XMGMT_SUPP_XCLBIN_MAJOR 2
> +
> +#define XMGMT_FLAG_FLASH_READY	1
> +#define XMGMT_FLAG_DEVCTL_READY	2
> +
> +#define XMGMT_UUID_STR_LEN	80
> +
> +struct xmgmt_main {
> +	struct platform_device *pdev;
> +	struct axlf *firmware_blp;
> +	struct axlf *firmware_plp;
> +	struct axlf *firmware_ulp;
> +	u32 flags;
ok
> +	struct fpga_manager *fmgr;
> +	struct mutex lock; /* busy lock */
ok
> +
do not need this nl
> +	uuid_t *blp_interface_uuids;
> +	u32 blp_interface_uuid_num;
ok
> +};
> +
> +/*
> + * VBNV stands for Vendor, BoardID, Name, Version. It is a string
> + * which describes board and shell.
> + *
> + * Caller is responsible for freeing the returned string.
ok
> + */
> +char *xmgmt_get_vbnv(struct platform_device *pdev)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	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 platform_device *pdev, char *uuidstr, size_t len)
> +{
> +	struct xrt_devctl_rw devctl_arg = { 0 };
> +	struct platform_device *devctl_leaf;
> +	char uuid_buf[UUID_SIZE];
> +	uuid_t uuid;
> +	int err;
> +
> +	devctl_leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
> +	if (!devctl_leaf) {
> +		xrt_err(pdev, "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(pdev, devctl_leaf);
> +	if (err) {
> +		xrt_err(pdev, "can not get uuid: %d", err);
> +		return err;
> +	}
> +	import_uuid(&uuid, uuid_buf);
ok
> +	xrt_md_trans_uuid2str(&uuid, uuidstr);
> +
> +	return 0;
> +}
> +
> +int xmgmt_hot_reset(struct platform_device *pdev)
> +{
> +	int ret = xleaf_broadcast_event(pdev, XRT_EVENT_PRE_HOT_RESET, false);
> +
> +	if (ret) {
> +		xrt_err(pdev, "offline failed, hot reset is canceled");
> +		return ret;
> +	}
> +
> +	xleaf_hot_reset(pdev);
> +	xleaf_broadcast_event(pdev, 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 platform_device *pdev = to_platform_device(dev);
> +
> +	xmgmt_hot_reset(pdev);
> +	return count;
> +}
> +static DEVICE_ATTR_WO(reset);
> +
> +static ssize_t VBNV_show(struct device *dev, struct device_attribute *da, char *buf)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	ssize_t ret;
> +	char *vbnv;
> +
> +	vbnv = xmgmt_get_vbnv(pdev);
> +	if (!vbnv)
> +		return -EINVAL;
ok
> +	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 platform_device *pdev = to_platform_device(dev);
> +	char uuid[XMGMT_UUID_STR_LEN];
ok
> +	ssize_t ret;
> +
> +	/* Getting UUID pointed to by VSEC, should be the same as logic UUID of BLP. */
> +	ret = get_dev_uuid(pdev, 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 platform_device *pdev = to_platform_device(dev);
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	ssize_t ret = 0;
> +	u32 i;
> +
> +	for (i = 0; i < xmm->blp_interface_uuid_num; i++) {
> +		char uuidstr[XMGMT_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 *xmgmt_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 xmgmt_main_attrgroup = {
> +	.attrs = xmgmt_main_attrs,
> +};
> +
ok,  removed ulp_image_write()
> +static int load_firmware_from_disk(struct platform_device *pdev, struct axlf **fw_buf, size_t *len)
> +{
> +	char uuid[XMGMT_UUID_STR_LEN];
> +	const struct firmware *fw;
> +	char fw_name[256];
> +	int err = 0;
> +
> +	*len = 0;
ok
> +	err = get_dev_uuid(pdev, uuid, sizeof(uuid));
> +	if (err)
> +		return err;
> +
> +	snprintf(fw_name, sizeof(fw_name), "xilinx/%s/partition.xsabin", uuid);
> +	xrt_info(pdev, "try loading fw: %s", fw_name);
> +
> +	err = request_firmware(&fw, fw_name, DEV(pdev));
> +	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 *xmgmt_get_axlf_firmware(struct xmgmt_main *xmm, enum provider_kind kind)
> +{
> +	switch (kind) {
> +	case XMGMT_BLP:
> +		return xmm->firmware_blp;
> +	case XMGMT_PLP:
> +		return xmm->firmware_plp;
> +	case XMGMT_ULP:
> +		return xmm->firmware_ulp;
> +	default:
> +		xrt_err(xmm->pdev, "unknown axlf kind: %d", kind);
> +		return NULL;
> +	}
> +}
> +
> +/* The caller needs to free the returned dtb buffer */
ok
> +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	const struct axlf *provider;
> +	char *dtb = NULL;
> +	int rc;
> +
> +	provider = xmgmt_get_axlf_firmware(xmm, kind);
> +	if (!provider)
> +		return dtb;
> +
> +	rc = xrt_xclbin_get_metadata(DEV(pdev), provider, &dtb);
> +	if (rc)
> +		xrt_err(pdev, "failed to find dtb: %d", rc);
> +	return dtb;
> +}
> +
> +/* The caller needs to free the returned uuid buffer */
ok
> +static const char *get_uuid_from_firmware(struct platform_device *pdev, const struct axlf *xclbin)
> +{
> +	const void *uuiddup = NULL;
> +	const void *uuid = NULL;
> +	void *dtb = NULL;
> +	int rc;
> +
> +	rc = xrt_xclbin_get_section(DEV(pdev), xclbin, PARTITION_METADATA, &dtb, NULL);
> +	if (rc)
> +		return NULL;
> +
> +	rc = xrt_md_get_prop(DEV(pdev), 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 platform_device *pdev,
> +			      const struct axlf *xclbin, size_t fw_len)
> +{
> +	const char *fw_buf = (const char *)xclbin;
> +	size_t axlflen = xclbin->header.length;
> +	char dev_uuid[XMGMT_UUID_STR_LEN];
> +	const char *fw_uuid;
> +	int err;
> +
> +	err = get_dev_uuid(pdev, dev_uuid, sizeof(dev_uuid));
> +	if (err)
> +		return false;
> +
> +	if (memcmp(fw_buf, XCLBIN_VERSION2, sizeof(XCLBIN_VERSION2)) != 0) {
> +		xrt_err(pdev, "unknown fw format");
> +		return false;
> +	}
> +
> +	if (axlflen > fw_len) {
> +		xrt_err(pdev, "truncated fw, length: %zu, expect: %zu", fw_len, axlflen);
> +		return false;
> +	}
> +
> +	if (xclbin->header.version_major != XMGMT_SUPP_XCLBIN_MAJOR) {
> +		xrt_err(pdev, "firmware is not supported");
> +		return false;
> +	}
> +
> +	fw_uuid = get_uuid_from_firmware(pdev, xclbin);
> +	if (!fw_uuid || strncmp(fw_uuid, dev_uuid, sizeof(dev_uuid)) != 0) {
> +		xrt_err(pdev, "bad fw UUID: %s, expect: %s",
> +			fw_uuid ? fw_uuid : "<none>", dev_uuid);
> +		kfree(fw_uuid);
> +		return false;
> +	}
> +
> +	kfree(fw_uuid);
> +	return true;
> +}
> +
> +int xmgmt_get_provider_uuid(struct platform_device *pdev, enum provider_kind kind, uuid_t *uuid)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	const struct axlf *fwbuf;
> +	const char *fw_uuid;
> +	int rc = -ENOENT;
> +
> +	mutex_lock(&xmm->lock);
> +
> +	fwbuf = xmgmt_get_axlf_firmware(xmm, kind);
> +	if (!fwbuf)
> +		goto done;
> +
> +	fw_uuid = get_uuid_from_firmware(pdev, fwbuf);
> +	if (!fw_uuid)
> +		goto done;
> +
> +	rc = xrt_md_trans_str2uuid(DEV(pdev), fw_uuid, uuid);
> +	kfree(fw_uuid);
> +
> +done:
> +	mutex_unlock(&xmm->lock);
> +	return rc;
> +}
> +
> +static int xmgmt_create_blp(struct xmgmt_main *xmm)
> +{
> +	const struct axlf *provider = xmgmt_get_axlf_firmware(xmm, XMGMT_BLP);
> +	struct platform_device *pdev = xmm->pdev;
> +	int rc = 0;
> +	char *dtb = NULL;
> +
> +	dtb = xmgmt_get_dtb(pdev, XMGMT_BLP);
> +	if (!dtb) {
> +		xrt_err(pdev, "did not get BLP metadata");
> +		return -EINVAL;
ok
> +	}
> +
> +	rc = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, provider, XMGMT_BLP);
> +	if (rc) {
> +		xrt_err(pdev, "failed to process BLP: %d", rc);
> +		goto failed;
> +	}
> +
> +	rc = xleaf_create_group(pdev, dtb);
> +	if (rc < 0)
> +		xrt_err(pdev, "failed to create BLP group: %d", rc);
> +	else
> +		rc = 0;
> +
> +	WARN_ON(xmm->blp_interface_uuids);
> +	rc = xrt_md_get_interface_uuids(&pdev->dev, dtb, 0, NULL);
> +	if (rc > 0) {
> +		xmm->blp_interface_uuid_num = rc;
> +		xmm->blp_interface_uuids = vzalloc(sizeof(uuid_t) * xmm->blp_interface_uuid_num);
blp_interface_uuids should be small, so convert to kzalloc
> +		if (!xmm->blp_interface_uuids) {
ok
> +			rc = -ENOMEM;
> +			goto failed;
> +		}
> +		xrt_md_get_interface_uuids(&pdev->dev, dtb, xmm->blp_interface_uuid_num,
> +					   xmm->blp_interface_uuids);
> +	}
> +
> +failed:
> +	vfree(dtb);
> +	return rc;
> +}
> +
> +static int xmgmt_load_firmware(struct xmgmt_main *xmm)
> +{
> +	struct platform_device *pdev = xmm->pdev;
> +	size_t fwlen;
> +	int rc;
> +
> +	rc = load_firmware_from_disk(pdev, &xmm->firmware_blp, &fwlen);
ok
> +	if (!rc && is_valid_firmware(pdev, xmm->firmware_blp, fwlen))
> +		xmgmt_create_blp(xmm);
> +	else
> +		xrt_err(pdev, "failed to find firmware, giving up: %d", rc);
> +	return rc;
> +}
> +
> +static void xmgmt_main_event_cb(struct platform_device *pdev, void *arg)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	struct xrt_event *evt = (struct xrt_event *)arg;
> +	enum xrt_events e = evt->xe_evt;
> +	struct platform_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 & XMGMT_FLAG_DEVCTL_READY)) {
> +			leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
> +			if (leaf) {
> +				xmm->flags |= XMGMT_FLAG_DEVCTL_READY;
> +				xleaf_put_leaf(pdev, leaf);
> +			}
> +		} else if (id == XRT_SUBDEV_QSPI && !(xmm->flags & XMGMT_FLAG_FLASH_READY)) {
> +			xmm->flags |= XMGMT_FLAG_FLASH_READY;
> +		} else {
> +			break;
> +		}
> +
> +		if (xmm->flags & XMGMT_FLAG_DEVCTL_READY)
> +			xmgmt_load_firmware(xmm);
> +		break;
> +	}
> +	case XRT_EVENT_PRE_REMOVAL:
> +		break;
> +	default:
> +		xrt_dbg(pdev, "ignored event %d", e);
> +		break;
> +	}
> +}
> +
> +static int xmgmt_main_probe(struct platform_device *pdev)
> +{
> +	struct xmgmt_main *xmm;
> +
> +	xrt_info(pdev, "probing...");
> +
> +	xmm = devm_kzalloc(DEV(pdev), sizeof(*xmm), GFP_KERNEL);
> +	if (!xmm)
> +		return -ENOMEM;
> +
> +	xmm->pdev = pdev;
> +	xmm->fmgr = xmgmt_fmgr_probe(pdev);
> +	if (IS_ERR(xmm->fmgr))
> +		return PTR_ERR(xmm->fmgr);
> +
> +	platform_set_drvdata(pdev, xmm);
> +	mutex_init(&xmm->lock);
> +
> +	/* Ready to handle req thru sysfs nodes. */
> +	if (sysfs_create_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup))
> +		xrt_err(pdev, "failed to create sysfs group");
> +	return 0;
> +}
> +
> +static int xmgmt_main_remove(struct platform_device *pdev)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +
> +	/* By now, group driver should prevent any inter-leaf call. */
> +
> +	xrt_info(pdev, "leaving...");
> +
> +	vfree(xmm->blp_interface_uuids);
> +	vfree(xmm->firmware_blp);
> +	vfree(xmm->firmware_plp);
> +	vfree(xmm->firmware_ulp);
> +	xmgmt_region_cleanup_all(pdev);
> +	xmgmt_fmgr_remove(xmm->fmgr);
> +	sysfs_remove_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup);
> +	return 0;
> +}
> +
> +static int
> +xmgmt_mainleaf_call(struct platform_device *pdev, u32 cmd, void *arg)
> +{
> +	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
> +	int ret = 0;
> +
> +	switch (cmd) {
> +	case XRT_XLEAF_EVENT:
> +		xmgmt_main_event_cb(pdev, arg);
> +		break;
> +	case XRT_MGMT_MAIN_GET_AXLF_SECTION: {
> +		struct xrt_mgmt_main_get_axlf_section *get =
> +			(struct xrt_mgmt_main_get_axlf_section *)arg;
> +		const struct axlf *firmware = xmgmt_get_axlf_firmware(xmm, get->xmmigas_axlf_kind);
> +
> +		if (!firmware) {
> +			ret = -ENOENT;
> +		} else {
> +			ret = xrt_xclbin_get_section(DEV(pdev), firmware,
> +						     get->xmmigas_section_kind,
> +						     &get->xmmigas_section,
> +						     &get->xmmigas_section_size);
> +		}
> +		break;
> +	}
> +	case XRT_MGMT_MAIN_GET_VBNV: {
> +		char **vbnv_p = (char **)arg;
> +
> +		*vbnv_p = xmgmt_get_vbnv(pdev);
> +		if (!*vbnv_p)
> +			ret = -EINVAL;
ok
> +		break;
> +	}
> +	default:
> +		xrt_err(pdev, "unknown cmd: %d", cmd);
> +		ret = -EINVAL;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static int xmgmt_main_open(struct inode *inode, struct file *file)
> +{
> +	struct platform_device *pdev = xleaf_devnode_open(inode);
> +
> +	/* Device may have gone already when we get here. */
> +	if (!pdev)
> +		return -ENODEV;
> +
> +	xrt_info(pdev, "opened");
> +	file->private_data = platform_get_drvdata(pdev);
> +	return 0;
> +}
> +
> +static int xmgmt_main_close(struct inode *inode, struct file *file)
> +{
> +	struct xmgmt_main *xmm = file->private_data;
> +
> +	xleaf_devnode_close(inode);
> +
> +	xrt_info(xmm->pdev, "closed");
> +	return 0;
> +}
> +
> +/*
> + * Called for xclbin download xclbin load ioctl.
> + */
> +static int xmgmt_bitstream_axlf_fpga_mgr(struct xmgmt_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 = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, axlf, XMGMT_ULP);
> +	if (ret == 0)
> +		xmm->firmware_ulp = axlf;
> +
> +	return ret;
> +}
> +
> +static int bitstream_axlf_ioctl(struct xmgmt_main *xmm, const void __user *arg)
> +{
> +	struct xmgmt_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))

ok

Tom

> +		return -EINVAL;
> +	if (xclbin_obj.header.version_major != XMGMT_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 = xmgmt_bitstream_axlf_fpga_mgr(xmm, copy_buffer, copy_buffer_size);
> +	if (ret)
> +		vfree(copy_buffer);
> +
> +	return ret;
> +}
> +
> +static long xmgmt_main_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> +{
> +	struct xmgmt_main *xmm = filp->private_data;
> +	long result = 0;
> +
> +	if (_IOC_TYPE(cmd) != XMGMT_IOC_MAGIC)
> +		return -ENOTTY;
> +
> +	mutex_lock(&xmm->lock);
> +
> +	xrt_info(xmm->pdev, "ioctl cmd %d, arg %ld", cmd, arg);
> +	switch (cmd) {
> +	case XMGMT_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_subdev_endpoints xrt_mgmt_main_endpoints[] = {
> +	{
> +		.xse_names = (struct xrt_subdev_ep_names []){
> +			{ .ep_name = XRT_MD_NODE_MGMT_MAIN },
> +			{ NULL },
> +		},
> +		.xse_min_ep = 1,
> +	},
> +	{ 0 },
> +};
> +
> +static struct xrt_subdev_drvdata xmgmt_main_data = {
> +	.xsd_dev_ops = {
> +		.xsd_leaf_call = xmgmt_mainleaf_call,
> +	},
> +	.xsd_file_ops = {
> +		.xsf_ops = {
> +			.owner = THIS_MODULE,
> +			.open = xmgmt_main_open,
> +			.release = xmgmt_main_close,
> +			.unlocked_ioctl = xmgmt_main_ioctl,
> +		},
> +		.xsf_dev_name = "xmgmt",
> +	},
> +};
> +
> +static const struct platform_device_id xmgmt_main_id_table[] = {
> +	{ XMGMT_MAIN, (kernel_ulong_t)&xmgmt_main_data },
> +	{ },
> +};
> +
> +static struct platform_driver xmgmt_main_driver = {
> +	.driver	= {
> +		.name    = XMGMT_MAIN,
> +	},
> +	.probe   = xmgmt_main_probe,
> +	.remove  = xmgmt_main_remove,
> +	.id_table = xmgmt_main_id_table,
> +};
> +
> +int xmgmt_register_leaf(void)
> +{
> +	return xleaf_register_driver(XRT_SUBDEV_MGMT_MAIN,
> +				     &xmgmt_main_driver, xrt_mgmt_main_endpoints);
> +}
> +
> +void xmgmt_unregister_leaf(void)
> +{
> +	xleaf_unregister_driver(XRT_SUBDEV_MGMT_MAIN);
> +}
> diff --git a/drivers/fpga/xrt/mgmt/xmgnt.h b/drivers/fpga/xrt/mgmt/xmgnt.h
> new file mode 100644
> index 000000000000..9d7c11194745
> --- /dev/null
> +++ b/drivers/fpga/xrt/mgmt/xmgnt.h
> @@ -0,0 +1,34 @@
> +/* 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 _XMGMT_XMGNT_H_
> +#define _XMGMT_XMGNT_H_

For consistency, should be shortened to _XMGMNT_H_

> +
> +#include <linux/platform_device.h>
> +#include "xmgmt-main.h"
> +
> +struct fpga_manager;
> +int xmgmt_process_xclbin(struct platform_device *pdev,
> +			 struct fpga_manager *fmgr,
> +			 const struct axlf *xclbin,
> +			 enum provider_kind kind);
> +void xmgmt_region_cleanup_all(struct platform_device *pdev);
> +
> +int xmgmt_hot_reset(struct platform_device *pdev);
> +
> +/* Getting dtb for specified group. Caller should vfree returned dtb .*/
> +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind);
> +char *xmgmt_get_vbnv(struct platform_device *pdev);
> +int xmgmt_get_provider_uuid(struct platform_device *pdev,
> +			    enum provider_kind kind, uuid_t *uuid);
> +
> +int xmgmt_register_leaf(void);
ok
> +void xmgmt_unregister_leaf(void);
> +
> +#endif	/* _XMGMT_XMGNT_H_ */
> diff --git a/include/uapi/linux/xrt/xmgmt-ioctl.h b/include/uapi/linux/xrt/xmgmt-ioctl.h
> new file mode 100644
> index 000000000000..da992e581189
> --- /dev/null
> +++ b/include/uapi/linux/xrt/xmgmt-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 *xclmgmt* driver are defined in file, *mgmt-ioctl.h*.
> + * Core functionality provided by *xmgmt* driver is described in the following table:
> + *
> + * =========== ============================== ==================================
> + * Functionality           ioctl request code           data format
> + * =========== ============================== ==================================
> + * 1 FPGA image download   XMGMT_IOCICAPDOWNLOAD_AXLF xmgmt_ioc_bitstream_axlf
> + * =========== ============================== ==================================
> + */
> +
> +#ifndef _XMGMT_IOCTL_H_
> +#define _XMGMT_IOCTL_H_
> +
> +#include <linux/ioctl.h>
> +
> +#define XMGMT_IOC_MAGIC	'X'
> +#define XMGMT_IOC_ICAP_DOWNLOAD_AXLF 0x6
> +
> +/**
> + * struct xmgmt_ioc_bitstream_axlf - load xclbin (AXLF) device image
> + * used with XMGMT_IOCICAPDOWNLOAD_AXLF ioctl
> + *
> + * @xclbin:	Pointer to user's xclbin structure in memory
> + */
> +struct xmgmt_ioc_bitstream_axlf {
> +	struct axlf *xclbin;
> +};
> +
> +#define XMGMT_IOCICAPDOWNLOAD_AXLF				\
> +	_IOW(XMGMT_IOC_MAGIC, XMGMT_IOC_ICAP_DOWNLOAD_AXLF, struct xmgmt_ioc_bitstream_axlf)
> +
> +/*
> + * The following definitions are for binary compatibility with classic XRT management driver
> + */
> +#define XCLMGMT_IOCICAPDOWNLOAD_AXLF XMGMT_IOCICAPDOWNLOAD_AXLF
> +#define xclmgmt_ioc_bitstream_axlf xmgmt_ioc_bitstream_axlf
> +
> +#endif
Lizhi Hou April 7, 2021, 10:37 p.m. UTC | #2
Hi Tom,


On 04/01/2021 07:07 AM, Tom Rix wrote:
>
> On 3/23/21 10:29 PM, Lizhi Hou wrote:
>> platform 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/xmgmt-main.h |  34 ++
>>   drivers/fpga/xrt/mgmt/main.c          | 670 ++++++++++++++++++++++++++
>>   drivers/fpga/xrt/mgmt/xmgnt.h         |  34 ++
>>   include/uapi/linux/xrt/xmgmt-ioctl.h  |  46 ++
>>   4 files changed, 784 insertions(+)
>>   create mode 100644 drivers/fpga/xrt/include/xmgmt-main.h
>>   create mode 100644 drivers/fpga/xrt/mgmt/main.c
> 'main' is generic, how about xmgnt-main ?
Sure. Will change to xmgnt-main
>>   create mode 100644 drivers/fpga/xrt/mgmt/xmgnt.h
>>   create mode 100644 include/uapi/linux/xrt/xmgmt-ioctl.h
>>
>> diff --git a/drivers/fpga/xrt/include/xmgmt-main.h b/drivers/fpga/xrt/include/xmgmt-main.h
>> new file mode 100644
>> index 000000000000..dce9f0d1a0dc
>> --- /dev/null
>> +++ b/drivers/fpga/xrt/include/xmgmt-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 _XMGMT_MAIN_H_
>> +#define _XMGMT_MAIN_H_
>> +
>> +#include <linux/xrt/xclbin.h>
>> +#include "xleaf.h"
>> +
>> +enum xrt_mgmt_main_leaf_cmd {
>> +     XRT_MGMT_MAIN_GET_AXLF_SECTION = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */
>> +     XRT_MGMT_MAIN_GET_VBNV,
>> +};
>> +
>> +/* There are three kind of partitions. Each of them is programmed independently. */
>> +enum provider_kind {
>> +     XMGMT_BLP, /* Base Logic Partition */
>> +     XMGMT_PLP, /* Provider Logic Partition */
>> +     XMGMT_ULP, /* User Logic Partition */
> ok
>> +};
>> +
>> +struct xrt_mgmt_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       /* _XMGMT_MAIN_H_ */
>> diff --git a/drivers/fpga/xrt/mgmt/main.c b/drivers/fpga/xrt/mgmt/main.c
>> new file mode 100644
>> index 000000000000..f3b46e1fd78b
>> --- /dev/null
>> +++ b/drivers/fpga/xrt/mgmt/main.c
>> @@ -0,0 +1,670 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Xilinx Alveo FPGA MGMT 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 "xclbin-helper.h"
>> +#include "metadata.h"
>> +#include "xleaf.h"
>> +#include <linux/xrt/xmgmt-ioctl.h>
>> +#include "xleaf/devctl.h"
>> +#include "xmgmt-main.h"
>> +#include "fmgr.h"
>> +#include "xleaf/icap.h"
>> +#include "xleaf/axigate.h"
>> +#include "xmgnt.h"
>> +
>> +#define XMGMT_MAIN "xmgmt_main"
>> +#define XMGMT_SUPP_XCLBIN_MAJOR 2
>> +
>> +#define XMGMT_FLAG_FLASH_READY       1
>> +#define XMGMT_FLAG_DEVCTL_READY      2
>> +
>> +#define XMGMT_UUID_STR_LEN   80
>> +
>> +struct xmgmt_main {
>> +     struct platform_device *pdev;
>> +     struct axlf *firmware_blp;
>> +     struct axlf *firmware_plp;
>> +     struct axlf *firmware_ulp;
>> +     u32 flags;
> ok
>> +     struct fpga_manager *fmgr;
>> +     struct mutex lock; /* busy lock */
> ok
>> +
> do not need this nl
Will remove.
>> +     uuid_t *blp_interface_uuids;
>> +     u32 blp_interface_uuid_num;
> ok
>> +};
>> +
>> +/*
>> + * VBNV stands for Vendor, BoardID, Name, Version. It is a string
>> + * which describes board and shell.
>> + *
>> + * Caller is responsible for freeing the returned string.
> ok
>> + */
>> +char *xmgmt_get_vbnv(struct platform_device *pdev)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     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 platform_device *pdev, char *uuidstr, size_t len)
>> +{
>> +     struct xrt_devctl_rw devctl_arg = { 0 };
>> +     struct platform_device *devctl_leaf;
>> +     char uuid_buf[UUID_SIZE];
>> +     uuid_t uuid;
>> +     int err;
>> +
>> +     devctl_leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
>> +     if (!devctl_leaf) {
>> +             xrt_err(pdev, "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(pdev, devctl_leaf);
>> +     if (err) {
>> +             xrt_err(pdev, "can not get uuid: %d", err);
>> +             return err;
>> +     }
>> +     import_uuid(&uuid, uuid_buf);
> ok
>> +     xrt_md_trans_uuid2str(&uuid, uuidstr);
>> +
>> +     return 0;
>> +}
>> +
>> +int xmgmt_hot_reset(struct platform_device *pdev)
>> +{
>> +     int ret = xleaf_broadcast_event(pdev, XRT_EVENT_PRE_HOT_RESET, false);
>> +
>> +     if (ret) {
>> +             xrt_err(pdev, "offline failed, hot reset is canceled");
>> +             return ret;
>> +     }
>> +
>> +     xleaf_hot_reset(pdev);
>> +     xleaf_broadcast_event(pdev, 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 platform_device *pdev = to_platform_device(dev);
>> +
>> +     xmgmt_hot_reset(pdev);
>> +     return count;
>> +}
>> +static DEVICE_ATTR_WO(reset);
>> +
>> +static ssize_t VBNV_show(struct device *dev, struct device_attribute *da, char *buf)
>> +{
>> +     struct platform_device *pdev = to_platform_device(dev);
>> +     ssize_t ret;
>> +     char *vbnv;
>> +
>> +     vbnv = xmgmt_get_vbnv(pdev);
>> +     if (!vbnv)
>> +             return -EINVAL;
> ok
>> +     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 platform_device *pdev = to_platform_device(dev);
>> +     char uuid[XMGMT_UUID_STR_LEN];
> ok
>> +     ssize_t ret;
>> +
>> +     /* Getting UUID pointed to by VSEC, should be the same as logic UUID of BLP. */
>> +     ret = get_dev_uuid(pdev, 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 platform_device *pdev = to_platform_device(dev);
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     ssize_t ret = 0;
>> +     u32 i;
>> +
>> +     for (i = 0; i < xmm->blp_interface_uuid_num; i++) {
>> +             char uuidstr[XMGMT_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 *xmgmt_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 xmgmt_main_attrgroup = {
>> +     .attrs = xmgmt_main_attrs,
>> +};
>> +
> ok,  removed ulp_image_write()
>> +static int load_firmware_from_disk(struct platform_device *pdev, struct axlf **fw_buf, size_t *len)
>> +{
>> +     char uuid[XMGMT_UUID_STR_LEN];
>> +     const struct firmware *fw;
>> +     char fw_name[256];
>> +     int err = 0;
>> +
>> +     *len = 0;
> ok
>> +     err = get_dev_uuid(pdev, uuid, sizeof(uuid));
>> +     if (err)
>> +             return err;
>> +
>> +     snprintf(fw_name, sizeof(fw_name), "xilinx/%s/partition.xsabin", uuid);
>> +     xrt_info(pdev, "try loading fw: %s", fw_name);
>> +
>> +     err = request_firmware(&fw, fw_name, DEV(pdev));
>> +     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 *xmgmt_get_axlf_firmware(struct xmgmt_main *xmm, enum provider_kind kind)
>> +{
>> +     switch (kind) {
>> +     case XMGMT_BLP:
>> +             return xmm->firmware_blp;
>> +     case XMGMT_PLP:
>> +             return xmm->firmware_plp;
>> +     case XMGMT_ULP:
>> +             return xmm->firmware_ulp;
>> +     default:
>> +             xrt_err(xmm->pdev, "unknown axlf kind: %d", kind);
>> +             return NULL;
>> +     }
>> +}
>> +
>> +/* The caller needs to free the returned dtb buffer */
> ok
>> +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     const struct axlf *provider;
>> +     char *dtb = NULL;
>> +     int rc;
>> +
>> +     provider = xmgmt_get_axlf_firmware(xmm, kind);
>> +     if (!provider)
>> +             return dtb;
>> +
>> +     rc = xrt_xclbin_get_metadata(DEV(pdev), provider, &dtb);
>> +     if (rc)
>> +             xrt_err(pdev, "failed to find dtb: %d", rc);
>> +     return dtb;
>> +}
>> +
>> +/* The caller needs to free the returned uuid buffer */
> ok
>> +static const char *get_uuid_from_firmware(struct platform_device *pdev, const struct axlf *xclbin)
>> +{
>> +     const void *uuiddup = NULL;
>> +     const void *uuid = NULL;
>> +     void *dtb = NULL;
>> +     int rc;
>> +
>> +     rc = xrt_xclbin_get_section(DEV(pdev), xclbin, PARTITION_METADATA, &dtb, NULL);
>> +     if (rc)
>> +             return NULL;
>> +
>> +     rc = xrt_md_get_prop(DEV(pdev), 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 platform_device *pdev,
>> +                           const struct axlf *xclbin, size_t fw_len)
>> +{
>> +     const char *fw_buf = (const char *)xclbin;
>> +     size_t axlflen = xclbin->header.length;
>> +     char dev_uuid[XMGMT_UUID_STR_LEN];
>> +     const char *fw_uuid;
>> +     int err;
>> +
>> +     err = get_dev_uuid(pdev, dev_uuid, sizeof(dev_uuid));
>> +     if (err)
>> +             return false;
>> +
>> +     if (memcmp(fw_buf, XCLBIN_VERSION2, sizeof(XCLBIN_VERSION2)) != 0) {
>> +             xrt_err(pdev, "unknown fw format");
>> +             return false;
>> +     }
>> +
>> +     if (axlflen > fw_len) {
>> +             xrt_err(pdev, "truncated fw, length: %zu, expect: %zu", fw_len, axlflen);
>> +             return false;
>> +     }
>> +
>> +     if (xclbin->header.version_major != XMGMT_SUPP_XCLBIN_MAJOR) {
>> +             xrt_err(pdev, "firmware is not supported");
>> +             return false;
>> +     }
>> +
>> +     fw_uuid = get_uuid_from_firmware(pdev, xclbin);
>> +     if (!fw_uuid || strncmp(fw_uuid, dev_uuid, sizeof(dev_uuid)) != 0) {
>> +             xrt_err(pdev, "bad fw UUID: %s, expect: %s",
>> +                     fw_uuid ? fw_uuid : "<none>", dev_uuid);
>> +             kfree(fw_uuid);
>> +             return false;
>> +     }
>> +
>> +     kfree(fw_uuid);
>> +     return true;
>> +}
>> +
>> +int xmgmt_get_provider_uuid(struct platform_device *pdev, enum provider_kind kind, uuid_t *uuid)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     const struct axlf *fwbuf;
>> +     const char *fw_uuid;
>> +     int rc = -ENOENT;
>> +
>> +     mutex_lock(&xmm->lock);
>> +
>> +     fwbuf = xmgmt_get_axlf_firmware(xmm, kind);
>> +     if (!fwbuf)
>> +             goto done;
>> +
>> +     fw_uuid = get_uuid_from_firmware(pdev, fwbuf);
>> +     if (!fw_uuid)
>> +             goto done;
>> +
>> +     rc = xrt_md_trans_str2uuid(DEV(pdev), fw_uuid, uuid);
>> +     kfree(fw_uuid);
>> +
>> +done:
>> +     mutex_unlock(&xmm->lock);
>> +     return rc;
>> +}
>> +
>> +static int xmgmt_create_blp(struct xmgmt_main *xmm)
>> +{
>> +     const struct axlf *provider = xmgmt_get_axlf_firmware(xmm, XMGMT_BLP);
>> +     struct platform_device *pdev = xmm->pdev;
>> +     int rc = 0;
>> +     char *dtb = NULL;
>> +
>> +     dtb = xmgmt_get_dtb(pdev, XMGMT_BLP);
>> +     if (!dtb) {
>> +             xrt_err(pdev, "did not get BLP metadata");
>> +             return -EINVAL;
> ok
>> +     }
>> +
>> +     rc = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, provider, XMGMT_BLP);
>> +     if (rc) {
>> +             xrt_err(pdev, "failed to process BLP: %d", rc);
>> +             goto failed;
>> +     }
>> +
>> +     rc = xleaf_create_group(pdev, dtb);
>> +     if (rc < 0)
>> +             xrt_err(pdev, "failed to create BLP group: %d", rc);
>> +     else
>> +             rc = 0;
>> +
>> +     WARN_ON(xmm->blp_interface_uuids);
>> +     rc = xrt_md_get_interface_uuids(&pdev->dev, dtb, 0, NULL);
>> +     if (rc > 0) {
>> +             xmm->blp_interface_uuid_num = rc;
>> +             xmm->blp_interface_uuids = vzalloc(sizeof(uuid_t) * xmm->blp_interface_uuid_num);
> blp_interface_uuids should be small, so convert to kzalloc
Will convert to kcalloc.

Thanks,
Lizhi
>> +             if (!xmm->blp_interface_uuids) {
> ok
>> +                     rc = -ENOMEM;
>> +                     goto failed;
>> +             }
>> +             xrt_md_get_interface_uuids(&pdev->dev, dtb, xmm->blp_interface_uuid_num,
>> +                                        xmm->blp_interface_uuids);
>> +     }
>> +
>> +failed:
>> +     vfree(dtb);
>> +     return rc;
>> +}
>> +
>> +static int xmgmt_load_firmware(struct xmgmt_main *xmm)
>> +{
>> +     struct platform_device *pdev = xmm->pdev;
>> +     size_t fwlen;
>> +     int rc;
>> +
>> +     rc = load_firmware_from_disk(pdev, &xmm->firmware_blp, &fwlen);
> ok
>> +     if (!rc && is_valid_firmware(pdev, xmm->firmware_blp, fwlen))
>> +             xmgmt_create_blp(xmm);
>> +     else
>> +             xrt_err(pdev, "failed to find firmware, giving up: %d", rc);
>> +     return rc;
>> +}
>> +
>> +static void xmgmt_main_event_cb(struct platform_device *pdev, void *arg)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     struct xrt_event *evt = (struct xrt_event *)arg;
>> +     enum xrt_events e = evt->xe_evt;
>> +     struct platform_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 & XMGMT_FLAG_DEVCTL_READY)) {
>> +                     leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
>> +                     if (leaf) {
>> +                             xmm->flags |= XMGMT_FLAG_DEVCTL_READY;
>> +                             xleaf_put_leaf(pdev, leaf);
>> +                     }
>> +             } else if (id == XRT_SUBDEV_QSPI && !(xmm->flags & XMGMT_FLAG_FLASH_READY)) {
>> +                     xmm->flags |= XMGMT_FLAG_FLASH_READY;
>> +             } else {
>> +                     break;
>> +             }
>> +
>> +             if (xmm->flags & XMGMT_FLAG_DEVCTL_READY)
>> +                     xmgmt_load_firmware(xmm);
>> +             break;
>> +     }
>> +     case XRT_EVENT_PRE_REMOVAL:
>> +             break;
>> +     default:
>> +             xrt_dbg(pdev, "ignored event %d", e);
>> +             break;
>> +     }
>> +}
>> +
>> +static int xmgmt_main_probe(struct platform_device *pdev)
>> +{
>> +     struct xmgmt_main *xmm;
>> +
>> +     xrt_info(pdev, "probing...");
>> +
>> +     xmm = devm_kzalloc(DEV(pdev), sizeof(*xmm), GFP_KERNEL);
>> +     if (!xmm)
>> +             return -ENOMEM;
>> +
>> +     xmm->pdev = pdev;
>> +     xmm->fmgr = xmgmt_fmgr_probe(pdev);
>> +     if (IS_ERR(xmm->fmgr))
>> +             return PTR_ERR(xmm->fmgr);
>> +
>> +     platform_set_drvdata(pdev, xmm);
>> +     mutex_init(&xmm->lock);
>> +
>> +     /* Ready to handle req thru sysfs nodes. */
>> +     if (sysfs_create_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup))
>> +             xrt_err(pdev, "failed to create sysfs group");
>> +     return 0;
>> +}
>> +
>> +static int xmgmt_main_remove(struct platform_device *pdev)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +
>> +     /* By now, group driver should prevent any inter-leaf call. */
>> +
>> +     xrt_info(pdev, "leaving...");
>> +
>> +     vfree(xmm->blp_interface_uuids);
>> +     vfree(xmm->firmware_blp);
>> +     vfree(xmm->firmware_plp);
>> +     vfree(xmm->firmware_ulp);
>> +     xmgmt_region_cleanup_all(pdev);
>> +     xmgmt_fmgr_remove(xmm->fmgr);
>> +     sysfs_remove_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup);
>> +     return 0;
>> +}
>> +
>> +static int
>> +xmgmt_mainleaf_call(struct platform_device *pdev, u32 cmd, void *arg)
>> +{
>> +     struct xmgmt_main *xmm = platform_get_drvdata(pdev);
>> +     int ret = 0;
>> +
>> +     switch (cmd) {
>> +     case XRT_XLEAF_EVENT:
>> +             xmgmt_main_event_cb(pdev, arg);
>> +             break;
>> +     case XRT_MGMT_MAIN_GET_AXLF_SECTION: {
>> +             struct xrt_mgmt_main_get_axlf_section *get =
>> +                     (struct xrt_mgmt_main_get_axlf_section *)arg;
>> +             const struct axlf *firmware = xmgmt_get_axlf_firmware(xmm, get->xmmigas_axlf_kind);
>> +
>> +             if (!firmware) {
>> +                     ret = -ENOENT;
>> +             } else {
>> +                     ret = xrt_xclbin_get_section(DEV(pdev), firmware,
>> +                                                  get->xmmigas_section_kind,
>> +                                                  &get->xmmigas_section,
>> +                                                  &get->xmmigas_section_size);
>> +             }
>> +             break;
>> +     }
>> +     case XRT_MGMT_MAIN_GET_VBNV: {
>> +             char **vbnv_p = (char **)arg;
>> +
>> +             *vbnv_p = xmgmt_get_vbnv(pdev);
>> +             if (!*vbnv_p)
>> +                     ret = -EINVAL;
> ok
>> +             break;
>> +     }
>> +     default:
>> +             xrt_err(pdev, "unknown cmd: %d", cmd);
>> +             ret = -EINVAL;
>> +             break;
>> +     }
>> +     return ret;
>> +}
>> +
>> +static int xmgmt_main_open(struct inode *inode, struct file *file)
>> +{
>> +     struct platform_device *pdev = xleaf_devnode_open(inode);
>> +
>> +     /* Device may have gone already when we get here. */
>> +     if (!pdev)
>> +             return -ENODEV;
>> +
>> +     xrt_info(pdev, "opened");
>> +     file->private_data = platform_get_drvdata(pdev);
>> +     return 0;
>> +}
>> +
>> +static int xmgmt_main_close(struct inode *inode, struct file *file)
>> +{
>> +     struct xmgmt_main *xmm = file->private_data;
>> +
>> +     xleaf_devnode_close(inode);
>> +
>> +     xrt_info(xmm->pdev, "closed");
>> +     return 0;
>> +}
>> +
>> +/*
>> + * Called for xclbin download xclbin load ioctl.
>> + */
>> +static int xmgmt_bitstream_axlf_fpga_mgr(struct xmgmt_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 = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, axlf, XMGMT_ULP);
>> +     if (ret == 0)
>> +             xmm->firmware_ulp = axlf;
>> +
>> +     return ret;
>> +}
>> +
>> +static int bitstream_axlf_ioctl(struct xmgmt_main *xmm, const void __user *arg)
>> +{
>> +     struct xmgmt_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))
> ok
>
> Tom
>
>> +             return -EINVAL;
>> +     if (xclbin_obj.header.version_major != XMGMT_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 = xmgmt_bitstream_axlf_fpga_mgr(xmm, copy_buffer, copy_buffer_size);
>> +     if (ret)
>> +             vfree(copy_buffer);
>> +
>> +     return ret;
>> +}
>> +
>> +static long xmgmt_main_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>> +{
>> +     struct xmgmt_main *xmm = filp->private_data;
>> +     long result = 0;
>> +
>> +     if (_IOC_TYPE(cmd) != XMGMT_IOC_MAGIC)
>> +             return -ENOTTY;
>> +
>> +     mutex_lock(&xmm->lock);
>> +
>> +     xrt_info(xmm->pdev, "ioctl cmd %d, arg %ld", cmd, arg);
>> +     switch (cmd) {
>> +     case XMGMT_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_subdev_endpoints xrt_mgmt_main_endpoints[] = {
>> +     {
>> +             .xse_names = (struct xrt_subdev_ep_names []){
>> +                     { .ep_name = XRT_MD_NODE_MGMT_MAIN },
>> +                     { NULL },
>> +             },
>> +             .xse_min_ep = 1,
>> +     },
>> +     { 0 },
>> +};
>> +
>> +static struct xrt_subdev_drvdata xmgmt_main_data = {
>> +     .xsd_dev_ops = {
>> +             .xsd_leaf_call = xmgmt_mainleaf_call,
>> +     },
>> +     .xsd_file_ops = {
>> +             .xsf_ops = {
>> +                     .owner = THIS_MODULE,
>> +                     .open = xmgmt_main_open,
>> +                     .release = xmgmt_main_close,
>> +                     .unlocked_ioctl = xmgmt_main_ioctl,
>> +             },
>> +             .xsf_dev_name = "xmgmt",
>> +     },
>> +};
>> +
>> +static const struct platform_device_id xmgmt_main_id_table[] = {
>> +     { XMGMT_MAIN, (kernel_ulong_t)&xmgmt_main_data },
>> +     { },
>> +};
>> +
>> +static struct platform_driver xmgmt_main_driver = {
>> +     .driver = {
>> +             .name    = XMGMT_MAIN,
>> +     },
>> +     .probe   = xmgmt_main_probe,
>> +     .remove  = xmgmt_main_remove,
>> +     .id_table = xmgmt_main_id_table,
>> +};
>> +
>> +int xmgmt_register_leaf(void)
>> +{
>> +     return xleaf_register_driver(XRT_SUBDEV_MGMT_MAIN,
>> +                                  &xmgmt_main_driver, xrt_mgmt_main_endpoints);
>> +}
>> +
>> +void xmgmt_unregister_leaf(void)
>> +{
>> +     xleaf_unregister_driver(XRT_SUBDEV_MGMT_MAIN);
>> +}
>> diff --git a/drivers/fpga/xrt/mgmt/xmgnt.h b/drivers/fpga/xrt/mgmt/xmgnt.h
>> new file mode 100644
>> index 000000000000..9d7c11194745
>> --- /dev/null
>> +++ b/drivers/fpga/xrt/mgmt/xmgnt.h
>> @@ -0,0 +1,34 @@
>> +/* 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 _XMGMT_XMGNT_H_
>> +#define _XMGMT_XMGNT_H_
> For consistency, should be shortened to _XMGMNT_H_
>
>> +
>> +#include <linux/platform_device.h>
>> +#include "xmgmt-main.h"
>> +
>> +struct fpga_manager;
>> +int xmgmt_process_xclbin(struct platform_device *pdev,
>> +                      struct fpga_manager *fmgr,
>> +                      const struct axlf *xclbin,
>> +                      enum provider_kind kind);
>> +void xmgmt_region_cleanup_all(struct platform_device *pdev);
>> +
>> +int xmgmt_hot_reset(struct platform_device *pdev);
>> +
>> +/* Getting dtb for specified group. Caller should vfree returned dtb .*/
>> +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind);
>> +char *xmgmt_get_vbnv(struct platform_device *pdev);
>> +int xmgmt_get_provider_uuid(struct platform_device *pdev,
>> +                         enum provider_kind kind, uuid_t *uuid);
>> +
>> +int xmgmt_register_leaf(void);
> ok
>> +void xmgmt_unregister_leaf(void);
>> +
>> +#endif       /* _XMGMT_XMGNT_H_ */
>> diff --git a/include/uapi/linux/xrt/xmgmt-ioctl.h b/include/uapi/linux/xrt/xmgmt-ioctl.h
>> new file mode 100644
>> index 000000000000..da992e581189
>> --- /dev/null
>> +++ b/include/uapi/linux/xrt/xmgmt-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 *xclmgmt* driver are defined in file, *mgmt-ioctl.h*.
>> + * Core functionality provided by *xmgmt* driver is described in the following table:
>> + *
>> + * =========== ============================== ==================================
>> + * Functionality           ioctl request code           data format
>> + * =========== ============================== ==================================
>> + * 1 FPGA image download   XMGMT_IOCICAPDOWNLOAD_AXLF xmgmt_ioc_bitstream_axlf
>> + * =========== ============================== ==================================
>> + */
>> +
>> +#ifndef _XMGMT_IOCTL_H_
>> +#define _XMGMT_IOCTL_H_
>> +
>> +#include <linux/ioctl.h>
>> +
>> +#define XMGMT_IOC_MAGIC      'X'
>> +#define XMGMT_IOC_ICAP_DOWNLOAD_AXLF 0x6
>> +
>> +/**
>> + * struct xmgmt_ioc_bitstream_axlf - load xclbin (AXLF) device image
>> + * used with XMGMT_IOCICAPDOWNLOAD_AXLF ioctl
>> + *
>> + * @xclbin:  Pointer to user's xclbin structure in memory
>> + */
>> +struct xmgmt_ioc_bitstream_axlf {
>> +     struct axlf *xclbin;
>> +};
>> +
>> +#define XMGMT_IOCICAPDOWNLOAD_AXLF                           \
>> +     _IOW(XMGMT_IOC_MAGIC, XMGMT_IOC_ICAP_DOWNLOAD_AXLF, struct xmgmt_ioc_bitstream_axlf)
>> +
>> +/*
>> + * The following definitions are for binary compatibility with classic XRT management driver
>> + */
>> +#define XCLMGMT_IOCICAPDOWNLOAD_AXLF XMGMT_IOCICAPDOWNLOAD_AXLF
>> +#define xclmgmt_ioc_bitstream_axlf xmgmt_ioc_bitstream_axlf
>> +
>> +#endif
diff mbox series

Patch

diff --git a/drivers/fpga/xrt/include/xmgmt-main.h b/drivers/fpga/xrt/include/xmgmt-main.h
new file mode 100644
index 000000000000..dce9f0d1a0dc
--- /dev/null
+++ b/drivers/fpga/xrt/include/xmgmt-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 _XMGMT_MAIN_H_
+#define _XMGMT_MAIN_H_
+
+#include <linux/xrt/xclbin.h>
+#include "xleaf.h"
+
+enum xrt_mgmt_main_leaf_cmd {
+	XRT_MGMT_MAIN_GET_AXLF_SECTION = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */
+	XRT_MGMT_MAIN_GET_VBNV,
+};
+
+/* There are three kind of partitions. Each of them is programmed independently. */
+enum provider_kind {
+	XMGMT_BLP, /* Base Logic Partition */
+	XMGMT_PLP, /* Provider Logic Partition */
+	XMGMT_ULP, /* User Logic Partition */
+};
+
+struct xrt_mgmt_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	/* _XMGMT_MAIN_H_ */
diff --git a/drivers/fpga/xrt/mgmt/main.c b/drivers/fpga/xrt/mgmt/main.c
new file mode 100644
index 000000000000..f3b46e1fd78b
--- /dev/null
+++ b/drivers/fpga/xrt/mgmt/main.c
@@ -0,0 +1,670 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Alveo FPGA MGMT 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 "xclbin-helper.h"
+#include "metadata.h"
+#include "xleaf.h"
+#include <linux/xrt/xmgmt-ioctl.h>
+#include "xleaf/devctl.h"
+#include "xmgmt-main.h"
+#include "fmgr.h"
+#include "xleaf/icap.h"
+#include "xleaf/axigate.h"
+#include "xmgnt.h"
+
+#define XMGMT_MAIN "xmgmt_main"
+#define XMGMT_SUPP_XCLBIN_MAJOR 2
+
+#define XMGMT_FLAG_FLASH_READY	1
+#define XMGMT_FLAG_DEVCTL_READY	2
+
+#define XMGMT_UUID_STR_LEN	80
+
+struct xmgmt_main {
+	struct platform_device *pdev;
+	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 *xmgmt_get_vbnv(struct platform_device *pdev)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	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 platform_device *pdev, char *uuidstr, size_t len)
+{
+	struct xrt_devctl_rw devctl_arg = { 0 };
+	struct platform_device *devctl_leaf;
+	char uuid_buf[UUID_SIZE];
+	uuid_t uuid;
+	int err;
+
+	devctl_leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
+	if (!devctl_leaf) {
+		xrt_err(pdev, "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(pdev, devctl_leaf);
+	if (err) {
+		xrt_err(pdev, "can not get uuid: %d", err);
+		return err;
+	}
+	import_uuid(&uuid, uuid_buf);
+	xrt_md_trans_uuid2str(&uuid, uuidstr);
+
+	return 0;
+}
+
+int xmgmt_hot_reset(struct platform_device *pdev)
+{
+	int ret = xleaf_broadcast_event(pdev, XRT_EVENT_PRE_HOT_RESET, false);
+
+	if (ret) {
+		xrt_err(pdev, "offline failed, hot reset is canceled");
+		return ret;
+	}
+
+	xleaf_hot_reset(pdev);
+	xleaf_broadcast_event(pdev, 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 platform_device *pdev = to_platform_device(dev);
+
+	xmgmt_hot_reset(pdev);
+	return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static ssize_t VBNV_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	ssize_t ret;
+	char *vbnv;
+
+	vbnv = xmgmt_get_vbnv(pdev);
+	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 platform_device *pdev = to_platform_device(dev);
+	char uuid[XMGMT_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(pdev, 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 platform_device *pdev = to_platform_device(dev);
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	ssize_t ret = 0;
+	u32 i;
+
+	for (i = 0; i < xmm->blp_interface_uuid_num; i++) {
+		char uuidstr[XMGMT_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 *xmgmt_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 xmgmt_main_attrgroup = {
+	.attrs = xmgmt_main_attrs,
+};
+
+static int load_firmware_from_disk(struct platform_device *pdev, struct axlf **fw_buf, size_t *len)
+{
+	char uuid[XMGMT_UUID_STR_LEN];
+	const struct firmware *fw;
+	char fw_name[256];
+	int err = 0;
+
+	*len = 0;
+	err = get_dev_uuid(pdev, uuid, sizeof(uuid));
+	if (err)
+		return err;
+
+	snprintf(fw_name, sizeof(fw_name), "xilinx/%s/partition.xsabin", uuid);
+	xrt_info(pdev, "try loading fw: %s", fw_name);
+
+	err = request_firmware(&fw, fw_name, DEV(pdev));
+	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 *xmgmt_get_axlf_firmware(struct xmgmt_main *xmm, enum provider_kind kind)
+{
+	switch (kind) {
+	case XMGMT_BLP:
+		return xmm->firmware_blp;
+	case XMGMT_PLP:
+		return xmm->firmware_plp;
+	case XMGMT_ULP:
+		return xmm->firmware_ulp;
+	default:
+		xrt_err(xmm->pdev, "unknown axlf kind: %d", kind);
+		return NULL;
+	}
+}
+
+/* The caller needs to free the returned dtb buffer */
+char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	const struct axlf *provider;
+	char *dtb = NULL;
+	int rc;
+
+	provider = xmgmt_get_axlf_firmware(xmm, kind);
+	if (!provider)
+		return dtb;
+
+	rc = xrt_xclbin_get_metadata(DEV(pdev), provider, &dtb);
+	if (rc)
+		xrt_err(pdev, "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 platform_device *pdev, const struct axlf *xclbin)
+{
+	const void *uuiddup = NULL;
+	const void *uuid = NULL;
+	void *dtb = NULL;
+	int rc;
+
+	rc = xrt_xclbin_get_section(DEV(pdev), xclbin, PARTITION_METADATA, &dtb, NULL);
+	if (rc)
+		return NULL;
+
+	rc = xrt_md_get_prop(DEV(pdev), 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 platform_device *pdev,
+			      const struct axlf *xclbin, size_t fw_len)
+{
+	const char *fw_buf = (const char *)xclbin;
+	size_t axlflen = xclbin->header.length;
+	char dev_uuid[XMGMT_UUID_STR_LEN];
+	const char *fw_uuid;
+	int err;
+
+	err = get_dev_uuid(pdev, dev_uuid, sizeof(dev_uuid));
+	if (err)
+		return false;
+
+	if (memcmp(fw_buf, XCLBIN_VERSION2, sizeof(XCLBIN_VERSION2)) != 0) {
+		xrt_err(pdev, "unknown fw format");
+		return false;
+	}
+
+	if (axlflen > fw_len) {
+		xrt_err(pdev, "truncated fw, length: %zu, expect: %zu", fw_len, axlflen);
+		return false;
+	}
+
+	if (xclbin->header.version_major != XMGMT_SUPP_XCLBIN_MAJOR) {
+		xrt_err(pdev, "firmware is not supported");
+		return false;
+	}
+
+	fw_uuid = get_uuid_from_firmware(pdev, xclbin);
+	if (!fw_uuid || strncmp(fw_uuid, dev_uuid, sizeof(dev_uuid)) != 0) {
+		xrt_err(pdev, "bad fw UUID: %s, expect: %s",
+			fw_uuid ? fw_uuid : "<none>", dev_uuid);
+		kfree(fw_uuid);
+		return false;
+	}
+
+	kfree(fw_uuid);
+	return true;
+}
+
+int xmgmt_get_provider_uuid(struct platform_device *pdev, enum provider_kind kind, uuid_t *uuid)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	const struct axlf *fwbuf;
+	const char *fw_uuid;
+	int rc = -ENOENT;
+
+	mutex_lock(&xmm->lock);
+
+	fwbuf = xmgmt_get_axlf_firmware(xmm, kind);
+	if (!fwbuf)
+		goto done;
+
+	fw_uuid = get_uuid_from_firmware(pdev, fwbuf);
+	if (!fw_uuid)
+		goto done;
+
+	rc = xrt_md_trans_str2uuid(DEV(pdev), fw_uuid, uuid);
+	kfree(fw_uuid);
+
+done:
+	mutex_unlock(&xmm->lock);
+	return rc;
+}
+
+static int xmgmt_create_blp(struct xmgmt_main *xmm)
+{
+	const struct axlf *provider = xmgmt_get_axlf_firmware(xmm, XMGMT_BLP);
+	struct platform_device *pdev = xmm->pdev;
+	int rc = 0;
+	char *dtb = NULL;
+
+	dtb = xmgmt_get_dtb(pdev, XMGMT_BLP);
+	if (!dtb) {
+		xrt_err(pdev, "did not get BLP metadata");
+		return -EINVAL;
+	}
+
+	rc = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, provider, XMGMT_BLP);
+	if (rc) {
+		xrt_err(pdev, "failed to process BLP: %d", rc);
+		goto failed;
+	}
+
+	rc = xleaf_create_group(pdev, dtb);
+	if (rc < 0)
+		xrt_err(pdev, "failed to create BLP group: %d", rc);
+	else
+		rc = 0;
+
+	WARN_ON(xmm->blp_interface_uuids);
+	rc = xrt_md_get_interface_uuids(&pdev->dev, dtb, 0, NULL);
+	if (rc > 0) {
+		xmm->blp_interface_uuid_num = rc;
+		xmm->blp_interface_uuids = vzalloc(sizeof(uuid_t) * xmm->blp_interface_uuid_num);
+		if (!xmm->blp_interface_uuids) {
+			rc = -ENOMEM;
+			goto failed;
+		}
+		xrt_md_get_interface_uuids(&pdev->dev, dtb, xmm->blp_interface_uuid_num,
+					   xmm->blp_interface_uuids);
+	}
+
+failed:
+	vfree(dtb);
+	return rc;
+}
+
+static int xmgmt_load_firmware(struct xmgmt_main *xmm)
+{
+	struct platform_device *pdev = xmm->pdev;
+	size_t fwlen;
+	int rc;
+
+	rc = load_firmware_from_disk(pdev, &xmm->firmware_blp, &fwlen);
+	if (!rc && is_valid_firmware(pdev, xmm->firmware_blp, fwlen))
+		xmgmt_create_blp(xmm);
+	else
+		xrt_err(pdev, "failed to find firmware, giving up: %d", rc);
+	return rc;
+}
+
+static void xmgmt_main_event_cb(struct platform_device *pdev, void *arg)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	struct xrt_event *evt = (struct xrt_event *)arg;
+	enum xrt_events e = evt->xe_evt;
+	struct platform_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 & XMGMT_FLAG_DEVCTL_READY)) {
+			leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM);
+			if (leaf) {
+				xmm->flags |= XMGMT_FLAG_DEVCTL_READY;
+				xleaf_put_leaf(pdev, leaf);
+			}
+		} else if (id == XRT_SUBDEV_QSPI && !(xmm->flags & XMGMT_FLAG_FLASH_READY)) {
+			xmm->flags |= XMGMT_FLAG_FLASH_READY;
+		} else {
+			break;
+		}
+
+		if (xmm->flags & XMGMT_FLAG_DEVCTL_READY)
+			xmgmt_load_firmware(xmm);
+		break;
+	}
+	case XRT_EVENT_PRE_REMOVAL:
+		break;
+	default:
+		xrt_dbg(pdev, "ignored event %d", e);
+		break;
+	}
+}
+
+static int xmgmt_main_probe(struct platform_device *pdev)
+{
+	struct xmgmt_main *xmm;
+
+	xrt_info(pdev, "probing...");
+
+	xmm = devm_kzalloc(DEV(pdev), sizeof(*xmm), GFP_KERNEL);
+	if (!xmm)
+		return -ENOMEM;
+
+	xmm->pdev = pdev;
+	xmm->fmgr = xmgmt_fmgr_probe(pdev);
+	if (IS_ERR(xmm->fmgr))
+		return PTR_ERR(xmm->fmgr);
+
+	platform_set_drvdata(pdev, xmm);
+	mutex_init(&xmm->lock);
+
+	/* Ready to handle req thru sysfs nodes. */
+	if (sysfs_create_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup))
+		xrt_err(pdev, "failed to create sysfs group");
+	return 0;
+}
+
+static int xmgmt_main_remove(struct platform_device *pdev)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+
+	/* By now, group driver should prevent any inter-leaf call. */
+
+	xrt_info(pdev, "leaving...");
+
+	vfree(xmm->blp_interface_uuids);
+	vfree(xmm->firmware_blp);
+	vfree(xmm->firmware_plp);
+	vfree(xmm->firmware_ulp);
+	xmgmt_region_cleanup_all(pdev);
+	xmgmt_fmgr_remove(xmm->fmgr);
+	sysfs_remove_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup);
+	return 0;
+}
+
+static int
+xmgmt_mainleaf_call(struct platform_device *pdev, u32 cmd, void *arg)
+{
+	struct xmgmt_main *xmm = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	switch (cmd) {
+	case XRT_XLEAF_EVENT:
+		xmgmt_main_event_cb(pdev, arg);
+		break;
+	case XRT_MGMT_MAIN_GET_AXLF_SECTION: {
+		struct xrt_mgmt_main_get_axlf_section *get =
+			(struct xrt_mgmt_main_get_axlf_section *)arg;
+		const struct axlf *firmware = xmgmt_get_axlf_firmware(xmm, get->xmmigas_axlf_kind);
+
+		if (!firmware) {
+			ret = -ENOENT;
+		} else {
+			ret = xrt_xclbin_get_section(DEV(pdev), firmware,
+						     get->xmmigas_section_kind,
+						     &get->xmmigas_section,
+						     &get->xmmigas_section_size);
+		}
+		break;
+	}
+	case XRT_MGMT_MAIN_GET_VBNV: {
+		char **vbnv_p = (char **)arg;
+
+		*vbnv_p = xmgmt_get_vbnv(pdev);
+		if (!*vbnv_p)
+			ret = -EINVAL;
+		break;
+	}
+	default:
+		xrt_err(pdev, "unknown cmd: %d", cmd);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int xmgmt_main_open(struct inode *inode, struct file *file)
+{
+	struct platform_device *pdev = xleaf_devnode_open(inode);
+
+	/* Device may have gone already when we get here. */
+	if (!pdev)
+		return -ENODEV;
+
+	xrt_info(pdev, "opened");
+	file->private_data = platform_get_drvdata(pdev);
+	return 0;
+}
+
+static int xmgmt_main_close(struct inode *inode, struct file *file)
+{
+	struct xmgmt_main *xmm = file->private_data;
+
+	xleaf_devnode_close(inode);
+
+	xrt_info(xmm->pdev, "closed");
+	return 0;
+}
+
+/*
+ * Called for xclbin download xclbin load ioctl.
+ */
+static int xmgmt_bitstream_axlf_fpga_mgr(struct xmgmt_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 = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, axlf, XMGMT_ULP);
+	if (ret == 0)
+		xmm->firmware_ulp = axlf;
+
+	return ret;
+}
+
+static int bitstream_axlf_ioctl(struct xmgmt_main *xmm, const void __user *arg)
+{
+	struct xmgmt_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 != XMGMT_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 = xmgmt_bitstream_axlf_fpga_mgr(xmm, copy_buffer, copy_buffer_size);
+	if (ret)
+		vfree(copy_buffer);
+
+	return ret;
+}
+
+static long xmgmt_main_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct xmgmt_main *xmm = filp->private_data;
+	long result = 0;
+
+	if (_IOC_TYPE(cmd) != XMGMT_IOC_MAGIC)
+		return -ENOTTY;
+
+	mutex_lock(&xmm->lock);
+
+	xrt_info(xmm->pdev, "ioctl cmd %d, arg %ld", cmd, arg);
+	switch (cmd) {
+	case XMGMT_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_subdev_endpoints xrt_mgmt_main_endpoints[] = {
+	{
+		.xse_names = (struct xrt_subdev_ep_names []){
+			{ .ep_name = XRT_MD_NODE_MGMT_MAIN },
+			{ NULL },
+		},
+		.xse_min_ep = 1,
+	},
+	{ 0 },
+};
+
+static struct xrt_subdev_drvdata xmgmt_main_data = {
+	.xsd_dev_ops = {
+		.xsd_leaf_call = xmgmt_mainleaf_call,
+	},
+	.xsd_file_ops = {
+		.xsf_ops = {
+			.owner = THIS_MODULE,
+			.open = xmgmt_main_open,
+			.release = xmgmt_main_close,
+			.unlocked_ioctl = xmgmt_main_ioctl,
+		},
+		.xsf_dev_name = "xmgmt",
+	},
+};
+
+static const struct platform_device_id xmgmt_main_id_table[] = {
+	{ XMGMT_MAIN, (kernel_ulong_t)&xmgmt_main_data },
+	{ },
+};
+
+static struct platform_driver xmgmt_main_driver = {
+	.driver	= {
+		.name    = XMGMT_MAIN,
+	},
+	.probe   = xmgmt_main_probe,
+	.remove  = xmgmt_main_remove,
+	.id_table = xmgmt_main_id_table,
+};
+
+int xmgmt_register_leaf(void)
+{
+	return xleaf_register_driver(XRT_SUBDEV_MGMT_MAIN,
+				     &xmgmt_main_driver, xrt_mgmt_main_endpoints);
+}
+
+void xmgmt_unregister_leaf(void)
+{
+	xleaf_unregister_driver(XRT_SUBDEV_MGMT_MAIN);
+}
diff --git a/drivers/fpga/xrt/mgmt/xmgnt.h b/drivers/fpga/xrt/mgmt/xmgnt.h
new file mode 100644
index 000000000000..9d7c11194745
--- /dev/null
+++ b/drivers/fpga/xrt/mgmt/xmgnt.h
@@ -0,0 +1,34 @@ 
+/* 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 _XMGMT_XMGNT_H_
+#define _XMGMT_XMGNT_H_
+
+#include <linux/platform_device.h>
+#include "xmgmt-main.h"
+
+struct fpga_manager;
+int xmgmt_process_xclbin(struct platform_device *pdev,
+			 struct fpga_manager *fmgr,
+			 const struct axlf *xclbin,
+			 enum provider_kind kind);
+void xmgmt_region_cleanup_all(struct platform_device *pdev);
+
+int xmgmt_hot_reset(struct platform_device *pdev);
+
+/* Getting dtb for specified group. Caller should vfree returned dtb .*/
+char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind);
+char *xmgmt_get_vbnv(struct platform_device *pdev);
+int xmgmt_get_provider_uuid(struct platform_device *pdev,
+			    enum provider_kind kind, uuid_t *uuid);
+
+int xmgmt_register_leaf(void);
+void xmgmt_unregister_leaf(void);
+
+#endif	/* _XMGMT_XMGNT_H_ */
diff --git a/include/uapi/linux/xrt/xmgmt-ioctl.h b/include/uapi/linux/xrt/xmgmt-ioctl.h
new file mode 100644
index 000000000000..da992e581189
--- /dev/null
+++ b/include/uapi/linux/xrt/xmgmt-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 *xclmgmt* driver are defined in file, *mgmt-ioctl.h*.
+ * Core functionality provided by *xmgmt* driver is described in the following table:
+ *
+ * =========== ============================== ==================================
+ * Functionality           ioctl request code           data format
+ * =========== ============================== ==================================
+ * 1 FPGA image download   XMGMT_IOCICAPDOWNLOAD_AXLF xmgmt_ioc_bitstream_axlf
+ * =========== ============================== ==================================
+ */
+
+#ifndef _XMGMT_IOCTL_H_
+#define _XMGMT_IOCTL_H_
+
+#include <linux/ioctl.h>
+
+#define XMGMT_IOC_MAGIC	'X'
+#define XMGMT_IOC_ICAP_DOWNLOAD_AXLF 0x6
+
+/**
+ * struct xmgmt_ioc_bitstream_axlf - load xclbin (AXLF) device image
+ * used with XMGMT_IOCICAPDOWNLOAD_AXLF ioctl
+ *
+ * @xclbin:	Pointer to user's xclbin structure in memory
+ */
+struct xmgmt_ioc_bitstream_axlf {
+	struct axlf *xclbin;
+};
+
+#define XMGMT_IOCICAPDOWNLOAD_AXLF				\
+	_IOW(XMGMT_IOC_MAGIC, XMGMT_IOC_ICAP_DOWNLOAD_AXLF, struct xmgmt_ioc_bitstream_axlf)
+
+/*
+ * The following definitions are for binary compatibility with classic XRT management driver
+ */
+#define XCLMGMT_IOCICAPDOWNLOAD_AXLF XMGMT_IOCICAPDOWNLOAD_AXLF
+#define xclmgmt_ioc_bitstream_axlf xmgmt_ioc_bitstream_axlf
+
+#endif