From patchwork Wed May 12 01:53:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435844 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1BEA5C43460 for ; Wed, 12 May 2021 01:58:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EF29F61925 for ; Wed, 12 May 2021 01:58:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230124AbhELB71 (ORCPT ); Tue, 11 May 2021 21:59:27 -0400 Received: from mail-dm6nam11on2088.outbound.protection.outlook.com ([40.107.223.88]:60639 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229954AbhELB70 (ORCPT ); Tue, 11 May 2021 21:59:26 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RUz1WvpiuKqMGGn7P7ls3QraHVlI5DvwBBvPHaHQNM5N5rX15FuUkXMR+t0ZzpqIKF3UAyruV+suDUcVQQpKo5dVB6XJAVKHyQPszIfaaxHrak7ObrGoYzacbYJmhFI5K52f5kgg6i7nVFt6+yj2mvWH7wCVNOfe7cU/ikqXaY8WVh7vWm2meP8wWJsItyCKCBuwGhqVBiNDIpKvsGUF5gJF3gMPgxWKnCnzwIg3QdcGBW+Ace/tGU6DA0xKlnFAEcXZcygtrkG1xbbpbXlVRqPkCRSej6BF1aj1YUVflSRfp+pWcXw790YJ1xNPA94PTGQNCp7P9SSgP0V6l8Q/Pg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=EcGZpgHowAkTMHSG/tiGDXIa/bEWyW/fV5vueCk/JOs=; b=gyzrJM80Zd1IcGaOao6AMtlxlXZ1tHFRT62oo0Y6j8e+3kXc4V7S+WpnktnJ1gxVQ9/y4osHvUkO5R6oMYacgwaurt92Gq/t5deFAjVHwnuuCskKMLf/HAam30boHdzyd/O6Gz8tMyw56JeC/VnpiVDbG+B6FQrvwIL/JBzvhL25D1rLZaEE015DxEr6KvKjdM33GT1anzyQokOnt3c3IiEEVe9QCuU94DhQ9Iw3VA9BRgsZlaO3/ZttE88IdQOCI4uc5XLdPfPtGr/gn+BHeLWNbW6iw7AomTxc7SWJe4qRkX9kp85KAdAg8ozWFUpH6nrKisiBqcdASrqYKyvxQg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=EcGZpgHowAkTMHSG/tiGDXIa/bEWyW/fV5vueCk/JOs=; b=jiWQGSTnEjehWvl+JwOKaX2w2+ookv3Bmaa1lSidS+AEPrw5QV4o7a1X9l6f+7/6lkAKY7M5w6VZNwMmc34G315cUYcEMF9IWUzaTFUq0nFSy0MNGPzbYnc5USfJeXp6LWCa1ZeMEqn1AmN9w9v2ncyJsoCYVX5Z6hB5FLnTo80= Received: from BN6PR1401CA0007.namprd14.prod.outlook.com (2603:10b6:405:4b::17) by MN2PR02MB6767.namprd02.prod.outlook.com (2603:10b6:208:1d2::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.26; Wed, 12 May 2021 01:58:17 +0000 Received: from BN1NAM02FT008.eop-nam02.prod.protection.outlook.com (2603:10b6:405:4b:cafe::95) by BN6PR1401CA0007.outlook.office365.com (2603:10b6:405:4b::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 01:58:17 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT008.mail.protection.outlook.com (10.13.2.126) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 01:58:16 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:57:55 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:57:55 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35716 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lge8I-0005OI-TB; Tue, 11 May 2021 18:57:54 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id F0138600128; Tue, 11 May 2021 18:53:44 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 03/20] fpga: xrt: xclbin file helper functions Date: Tue, 11 May 2021 18:53:22 -0700 Message-ID: <20210512015339.5649-4-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 7b47f4a7-3825-4a7d-0928-08d914e968f8 X-MS-TrafficTypeDiagnostic: MN2PR02MB6767: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1824; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: mFZeN5N3ypgDg3MtdL2WwHtqOhusl290UYkp5isM+lYjZDC/nC1YMX6/dZI01RgulSVGtQwvhLPfiRK7a8fzP+b5z2f7Z6PPKBEa1Vz2rSFLNKCdKIUyYEBp9DquvPwpw52zl31Q4JZJ/dn+GEmiyr6Ki35Li6VeALR5rXpQc7+Q9jRvKmopQIxGV96g9CSinqE5r03u3UaK8WSDunCJHiQyVeuNyIKNdZkqM1GX2m3/hK7ozLkVjkGhrd4ediMkM6UN3hcqotPFugL6W8/sRI/YqV7vhQxtYG71b1N6dVMIhlZQsstTo8itkMmXXRCnoVcXdXWOnOBWVAOvA2hoP8Sfdafhku26GYwkQeEu8E41hw5lua/rBwflWYaNpl0ZzfTbS3P9swF8Sjs0RyNuQOq5ZX9DtygILr6vrpyvPB7V0tp2wANAq56kb6Vy3geCu29T/7ziSc3MVxOl77p9TOFIvemDR2t1RFIW6vpaGqQeaIxaFTIOC4DvUIJFQQOq+hDEeMh4TeUsSrmj7laajZF9pRsQuNqe6iQ8ohg0g7hxLvUAXdNsQllcOvyEmjnFXMcLxX/KJuP1veVbrCiFx9OUreIaYqQKHkVb+HZfJC882EzS2XBrpTVHX6yYWJCt+384MOGnx8aWCjTHGSiU5MXLHC79eTQw/5FidinPChE= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch01.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(136003)(39850400004)(376002)(346002)(396003)(46966006)(36840700001)(36860700001)(478600001)(2906002)(70206006)(36756003)(336012)(70586007)(83380400001)(426003)(5660300002)(8676002)(2616005)(6666004)(6916009)(7636003)(356005)(4326008)(44832011)(82310400003)(26005)(1076003)(30864003)(186003)(36906005)(6266002)(47076005)(107886003)(54906003)(82740400003)(42186006)(316002)(8936002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 01:58:16.9117 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7b47f4a7-3825-4a7d-0928-08d914e968f8 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT008.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR02MB6767 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Alveo FPGA firmware and partial reconfigure file are in xclbin format. This code enumerates and extracts sections from xclbin files. xclbin.h is cross platform and used across all platforms and OS. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/xclbin-helper.h | 48 +++ drivers/fpga/xrt/lib/xclbin.c | 381 +++++++++++++++++++++ include/uapi/linux/xrt/xclbin.h | 409 +++++++++++++++++++++++ 3 files changed, 838 insertions(+) create mode 100644 drivers/fpga/xrt/include/xclbin-helper.h create mode 100644 drivers/fpga/xrt/lib/xclbin.c create mode 100644 include/uapi/linux/xrt/xclbin.h diff --git a/drivers/fpga/xrt/include/xclbin-helper.h b/drivers/fpga/xrt/include/xclbin-helper.h new file mode 100644 index 000000000000..d5e29a882cd1 --- /dev/null +++ b/drivers/fpga/xrt/include/xclbin-helper.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * David Zhang + * Sonal Santan + */ + +#ifndef _XCLBIN_HELPER_H_ +#define _XCLBIN_HELPER_H_ + +#include +#include +#include + +#define XCLBIN_VERSION2 "xclbin2" +#define XCLBIN_HWICAP_BITFILE_BUF_SZ 1024 +#define XCLBIN_MAX_SZ_1G (1024 * 1024 * 1024) /* Assuming xclbin <= 1G, always */ + +enum axlf_section_kind; +struct axlf; + +/** + * Bitstream header information as defined by Xilinx tools. + * Please note that this struct definition is not owned by the driver. + */ +struct xclbin_bit_head_info { + u32 header_length; /* Length of header in 32 bit words */ + u32 bitstream_length; /* Length of bitstream to read in bytes */ + const unchar *design_name; /* Design name get from bitstream */ + const unchar *part_name; /* Part name read from bitstream */ + const unchar *date; /* Date read from bitstream header */ + const unchar *time; /* Bitstream creation time */ + u32 magic_length; /* Length of the magic numbers */ + const unchar *version; /* Version string */ +}; + +/* caller must free the allocated memory for **data. len could be NULL. */ +int xrt_xclbin_get_section(struct device *dev, const struct axlf *xclbin, + enum axlf_section_kind kind, void **data, + uint64_t *len); +int xrt_xclbin_get_metadata(struct device *dev, const struct axlf *xclbin, char **dtb); +int xrt_xclbin_parse_bitstream_header(struct device *dev, const unchar *data, + u32 size, struct xclbin_bit_head_info *head_info); +const char *xrt_clock_type2epname(enum XCLBIN_CLOCK_TYPE type); + +#endif /* _XCLBIN_HELPER_H_ */ diff --git a/drivers/fpga/xrt/lib/xclbin.c b/drivers/fpga/xrt/lib/xclbin.c new file mode 100644 index 000000000000..6edac3d418be --- /dev/null +++ b/drivers/fpga/xrt/lib/xclbin.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Driver XCLBIN parser + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: David Zhang + */ + +#include +#include +#include +#include "xclbin-helper.h" +#include "metadata.h" + +/* Used for parsing bitstream header */ +#define BITSTREAM_EVEN_MAGIC_BYTE 0x0f +#define BITSTREAM_ODD_MAGIC_BYTE 0xf0 + +static inline u16 bitstream_read16(const char *data, u32 *offset) +{ + u16 val; + + val = be16_to_cpu(*(__be16 *)(data + *offset)); + *offset += sizeof(__be16); + + return val; +} + +static inline u32 bitstream_read32(const char *data, u32 *offset) +{ + u32 val; + + val = be32_to_cpu(*(__be32 *)(data + *offset)); + *offset += sizeof(__be32); + + return val; +} + +static int xrt_xclbin_get_section_hdr(const struct axlf *xclbin, + enum axlf_section_kind kind, + const struct axlf_section_header **header) +{ + const struct axlf_section_header *phead = NULL; + u64 xclbin_len; + int i; + + *header = NULL; + for (i = 0; i < xclbin->header.num_sections; i++) { + if (xclbin->sections[i].section_kind == kind) { + phead = &xclbin->sections[i]; + break; + } + } + + if (!phead) + return -ENOENT; + + xclbin_len = xclbin->header.length; + if (xclbin_len > XCLBIN_MAX_SZ_1G || !phead->section_size || + phead->section_offset + phead->section_size > xclbin_len) + return -EINVAL; + + *header = phead; + return 0; +} + +static int xrt_xclbin_section_info(const struct axlf *xclbin, + enum axlf_section_kind kind, + u64 *offset, u64 *size) +{ + const struct axlf_section_header *mem_header = NULL; + int rc; + + rc = xrt_xclbin_get_section_hdr(xclbin, kind, &mem_header); + if (rc) + return rc; + + *offset = mem_header->section_offset; + *size = mem_header->section_size; + + return 0; +} + +/* caller must free the allocated memory for **data */ +int xrt_xclbin_get_section(struct device *dev, + const struct axlf *buf, + enum axlf_section_kind kind, + void **data, u64 *len) +{ + const struct axlf *xclbin = (const struct axlf *)buf; + void *section = NULL; + u64 offset; + u64 size; + int err; + + if (!data) { + dev_err(dev, "invalid data pointer"); + return -EINVAL; + } + + err = xrt_xclbin_section_info(xclbin, kind, &offset, &size); + if (err) { + dev_dbg(dev, "parsing section failed. kind %d, err = %d", kind, err); + return err; + } + + section = vzalloc(size); + if (!section) + return -ENOMEM; + + memcpy(section, ((const char *)xclbin) + offset, size); + + *data = section; + if (len) + *len = size; + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_xclbin_get_section); + +static inline int xclbin_bit_get_string(const unchar *data, u32 size, + u32 offset, unchar prefix, + const unchar **str) +{ + int len; + u32 tmp; + + /* prefix and length will be 3 bytes */ + if (offset + 3 > size) + return -EINVAL; + + /* Read prefix */ + tmp = data[offset++]; + if (tmp != prefix) + return -EINVAL; + + /* Get string length */ + len = bitstream_read16(data, &offset); + if (offset + len > size) + return -EINVAL; + + if (data[offset + len - 1] != '\0') + return -EINVAL; + + *str = data + offset; + + return len + 3; +} + +/* parse bitstream header */ +int xrt_xclbin_parse_bitstream_header(struct device *dev, const unchar *data, + u32 size, struct xclbin_bit_head_info *head_info) +{ + u32 offset = 0; + int len, i; + u16 magic; + + memset(head_info, 0, sizeof(*head_info)); + + /* Get "Magic" length */ + if (size < sizeof(u16)) { + dev_err(dev, "invalid size"); + return -EINVAL; + } + + len = bitstream_read16(data, &offset); + if (offset + len > size) { + dev_err(dev, "invalid magic len"); + return -EINVAL; + } + head_info->magic_length = len; + + for (i = 0; i < head_info->magic_length - 1; i++) { + magic = data[offset++]; + if (!(i % 2) && magic != BITSTREAM_EVEN_MAGIC_BYTE) { + dev_err(dev, "invalid magic even byte at %d", offset); + return -EINVAL; + } + + if ((i % 2) && magic != BITSTREAM_ODD_MAGIC_BYTE) { + dev_err(dev, "invalid magic odd byte at %d", offset); + return -EINVAL; + } + } + + if (offset + 3 > size) { + dev_err(dev, "invalid length of magic end"); + return -EINVAL; + } + /* Read null end of magic data. */ + if (data[offset++]) { + dev_err(dev, "invalid magic end"); + return -EINVAL; + } + + /* Read 0x01 (short) */ + magic = bitstream_read16(data, &offset); + + /* Check the "0x01" half word */ + if (magic != 0x01) { + dev_err(dev, "invalid magic end"); + return -EINVAL; + } + + len = xclbin_bit_get_string(data, size, offset, 'a', &head_info->design_name); + if (len < 0) { + dev_err(dev, "get design name failed"); + return -EINVAL; + } + + head_info->version = strstr(head_info->design_name, "Version=") + strlen("Version="); + offset += len; + + len = xclbin_bit_get_string(data, size, offset, 'b', &head_info->part_name); + if (len < 0) { + dev_err(dev, "get part name failed"); + return -EINVAL; + } + offset += len; + + len = xclbin_bit_get_string(data, size, offset, 'c', &head_info->date); + if (len < 0) { + dev_err(dev, "get data failed"); + return -EINVAL; + } + offset += len; + + len = xclbin_bit_get_string(data, size, offset, 'd', &head_info->time); + if (len < 0) { + dev_err(dev, "get time failed"); + return -EINVAL; + } + offset += len; + + if (offset + 5 >= size) { + dev_err(dev, "can not get bitstream length"); + return -EINVAL; + } + + /* Read 'e' */ + if (data[offset++] != 'e') { + dev_err(dev, "invalid prefix of bitstream length"); + return -EINVAL; + } + + /* Get byte length of bitstream */ + head_info->bitstream_length = bitstream_read32(data, &offset); + + head_info->header_length = offset; + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_xclbin_parse_bitstream_header); + +static struct xrt_clock_desc { + char *clock_ep_name; + u32 clock_xclbin_type; + char *clkfreq_ep_name; +} clock_desc[] = { + { + .clock_ep_name = XRT_MD_NODE_CLK_KERNEL1, + .clock_xclbin_type = CT_DATA, + .clkfreq_ep_name = XRT_MD_NODE_CLKFREQ_K1, + }, + { + .clock_ep_name = XRT_MD_NODE_CLK_KERNEL2, + .clock_xclbin_type = CT_KERNEL, + .clkfreq_ep_name = XRT_MD_NODE_CLKFREQ_K2, + }, + { + .clock_ep_name = XRT_MD_NODE_CLK_KERNEL3, + .clock_xclbin_type = CT_SYSTEM, + .clkfreq_ep_name = XRT_MD_NODE_CLKFREQ_HBM, + }, +}; + +const char *xrt_clock_type2epname(enum XCLBIN_CLOCK_TYPE type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clock_desc); i++) { + if (clock_desc[i].clock_xclbin_type == type) + return clock_desc[i].clock_ep_name; + } + return NULL; +} +EXPORT_SYMBOL_GPL(xrt_clock_type2epname); + +static const char *clock_type2clkfreq_name(enum XCLBIN_CLOCK_TYPE type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clock_desc); i++) { + if (clock_desc[i].clock_xclbin_type == type) + return clock_desc[i].clkfreq_ep_name; + } + return NULL; +} + +static int xrt_xclbin_add_clock_metadata(struct device *dev, + const struct axlf *xclbin, + char *dtb) +{ + struct clock_freq_topology *clock_topo; + u16 freq; + int rc; + int i; + + /* if clock section does not exist, add nothing and return success */ + rc = xrt_xclbin_get_section(dev, xclbin, CLOCK_FREQ_TOPOLOGY, + (void **)&clock_topo, NULL); + if (rc == -ENOENT) + return 0; + else if (rc) + return rc; + + for (i = 0; i < clock_topo->count; i++) { + u8 type = clock_topo->clock_freq[i].type; + const char *ep_name = xrt_clock_type2epname(type); + const char *counter_name = clock_type2clkfreq_name(type); + + if (!ep_name || !counter_name) + continue; + + freq = be16_to_cpu((__force __be16)clock_topo->clock_freq[i].freq_MHZ); + rc = xrt_md_set_prop(dev, dtb, ep_name, NULL, XRT_MD_PROP_CLK_FREQ, + &freq, sizeof(freq)); + if (rc) + break; + + rc = xrt_md_set_prop(dev, dtb, ep_name, NULL, XRT_MD_PROP_CLK_CNT, + counter_name, strlen(counter_name) + 1); + if (rc) + break; + } + + vfree(clock_topo); + + return rc; +} + +int xrt_xclbin_get_metadata(struct device *dev, const struct axlf *xclbin, char **dtb) +{ + char *md = NULL, *newmd = NULL; + u64 len, md_len; + int rc; + + *dtb = NULL; + + rc = xrt_xclbin_get_section(dev, xclbin, PARTITION_METADATA, (void **)&md, &len); + if (rc) + goto done; + + md_len = xrt_md_size(dev, md); + + /* Sanity check the dtb section. */ + if (md_len > len) { + rc = -EINVAL; + goto done; + } + + /* use dup function here to convert incoming metadata to writable */ + newmd = xrt_md_dup(dev, md); + if (!newmd) { + rc = -EFAULT; + goto done; + } + + /* Convert various needed xclbin sections into dtb. */ + rc = xrt_xclbin_add_clock_metadata(dev, xclbin, newmd); + + if (!rc) + *dtb = newmd; + else + vfree(newmd); +done: + vfree(md); + return rc; +} +EXPORT_SYMBOL_GPL(xrt_xclbin_get_metadata); diff --git a/include/uapi/linux/xrt/xclbin.h b/include/uapi/linux/xrt/xclbin.h new file mode 100644 index 000000000000..fdaf0c91843d --- /dev/null +++ b/include/uapi/linux/xrt/xclbin.h @@ -0,0 +1,409 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Xilinx FPGA compiled binary container format + * + * Copyright (C) 2015-2021, Xilinx Inc + */ + +#ifndef _XCLBIN_H_ +#define _XCLBIN_H_ + +#if defined(__KERNEL__) + +#include + +#elif defined(__cplusplus) + +#include +#include +#include +#include + +#else + +#include +#include +#include + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * DOC: Container format for Xilinx FPGA images + * The container stores bitstreams, metadata and firmware images. + * xclbin/xsabin is an ELF-like binary container format. It is a structured + * series of sections. There is a file header followed by several section + * headers which is followed by sections. A section header points to an + * actual section. There is an optional signature at the end. The + * following figure illustrates a typical xclbin: + * + * +---------------------+ + * | | + * | HEADER | + * +---------------------+ + * | SECTION HEADER | + * | | + * +---------------------+ + * | ... | + * | | + * +---------------------+ + * | SECTION HEADER | + * | | + * +---------------------+ + * | SECTION | + * | | + * +---------------------+ + * | ... | + * | | + * +---------------------+ + * | SECTION | + * | | + * +---------------------+ + * | SIGNATURE | + * | (OPTIONAL) | + * +---------------------+ + */ + +enum XCLBIN_MODE { + XCLBIN_FLAT = 0, + XCLBIN_PR, + XCLBIN_TANDEM_STAGE2, + XCLBIN_TANDEM_STAGE2_WITH_PR, + XCLBIN_HW_EMU, + XCLBIN_SW_EMU, + XCLBIN_MODE_MAX +}; + +enum axlf_section_kind { + BITSTREAM = 0, + CLEARING_BITSTREAM, + EMBEDDED_METADATA, + FIRMWARE, + DEBUG_DATA, + SCHED_FIRMWARE, + MEM_TOPOLOGY, + CONNECTIVITY, + IP_LAYOUT, + DEBUG_IP_LAYOUT, + DESIGN_CHECK_POINT, + CLOCK_FREQ_TOPOLOGY, + MCS, + BMC, + BUILD_METADATA, + KEYVALUE_METADATA, + USER_METADATA, + DNA_CERTIFICATE, + PDI, + BITSTREAM_PARTIAL_PDI, + PARTITION_METADATA, + EMULATION_DATA, + SYSTEM_METADATA, + SOFT_KERNEL, + ASK_FLASH, + AIE_METADATA, + ASK_GROUP_TOPOLOGY, + ASK_GROUP_CONNECTIVITY +}; + +enum MEM_TYPE { + MEM_DDR3 = 0, + MEM_DDR4, + MEM_DRAM, + MEM_STREAMING, + MEM_PREALLOCATED_GLOB, + MEM_ARE, + MEM_HBM, + MEM_BRAM, + MEM_URAM, + MEM_STREAMING_CONNECTION +}; + +enum IP_TYPE { + IP_MB = 0, + IP_KERNEL, + IP_DNASC, + IP_DDR4_CONTROLLER, + IP_MEM_DDR4, + IP_MEM_HBM +}; + +struct axlf_section_header { + uint32_t section_kind; /* Section type */ + char section_name[16]; /* Examples: "stage2", "clear1", */ + /* "clear2", "ocl1", "ocl2, */ + /* "ublaze", "sched" */ + char rsvd[4]; + uint64_t section_offset; /* File offset of section data */ + uint64_t section_size; /* Size of section data */ +} __packed; + +struct axlf_header { + uint64_t length; /* Total size of the xclbin file */ + uint64_t time_stamp; /* Number of seconds since epoch */ + /* when xclbin was created */ + uint64_t feature_rom_timestamp; /* TimeSinceEpoch of the featureRom */ + uint16_t version_patch; /* Patch Version */ + uint8_t version_major; /* Major Version - Version: 2.1.0 */ + uint8_t version_minor; /* Minor Version */ + uint32_t mode; /* XCLBIN_MODE */ + union { + struct { + uint64_t platform_id; /* 64 bit platform ID: */ + /* vendor-device-subvendor-subdev */ + uint64_t feature_id; /* 64 bit feature id */ + } rom; + unsigned char rom_uuid[16]; /* feature ROM UUID for which */ + /* this xclbin was generated */ + }; + unsigned char platform_vbnv[64]; /* e.g. */ + /* xilinx:xil-accel-rd-ku115:4ddr-xpr:3.4: null terminated */ + union { + char next_axlf[16]; /* Name of next xclbin file */ + /* in the daisy chain */ + unsigned char uuid[16]; /* uuid of this xclbin */ + }; + char debug_bin[16]; /* Name of binary with debug */ + /* information */ + uint32_t num_sections; /* Number of section headers */ + char rsvd[4]; +} __packed; + +struct axlf { + char magic[8]; /* Should be "xclbin2\0" */ + int32_t signature_length; /* Length of the signature */ + /* -1 indicates no signature */ + unsigned char reserved[28]; /* Note: Initialized to 0xFFs */ + + unsigned char key_block[256]; /* Signature for validation */ + /* of binary */ + uint64_t unique_id; /* axlf's uniqueId, use it to */ + /* skip redownload etc */ + struct axlf_header header; /* Inline header */ + struct axlf_section_header sections[1]; /* One or more section */ + /* headers follow */ +} __packed; + +/* bitstream information */ +struct xlnx_bitstream { + uint8_t freq[8]; + char bits[1]; +} __packed; + +/**** MEMORY TOPOLOGY SECTION ****/ +struct mem_data { + uint8_t type; /* enum corresponding to mem_type */ + uint8_t used; /* if 0 this bank is not present */ + uint8_t rsvd[6]; + union { + uint64_t size; /* if mem_type DDR, then size in KB */ + uint64_t route_id; /* if streaming then "route_id" */ + }; + union { + uint64_t base_address;/* if DDR then the base address */ + uint64_t flow_id; /* if streaming then "flow id" */ + }; + unsigned char tag[16]; /* DDR: BANK0,1,2,3, has to be null */ + /* terminated; if streaming then stream0, 1 etc */ +} __packed; + +struct mem_topology { + int32_t count; /* Number of mem_data */ + struct mem_data mem_data[1]; /* Should be sorted on mem_type */ +} __packed; + +/**** CONNECTIVITY SECTION ****/ +/* Connectivity of each argument of CU(Compute Unit). It will be in terms + * of argument index associated. For associating CU instances with arguments + * and banks, start at the connectivity section. Using the ip_layout_index + * access the ip_data.name. Now we can associate this CU instance with its + * original CU name and get the connectivity as well. This enables us to form + * related groups of CU instances. + */ + +struct connection { + int32_t arg_index; /* From 0 to n, may not be contiguous as scalars */ + /* skipped */ + int32_t ip_layout_index; /* index into the ip_layout section */ + /* ip_layout.ip_data[index].type == IP_KERNEL */ + int32_t mem_data_index; /* index of the mem_data . Flag error is */ + /* used false. */ +} __packed; + +struct connectivity { + int32_t count; + struct connection connection[1]; +} __packed; + +/**** IP_LAYOUT SECTION ****/ + +/* IP Kernel */ +#define IP_INT_ENABLE_MASK 0x0001 +#define IP_INTERRUPT_ID_MASK 0x00FE +#define IP_INTERRUPT_ID_SHIFT 0x1 + +enum IP_CONTROL { + AP_CTRL_HS = 0, + AP_CTRL_CHAIN, + AP_CTRL_NONE, + AP_CTRL_ME, + ACCEL_ADAPTER +}; + +#define IP_CONTROL_MASK 0xFF00 +#define IP_CONTROL_SHIFT 0x8 + +/* IPs on AXI lite - their types, names, and base addresses. */ +struct ip_data { + uint32_t type; /* map to IP_TYPE enum */ + union { + uint32_t properties; /* Default: 32-bits to indicate ip */ + /* specific property. */ + /* type: IP_KERNEL + * int_enable : Bit - 0x0000_0001; + * interrupt_id : Bits - 0x0000_00FE; + * ip_control : Bits = 0x0000_FF00; + */ + struct { /* type: IP_MEM_* */ + uint16_t index; + uint8_t pc_index; + uint8_t unused; + } indices; + }; + uint64_t base_address; + uint8_t name[64]; /* eg Kernel name corresponding to KERNEL */ + /* instance, can embed CU name in future. */ +} __packed; + +struct ip_layout { + int32_t count; + struct ip_data ip_data[1]; /* All the ip_data needs to be sorted */ + /* by base_address. */ +} __packed; + +/*** Debug IP section layout ****/ +enum DEBUG_IP_TYPE { + UNDEFINED = 0, + LAPC, + ILA, + AXI_MM_MONITOR, + AXI_TRACE_FUNNEL, + AXI_MONITOR_FIFO_LITE, + AXI_MONITOR_FIFO_FULL, + ACCEL_MONITOR, + AXI_STREAM_MONITOR, + AXI_STREAM_PROTOCOL_CHECKER, + TRACE_S2MM, + AXI_DMA, + TRACE_S2MM_FULL +}; + +struct debug_ip_data { + uint8_t type; /* type of enum DEBUG_IP_TYPE */ + uint8_t index_lowbyte; + uint8_t properties; + uint8_t major; + uint8_t minor; + uint8_t index_highbyte; + uint8_t reserved[2]; + uint64_t base_address; + char name[128]; +} __packed; + +struct debug_ip_layout { + uint16_t count; + struct debug_ip_data debug_ip_data[1]; +} __packed; + +/* Supported clock frequency types */ +enum XCLBIN_CLOCK_TYPE { + CT_UNUSED = 0, /* Initialized value */ + CT_DATA = 1, /* Data clock */ + CT_KERNEL = 2, /* Kernel clock */ + CT_SYSTEM = 3 /* System Clock */ +}; + +/* Clock Frequency Entry */ +struct clock_freq { + uint16_t freq_MHZ; /* Frequency in MHz */ + uint8_t type; /* Clock type (enum CLOCK_TYPE) */ + uint8_t unused[5]; /* Not used - padding */ + char name[128]; /* Clock Name */ +} __packed; + +/* Clock frequency section */ +struct clock_freq_topology { + int16_t count; /* Number of entries */ + struct clock_freq clock_freq[1]; /* Clock array */ +} __packed; + +/* Supported MCS file types */ +enum MCS_TYPE { + MCS_UNKNOWN = 0, /* Initialized value */ + MCS_PRIMARY = 1, /* The primary mcs file data */ + MCS_SECONDARY = 2, /* The secondary mcs file data */ +}; + +/* One chunk of MCS data */ +struct mcs_chunk { + uint8_t type; /* MCS data type */ + uint8_t unused[7]; /* padding */ + uint64_t offset; /* data offset from the start of */ + /* the section */ + uint64_t size; /* data size */ +} __packed; + +/* MCS data section */ +struct mcs { + int8_t count; /* Number of chunks */ + int8_t unused[7]; /* padding */ + struct mcs_chunk chunk[1]; /* MCS chunks followed by data */ +} __packed; + +/* bmc data section */ +struct bmc { + uint64_t offset; /* data offset from the start of */ + /* the section */ + uint64_t size; /* data size (bytes) */ + char image_name[64]; /* Name of the image */ + /* (e.g., MSP432P401R) */ + char device_name[64]; /* Device ID (e.g., VCU1525) */ + char version[64]; + char md5value[33]; /* MD5 Expected Value */ + /* (e.g., 56027182079c0bd621761b7dab5a27ca) */ + char padding[7]; /* Padding */ +} __packed; + +/* soft kernel data section, used by classic driver */ +struct soft_kernel { + /** Prefix Syntax: + * mpo - member, pointer, offset + * This variable represents a zero terminated string + * that is offseted from the beginning of the section. + * The pointer to access the string is initialized as follows: + * char * pCharString = (address_of_section) + (mpo value) + */ + uint32_t mpo_name; /* Name of the soft kernel */ + uint32_t image_offset; /* Image offset */ + uint32_t image_size; /* Image size */ + uint32_t mpo_version; /* Version */ + uint32_t mpo_md5_value; /* MD5 checksum */ + uint32_t mpo_symbol_name; /* Symbol name */ + uint32_t num_instances; /* Number of instances */ + uint8_t padding[36]; /* Reserved for future use */ + uint8_t reserved_ext[16]; /* Reserved for future extended data */ +} __packed; + +enum CHECKSUM_TYPE { + CST_UNKNOWN = 0, + CST_SDBM = 1, + CST_LAST +}; + +#ifdef __cplusplus +} +#endif + +#endif From patchwork Wed May 12 01:53:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435843 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2EA8CC433ED for ; Wed, 12 May 2021 01:58:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 01EE2616E9 for ; Wed, 12 May 2021 01:58:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230188AbhELB7p (ORCPT ); Tue, 11 May 2021 21:59:45 -0400 Received: from mail-mw2nam12on2053.outbound.protection.outlook.com ([40.107.244.53]:56121 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230202AbhELB7n (ORCPT ); Tue, 11 May 2021 21:59:43 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lRiZ1o6RC9nUJkUFgzZasmRyvZEpMtqjBY/QxPKcT6wRrffHysXYHhJ6HgI8QJSufvICEwZyuTvap12FHQeBhjkKU4vP4COI5gfT4KFNV6u2dOvgGEZAN8UnbrlkIJF0ja2V5RyiE20BRryco8K6m4XQmj3vLR88k4HDAGgnM7qofgng6lLMlNCi1+P3ncWIWzIPGUsnqaB+hbr5oJ6SgqCT8kOFgzvcqnT4z4Qya+rJiwkQ09xwONuRczi7XGStqUPGTNrSrJzXUb92v+ZEw16JzkFZVFoB83sK/BroKq1jJvRfgBzE+SbQ3vYE02D4w+jYzEJnKv1PJzGjujkAzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PCX0uLyI8DyDALmjDSx/DCq6ZEGpSQm1m8kEhGOkgTs=; b=EWwgSr2pzGlBC9sO0hl5JrbbJTDziqVrOaxkJm8uZI3i9GfX+DW/MaWGbg88PRAwOHYeMcueRlauiUBl1YTD/5wMeDRd7jLKJhW07kk16GdyItYnoFsv0XT8oYsIBe0/FoV4wuytHHv+QYaHszmqyZMFVfrpj37qcT3hfxcB3YtmHmnQ7O6eCXMbzy73S+6yY/BwIELPojKY6WyY254AGNiSPHcMvUSD8nzgikdYbWVjD/zdVdk1ip+UdSZVvkD2vpEMrbdOY3HMKON9fHbEB8U3avfZj3L+cyOtmTkOF6OVyqoAZj+R2ZKWuRuR5Gy6U7+CmF5sbOsxLKQLOQMupA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PCX0uLyI8DyDALmjDSx/DCq6ZEGpSQm1m8kEhGOkgTs=; b=lxNhKqiJP+22YiFGERjODFC+PXBlYcmXyA02eTfg6+je6/Q4u7+UPU4BthlU/mkIajE/UXeiT1ud/qwxEs7yBlVfamcWsGNq8s/DsknTCkjm+klXRRxrgzdZ2iXcqESDSu/czmyR66qZHnAKC/IgMyq7hTO14Y5m5lj/X01WEGQ= Received: from BN0PR04CA0160.namprd04.prod.outlook.com (2603:10b6:408:eb::15) by SJ0PR02MB7679.namprd02.prod.outlook.com (2603:10b6:a03:31a::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4129.25; Wed, 12 May 2021 01:58:35 +0000 Received: from BN1NAM02FT017.eop-nam02.prod.protection.outlook.com (2603:10b6:408:eb:cafe::85) by BN0PR04CA0160.outlook.office365.com (2603:10b6:408:eb::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 01:58:34 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch02.xlnx.xilinx.com; Received: from xsj-pvapexch02.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT017.mail.protection.outlook.com (10.13.2.134) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 01:58:34 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:58:19 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:58:19 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35722 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lge8h-0005RH-0N; Tue, 11 May 2021 18:58:19 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 1D45260012A; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 05/20] fpga: xrt: group driver Date: Tue, 11 May 2021 18:53:24 -0700 Message-ID: <20210512015339.5649-6-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 27643fdd-3406-4883-78a0-08d914e97393 X-MS-TrafficTypeDiagnostic: SJ0PR02MB7679: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:126; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: G96DN3V5MNlQsd7ztR70TFhItRybJ8MEGJL67Rtxv+fw4SDVklQN9rruR0N1+H+bjuKVLSnFpeKvswPMEPQEW32yF1vPscAkHVnX7TyCp5/WnnwFtJBpXZ8u67yQkKseMkGhIVGgfok7G0BITgYpKybnqCsFzY2IU/A0LbnLpG1SroOHihcj4ngjwMxVlO219rRImJBQowU+o17astc4SU+TIMqLyXIlfRAw/bdNDrXGWdlhsUnyevB1oqmOpb2eTK3M4AVBdLzQG7vG2i4+NDRSywpfTiVlRmg0+jMQ9vMouyxM247IpnYAdD8TN+cGw3CTeE4Sejx215wNlEiGn+hbJo3ZVayThxHl5zMEFDEuNc+/7ClpPP+rxh72uMpaPOfa2atnECcJR3kaV7cEBJYP0nODQAu/XIZoZA9c4Zcgwl0iuHx1qjn20o8LcwVfDfOTKm8ZEjKy1jBTd+7JkmZ73yu24y6Ugwtl2+Qn0Zv0mDtsQpL83Bs1l6KpqoFVanw+qwjzLJso0Ll/FqAP9sq2zmTWUgXog9RnIm4zeCFkKHoZ+0J+ljLBE/wY1e8Pm3dbeYtcFcGxMJp4AG6/YvwprwYpUuIcJmA+/c62awS2qP3iL7ZlIAZuo3w6Q60ESjt4UtRzdk3pWVys2m3UjilNRf4B/+h11HmjXGemrAM= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(376002)(136003)(396003)(39850400004)(346002)(46966006)(36840700001)(4326008)(6266002)(70586007)(36860700001)(44832011)(6666004)(6916009)(47076005)(36756003)(107886003)(2616005)(82310400003)(186003)(2906002)(8676002)(5660300002)(83380400001)(356005)(1076003)(7636003)(478600001)(54906003)(8936002)(426003)(336012)(70206006)(42186006)(316002)(82740400003)(36906005)(26005); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 01:58:34.7086 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 27643fdd-3406-4883-78a0-08d914e97393 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch02.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT017.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR02MB7679 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org group driver that manages life cycle of a bunch of leaf driver instances and bridges them with root. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/group.h | 25 +++ drivers/fpga/xrt/lib/group.c | 278 +++++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 drivers/fpga/xrt/include/group.h create mode 100644 drivers/fpga/xrt/lib/group.c diff --git a/drivers/fpga/xrt/include/group.h b/drivers/fpga/xrt/include/group.h new file mode 100644 index 000000000000..09e9d03f53fe --- /dev/null +++ b/drivers/fpga/xrt/include/group.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_GROUP_H_ +#define _XRT_GROUP_H_ + +#include "xleaf.h" + +/* + * Group driver leaf calls. + */ +enum xrt_group_leaf_cmd { + XRT_GROUP_GET_LEAF = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_GROUP_PUT_LEAF, + XRT_GROUP_INIT_CHILDREN, + XRT_GROUP_FINI_CHILDREN, + XRT_GROUP_TRIGGER_EVENT, +}; + +#endif /* _XRT_GROUP_H_ */ diff --git a/drivers/fpga/xrt/lib/group.c b/drivers/fpga/xrt/lib/group.c new file mode 100644 index 000000000000..b45f05449e0b --- /dev/null +++ b/drivers/fpga/xrt/lib/group.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Group Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include "xleaf.h" +#include "subdev_pool.h" +#include "group.h" +#include "metadata.h" +#include "lib-drv.h" + +#define XRT_GRP "xrt_group" + +struct xrt_group { + struct xrt_device *xdev; + struct xrt_subdev_pool leaves; + bool leaves_created; + struct mutex lock; /* lock for group */ +}; + +static int xrt_grp_root_cb(struct device *dev, void *parg, + enum xrt_root_cmd cmd, void *arg) +{ + int rc; + struct xrt_device *xdev = + container_of(dev, struct xrt_device, dev); + struct xrt_group *xg = (struct xrt_group *)parg; + + switch (cmd) { + case XRT_ROOT_GET_LEAF_HOLDERS: { + struct xrt_root_get_holders *holders = + (struct xrt_root_get_holders *)arg; + rc = xrt_subdev_pool_get_holders(&xg->leaves, + holders->xpigh_xdev, + holders->xpigh_holder_buf, + holders->xpigh_holder_buf_len); + break; + } + default: + /* Forward parent call to root. */ + rc = xrt_subdev_root_request(xdev, cmd, arg); + break; + } + + return rc; +} + +/* + * Cut subdev's dtb from group's dtb based on passed-in endpoint descriptor. + * Return the subdev's dtb through dtbp, if found. + */ +static int xrt_grp_cut_subdev_dtb(struct xrt_group *xg, struct xrt_dev_endpoints *eps, + char *grp_dtb, char **dtbp) +{ + int ret, i, ep_count = 0; + char *dtb = NULL; + + ret = xrt_md_create(DEV(xg->xdev), &dtb); + if (ret) + return ret; + + for (i = 0; eps->xse_names[i].ep_name || eps->xse_names[i].compat; i++) { + const char *ep_name = eps->xse_names[i].ep_name; + const char *compat = eps->xse_names[i].compat; + + if (!ep_name) + xrt_md_get_compatible_endpoint(DEV(xg->xdev), grp_dtb, compat, &ep_name); + if (!ep_name) + continue; + + ret = xrt_md_copy_endpoint(DEV(xg->xdev), dtb, grp_dtb, ep_name, compat, NULL); + if (ret) + continue; + xrt_md_del_endpoint(DEV(xg->xdev), grp_dtb, ep_name, compat); + ep_count++; + } + /* Found enough endpoints, return the subdev's dtb. */ + if (ep_count >= eps->xse_min_ep) { + *dtbp = dtb; + return 0; + } + + /* Cleanup - Restore all endpoints that has been deleted, if any. */ + if (ep_count > 0) { + xrt_md_copy_endpoint(DEV(xg->xdev), grp_dtb, dtb, + XRT_MD_NODE_ENDPOINTS, NULL, NULL); + } + vfree(dtb); + *dtbp = NULL; + return 0; +} + +static int xrt_grp_create_leaves(struct xrt_group *xg) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(xg->xdev); + struct xrt_dev_endpoints *eps = NULL; + int ret = 0, failed = 0; + enum xrt_subdev_id did; + char *grp_dtb = NULL; + unsigned long mlen; + + if (!pdata) + return -EINVAL; + + mlen = xrt_md_size(DEV(xg->xdev), pdata->xsp_dtb); + if (mlen == XRT_MD_INVALID_LENGTH) { + xrt_err(xg->xdev, "invalid dtb, len %ld", mlen); + return -EINVAL; + } + + mutex_lock(&xg->lock); + + if (xg->leaves_created) { + /* + * This is expected since caller does not keep track of the state of the group + * and may, in some cases, still try to create leaves after it has already been + * created. This special error code will let the caller know what is going on. + */ + mutex_unlock(&xg->lock); + return -EEXIST; + } + + grp_dtb = vmalloc(mlen); + if (!grp_dtb) { + mutex_unlock(&xg->lock); + return -ENOMEM; + } + + /* Create all leaves based on dtb. */ + xrt_info(xg->xdev, "bringing up leaves..."); + memcpy(grp_dtb, pdata->xsp_dtb, mlen); + for (did = 0; did < XRT_SUBDEV_NUM; did++) { + eps = xrt_drv_get_endpoints(did); + while (eps && eps->xse_names) { + char *dtb = NULL; + + ret = xrt_grp_cut_subdev_dtb(xg, eps, grp_dtb, &dtb); + if (ret) { + failed++; + xrt_err(xg->xdev, "failed to cut subdev dtb for drv %s: %d", + xrt_drv_name(did), ret); + } + if (!dtb) { + /* + * No more dtb to cut or bad things happened for this instance, + * switch to the next one. + */ + eps++; + continue; + } + + /* Found a dtb for this instance, let's add it. */ + ret = xrt_subdev_pool_add(&xg->leaves, did, xrt_grp_root_cb, xg, dtb); + if (ret < 0) { + /* + * It is not a fatal error here. Some functionality is not usable + * due to this missing device, but the error can be handled + * when the functionality is used. + */ + failed++; + xrt_err(xg->xdev, "failed to add %s: %d", xrt_drv_name(did), ret); + } + vfree(dtb); + /* Continue searching for the same instance from grp_dtb. */ + } + } + + xg->leaves_created = true; + vfree(grp_dtb); + mutex_unlock(&xg->lock); + return failed == 0 ? 0 : -ECHILD; +} + +static void xrt_grp_remove_leaves(struct xrt_group *xg) +{ + mutex_lock(&xg->lock); + + if (!xg->leaves_created) { + mutex_unlock(&xg->lock); + return; + } + + xrt_info(xg->xdev, "tearing down leaves..."); + xrt_subdev_pool_fini(&xg->leaves); + xg->leaves_created = false; + + mutex_unlock(&xg->lock); +} + +static int xrt_grp_probe(struct xrt_device *xdev) +{ + struct xrt_group *xg; + + xrt_info(xdev, "probing..."); + + xg = devm_kzalloc(&xdev->dev, sizeof(*xg), GFP_KERNEL); + if (!xg) + return -ENOMEM; + + xg->xdev = xdev; + mutex_init(&xg->lock); + xrt_subdev_pool_init(DEV(xdev), &xg->leaves); + xrt_set_drvdata(xdev, xg); + + return 0; +} + +static void xrt_grp_remove(struct xrt_device *xdev) +{ + struct xrt_group *xg = xrt_get_drvdata(xdev); + + xrt_info(xdev, "leaving..."); + xrt_grp_remove_leaves(xg); +} + +static int xrt_grp_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + int rc = 0; + struct xrt_group *xg = xrt_get_drvdata(xdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Simply forward to every child. */ + xrt_subdev_pool_handle_event(&xg->leaves, + (struct xrt_event *)arg); + break; + case XRT_GROUP_GET_LEAF: { + struct xrt_root_get_leaf *get_leaf = + (struct xrt_root_get_leaf *)arg; + + rc = xrt_subdev_pool_get(&xg->leaves, get_leaf->xpigl_match_cb, + get_leaf->xpigl_match_arg, + DEV(get_leaf->xpigl_caller_xdev), + &get_leaf->xpigl_tgt_xdev); + break; + } + case XRT_GROUP_PUT_LEAF: { + struct xrt_root_put_leaf *put_leaf = + (struct xrt_root_put_leaf *)arg; + + rc = xrt_subdev_pool_put(&xg->leaves, put_leaf->xpipl_tgt_xdev, + DEV(put_leaf->xpipl_caller_xdev)); + break; + } + case XRT_GROUP_INIT_CHILDREN: + rc = xrt_grp_create_leaves(xg); + break; + case XRT_GROUP_FINI_CHILDREN: + xrt_grp_remove_leaves(xg); + break; + case XRT_GROUP_TRIGGER_EVENT: + xrt_subdev_pool_trigger_event(&xg->leaves, (enum xrt_events)(uintptr_t)arg); + break; + default: + xrt_err(xdev, "unknown IOCTL cmd %d", cmd); + rc = -EINVAL; + break; + } + return rc; +} + +static struct xrt_driver xrt_group_driver = { + .driver = { + .name = XRT_GRP, + }, + .subdev_id = XRT_SUBDEV_GRP, + .probe = xrt_grp_probe, + .remove = xrt_grp_remove, + .leaf_call = xrt_grp_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(group); From patchwork Wed May 12 01:53:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435842 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5258DC433ED for ; Wed, 12 May 2021 01:59:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3A49861935 for ; Wed, 12 May 2021 01:59:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229934AbhELCAG (ORCPT ); Tue, 11 May 2021 22:00:06 -0400 Received: from mail-dm6nam12on2061.outbound.protection.outlook.com ([40.107.243.61]:41536 "EHLO NAM12-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229984AbhELCAF (ORCPT ); Tue, 11 May 2021 22:00:05 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=UPJdzs0fmPwTWhnpyNHk5bTDMGHjC/C5XrogyJ02htkEuKBIOmYHC7cQbvhKLmuM7M1XMT0zOGn0pRuTo46rkHjw7xwiP7QzFLwXLazUY6/WbcB3rvu3ykZAydzHqTzcyliGZxZapdzJiPE/O6bAilqSx74azreuixXKu+xpBwAWpdiczKXbogdKDgYxr/9Au53CP9qs9MHNCld008zxLNacL89Vr0opQlBPYtENcMGb52S8Aqu7HHRwLuChqVs+mdGBQJGGRsb1OmvgUiYhBZgOnK1G65Rh6MagEVsC13gF9fFB7zYJPWIKKG+mlS9RzG7IUDOyylW+oCegMywEJg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CBPICZ1UWTcNnkauGu/Oj8H25NoubpXPBQ9WQSMKpt8=; b=j8auCvoja0MTw2te6z/2zKXa9+9yDaMQS9nnOSJNzupHva18w/5VAY9AlZXq353745Phd/KRLpy41ShJ/62QueON6iKWLccVhFesQqZWCer5iuOBCX/oUvJCpJI6f/IWqFoEmiZl3qW8DaI+XBrpqfEnopQdSiFpUGiY6Ei1OwXiaLBuGJq1cB5Z9rQEaDXu2GTdN5ORMZB0ILtXrjd/xox0TiSCfBzaXkKd2knfiFaz+Aajk87McLHyMCZaNnoAzF2LxY5aoO2xzGPgqb2yaaAoe+eSnUiUtP5mK8EQjETFf0NcCsc7sRwd3hVu7KQVni6nYAyerrg0bWRQr4R6/A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CBPICZ1UWTcNnkauGu/Oj8H25NoubpXPBQ9WQSMKpt8=; b=c7gWyBhHdC07/XfIfiDkyCS7BD97IQrpGwi/wtu9s2b1OC82F3qWM+cjuuJ9NnPm38Z8tnrKAH/d5FPmscMO3Yt319AYHBsGdYxSxEgxuHpgfEiH9Z+oV+aU3XHWQr3ZzPW+GdRxohM1LAWfzEm+NV2NWInWAEnl7b28MYMAeKw= Received: from BN6PR1101CA0016.namprd11.prod.outlook.com (2603:10b6:405:4a::26) by MW2PR02MB3692.namprd02.prod.outlook.com (2603:10b6:907:e::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4129.25; Wed, 12 May 2021 01:58:56 +0000 Received: from BN1NAM02FT054.eop-nam02.prod.protection.outlook.com (2603:10b6:405:4a:cafe::85) by BN6PR1101CA0016.outlook.office365.com (2603:10b6:405:4a::26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 01:58:55 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch02.xlnx.xilinx.com; Received: from xsj-pvapexch02.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT054.mail.protection.outlook.com (10.13.2.162) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 01:58:55 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:58:43 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:58:43 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35726 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lge95-0005Tp-3o; Tue, 11 May 2021 18:58:43 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 4965560012D; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 07/20] fpga: xrt: root driver infrastructure Date: Tue, 11 May 2021 18:53:26 -0700 Message-ID: <20210512015339.5649-8-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 6e12ab0d-edaf-4c4f-77ed-08d914e98021 X-MS-TrafficTypeDiagnostic: MW2PR02MB3692: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:454; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Qthdcjp9QYN5pAGMvwzwBT602G89DaimoXdIhZ4PwwzeDwOawCIKPQYpCTsgxweGDdh8NCDZnkvLIhrJTg0BtACS6MbUneUuihel5yeo9tgc5Hd4cf6gS84ha+32JtlpGjMS1JsICm457efMG5LGllqHA3I3lTIQ/MHS+sM0KjJoGM746u1FYdXWxQqnfBHAdJHyG+IQoW2wqh6coAiiq8LxxlsmMY/0p4F070mzkOYHG6cTXK/c/lEa5uVpycqk0wBkzMMy84+lO7IsHlsmnAu1llVeisYmMY5AwPkBaFohnKxYgzjk6Wz/NuV9nfqVDFdU3TsOxj/ktCIWNJXSY+N0OU9oX0FghNxOlTOSvb/GzMkgNXK45UAxcMuAqY6AmdSRfG4+rToMd1pGFru0dlXtZKR8NY+9Yka+cehV7Hk+pzgpO68LrLJb/M8THNBXbYgqXAgMcbz0f5yD2vUXa/qGh+IQ9XNlSmwcZVkhdfpZH6vwGFq98quIO2xokCv3eW6gEcD8rGO3frhYdFpiQiCcQ0rV6K7QL6QIPyQPwnM4kWsjA4zbaty3cG0gvlWb8WglKDrVz/nw6VmkdvAc6/z++KfV0elen/Y5kylCv0taFuzOpDGpBkeqoRlCCIxnBJph1k90lFuMjX+ohFh9a4yLRMAqXYHAZlLt6LVH8qM= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(376002)(136003)(396003)(39850400004)(346002)(46966006)(36840700001)(4326008)(6266002)(70586007)(36860700001)(44832011)(6666004)(6916009)(47076005)(36756003)(107886003)(2616005)(82310400003)(186003)(2906002)(8676002)(5660300002)(83380400001)(356005)(1076003)(7636003)(30864003)(478600001)(54906003)(8936002)(426003)(336012)(70206006)(42186006)(316002)(82740400003)(36906005)(26005); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 01:58:55.7769 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 6e12ab0d-edaf-4c4f-77ed-08d914e98021 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch02.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT054.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW2PR02MB3692 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Contains common code for all root drivers and handles root calls from xrt drivers. This is part of root driver infrastructure. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/events.h | 45 +++ drivers/fpga/xrt/include/xroot.h | 117 +++++++ drivers/fpga/xrt/lib/subdev_pool.h | 53 +++ drivers/fpga/xrt/lib/xroot.c | 536 +++++++++++++++++++++++++++++ 4 files changed, 751 insertions(+) create mode 100644 drivers/fpga/xrt/include/events.h create mode 100644 drivers/fpga/xrt/include/xroot.h create mode 100644 drivers/fpga/xrt/lib/subdev_pool.h create mode 100644 drivers/fpga/xrt/lib/xroot.c diff --git a/drivers/fpga/xrt/include/events.h b/drivers/fpga/xrt/include/events.h new file mode 100644 index 000000000000..775171a47c8e --- /dev/null +++ b/drivers/fpga/xrt/include/events.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_EVENTS_H_ +#define _XRT_EVENTS_H_ + +#include "subdev_id.h" + +/* + * Event notification. + */ +enum xrt_events { + XRT_EVENT_TEST = 0, /* for testing */ + /* + * Events related to specific subdev + * Callback arg: struct xrt_event_arg_subdev + */ + XRT_EVENT_POST_CREATION, + XRT_EVENT_PRE_REMOVAL, + /* + * Events related to change of the whole board + * Callback arg: + */ + XRT_EVENT_PRE_HOT_RESET, + XRT_EVENT_POST_HOT_RESET, + XRT_EVENT_PRE_GATE_CLOSE, + XRT_EVENT_POST_GATE_OPEN, +}; + +struct xrt_event_arg_subdev { + enum xrt_subdev_id xevt_subdev_id; + int xevt_subdev_instance; +}; + +struct xrt_event { + enum xrt_events xe_evt; + struct xrt_event_arg_subdev xe_subdev; +}; + +#endif /* _XRT_EVENTS_H_ */ diff --git a/drivers/fpga/xrt/include/xroot.h b/drivers/fpga/xrt/include/xroot.h new file mode 100644 index 000000000000..56461bcb07a9 --- /dev/null +++ b/drivers/fpga/xrt/include/xroot.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_ROOT_H_ +#define _XRT_ROOT_H_ + +#include "xdevice.h" +#include "subdev_id.h" +#include "events.h" + +typedef bool (*xrt_subdev_match_t)(enum xrt_subdev_id, struct xrt_device *, void *); +#define XRT_SUBDEV_MATCH_PREV ((xrt_subdev_match_t)-1) +#define XRT_SUBDEV_MATCH_NEXT ((xrt_subdev_match_t)-2) + +/* + * Root calls. + */ +enum xrt_root_cmd { + /* Leaf actions. */ + XRT_ROOT_GET_LEAF = 0, + XRT_ROOT_PUT_LEAF, + XRT_ROOT_GET_LEAF_HOLDERS, + + /* Group actions. */ + XRT_ROOT_CREATE_GROUP, + XRT_ROOT_REMOVE_GROUP, + XRT_ROOT_LOOKUP_GROUP, + XRT_ROOT_WAIT_GROUP_BRINGUP, + + /* Event actions. */ + XRT_ROOT_EVENT_SYNC, + XRT_ROOT_EVENT_ASYNC, + + /* Device info. */ + XRT_ROOT_GET_RESOURCE, + XRT_ROOT_GET_ID, + + /* Misc. */ + XRT_ROOT_HOT_RESET, + XRT_ROOT_HWMON, +}; + +struct xrt_root_get_leaf { + struct xrt_device *xpigl_caller_xdev; + xrt_subdev_match_t xpigl_match_cb; + void *xpigl_match_arg; + struct xrt_device *xpigl_tgt_xdev; +}; + +struct xrt_root_put_leaf { + struct xrt_device *xpipl_caller_xdev; + struct xrt_device *xpipl_tgt_xdev; +}; + +struct xrt_root_lookup_group { + struct xrt_device *xpilp_xdev; /* caller's xdev */ + xrt_subdev_match_t xpilp_match_cb; + void *xpilp_match_arg; + int xpilp_grp_inst; +}; + +struct xrt_root_get_holders { + struct xrt_device *xpigh_xdev; /* caller's xdev */ + char *xpigh_holder_buf; + size_t xpigh_holder_buf_len; +}; + +struct xrt_root_get_res { + u32 xpigr_region_id; + struct resource *xpigr_res; +}; + +struct xrt_root_get_id { + unsigned short xpigi_vendor_id; + unsigned short xpigi_device_id; + unsigned short xpigi_sub_vendor_id; + unsigned short xpigi_sub_device_id; +}; + +struct xrt_root_hwmon { + bool xpih_register; + const char *xpih_name; + void *xpih_drvdata; + const struct attribute_group **xpih_groups; + struct device *xpih_hwmon_dev; +}; + +/* + * Callback for leaf to make a root request. Arguments are: parent device, parent cookie, req, + * and arg. + */ +typedef int (*xrt_subdev_root_cb_t)(struct device *, void *, u32, void *); +int xrt_subdev_root_request(struct xrt_device *self, u32 cmd, void *arg); + +/* + * Defines physical function (MPF / UPF) specific operations + * needed in common root driver. + */ +struct xroot_physical_function_callback { + void (*xpc_get_id)(struct device *dev, struct xrt_root_get_id *rid); + int (*xpc_get_resource)(struct device *dev, struct xrt_root_get_res *res); + void (*xpc_hot_reset)(struct device *dev); +}; + +int xroot_probe(struct device *dev, struct xroot_physical_function_callback *cb, void **root); +void xroot_remove(void *root); +bool xroot_wait_for_bringup(void *root); +int xroot_create_group(void *xr, char *dtb); +int xroot_add_simple_node(void *root, char *dtb, const char *endpoint); +void xroot_broadcast(void *root, enum xrt_events evt); + +#endif /* _XRT_ROOT_H_ */ diff --git a/drivers/fpga/xrt/lib/subdev_pool.h b/drivers/fpga/xrt/lib/subdev_pool.h new file mode 100644 index 000000000000..03f617d7ffd7 --- /dev/null +++ b/drivers/fpga/xrt/lib/subdev_pool.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_SUBDEV_POOL_H_ +#define _XRT_SUBDEV_POOL_H_ + +#include +#include +#include "xroot.h" + +/* + * The struct xrt_subdev_pool manages a list of xrt_subdevs for root and group drivers. + */ +struct xrt_subdev_pool { + struct list_head xsp_dev_list; + struct device *xsp_owner; + struct mutex xsp_lock; /* pool lock */ + bool xsp_closing; +}; + +/* + * Subdev pool helper functions for root and group drivers only. + */ +void xrt_subdev_pool_init(struct device *dev, + struct xrt_subdev_pool *spool); +void xrt_subdev_pool_fini(struct xrt_subdev_pool *spool); +int xrt_subdev_pool_get(struct xrt_subdev_pool *spool, + xrt_subdev_match_t match, + void *arg, struct device *holder_dev, + struct xrt_device **xdevp); +int xrt_subdev_pool_put(struct xrt_subdev_pool *spool, + struct xrt_device *xdev, + struct device *holder_dev); +int xrt_subdev_pool_add(struct xrt_subdev_pool *spool, + enum xrt_subdev_id id, xrt_subdev_root_cb_t pcb, + void *pcb_arg, char *dtb); +int xrt_subdev_pool_del(struct xrt_subdev_pool *spool, + enum xrt_subdev_id id, int instance); +ssize_t xrt_subdev_pool_get_holders(struct xrt_subdev_pool *spool, + struct xrt_device *xdev, + char *buf, size_t len); + +void xrt_subdev_pool_trigger_event(struct xrt_subdev_pool *spool, + enum xrt_events evt); +void xrt_subdev_pool_handle_event(struct xrt_subdev_pool *spool, + struct xrt_event *evt); + +#endif /* _XRT_SUBDEV_POOL_H_ */ diff --git a/drivers/fpga/xrt/lib/xroot.c b/drivers/fpga/xrt/lib/xroot.c new file mode 100644 index 000000000000..7b3e540dd6c0 --- /dev/null +++ b/drivers/fpga/xrt/lib/xroot.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Root Functions + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include +#include "xroot.h" +#include "subdev_pool.h" +#include "group.h" +#include "metadata.h" + +#define xroot_err(xr, fmt, args...) dev_err((xr)->dev, "%s: " fmt, __func__, ##args) +#define xroot_warn(xr, fmt, args...) dev_warn((xr)->dev, "%s: " fmt, __func__, ##args) +#define xroot_info(xr, fmt, args...) dev_info((xr)->dev, "%s: " fmt, __func__, ##args) +#define xroot_dbg(xr, fmt, args...) dev_dbg((xr)->dev, "%s: " fmt, __func__, ##args) + +#define XROOT_GROUP_FIRST (-1) +#define XROOT_GROUP_LAST (-2) + +static int xroot_root_cb(struct device *, void *, u32, void *); + +struct xroot_evt { + struct list_head list; + struct xrt_event evt; + struct completion comp; + bool async; +}; + +struct xroot_events { + struct mutex evt_lock; /* event lock */ + struct list_head evt_list; + struct work_struct evt_work; +}; + +struct xroot_groups { + struct xrt_subdev_pool pool; + struct work_struct bringup_work; + atomic_t bringup_pending_cnt; + atomic_t bringup_failed_cnt; + struct completion bringup_comp; +}; + +struct xroot { + struct device *dev; + struct xroot_events events; + struct xroot_groups groups; + struct xroot_physical_function_callback pf_cb; +}; + +struct xroot_group_match_arg { + enum xrt_subdev_id id; + int instance; +}; + +static bool xroot_group_match(enum xrt_subdev_id id, struct xrt_device *xdev, void *arg) +{ + struct xroot_group_match_arg *a = (struct xroot_group_match_arg *)arg; + + /* xdev->instance is the instance of the subdev. */ + return id == a->id && xdev->instance == a->instance; +} + +static int xroot_get_group(struct xroot *xr, int instance, struct xrt_device **grpp) +{ + int rc = 0; + struct xrt_subdev_pool *grps = &xr->groups.pool; + struct device *dev = xr->dev; + struct xroot_group_match_arg arg = { XRT_SUBDEV_GRP, instance }; + + if (instance == XROOT_GROUP_LAST) { + rc = xrt_subdev_pool_get(grps, XRT_SUBDEV_MATCH_NEXT, + *grpp, dev, grpp); + } else if (instance == XROOT_GROUP_FIRST) { + rc = xrt_subdev_pool_get(grps, XRT_SUBDEV_MATCH_PREV, + *grpp, dev, grpp); + } else { + rc = xrt_subdev_pool_get(grps, xroot_group_match, + &arg, dev, grpp); + } + + if (rc && rc != -ENOENT) + xroot_err(xr, "failed to hold group %d: %d", instance, rc); + return rc; +} + +static void xroot_put_group(struct xroot *xr, struct xrt_device *grp) +{ + int inst = grp->instance; + int rc = xrt_subdev_pool_put(&xr->groups.pool, grp, xr->dev); + + if (rc) + xroot_err(xr, "failed to release group %d: %d", inst, rc); +} + +static int xroot_trigger_event(struct xroot *xr, struct xrt_event *e, bool async) +{ + struct xroot_evt *enew = vzalloc(sizeof(*enew)); + + if (!enew) + return -ENOMEM; + + enew->evt = *e; + enew->async = async; + init_completion(&enew->comp); + + mutex_lock(&xr->events.evt_lock); + list_add(&enew->list, &xr->events.evt_list); + mutex_unlock(&xr->events.evt_lock); + + schedule_work(&xr->events.evt_work); + + if (async) + return 0; + + wait_for_completion(&enew->comp); + vfree(enew); + return 0; +} + +static void +xroot_group_trigger_event(struct xroot *xr, int inst, enum xrt_events e) +{ + int ret; + struct xrt_device *xdev = NULL; + struct xrt_event evt = { 0 }; + + WARN_ON(inst < 0); + /* Only triggers subdev specific events. */ + if (e != XRT_EVENT_POST_CREATION && e != XRT_EVENT_PRE_REMOVAL) { + xroot_err(xr, "invalid event %d", e); + return; + } + + ret = xroot_get_group(xr, inst, &xdev); + if (ret) + return; + + /* Triggers event for children, first. */ + xleaf_call(xdev, XRT_GROUP_TRIGGER_EVENT, (void *)(uintptr_t)e); + + /* Triggers event for itself. */ + evt.xe_evt = e; + evt.xe_subdev.xevt_subdev_id = XRT_SUBDEV_GRP; + evt.xe_subdev.xevt_subdev_instance = inst; + xroot_trigger_event(xr, &evt, false); + + xroot_put_group(xr, xdev); +} + +int xroot_create_group(void *root, char *dtb) +{ + struct xroot *xr = (struct xroot *)root; + int ret; + + atomic_inc(&xr->groups.bringup_pending_cnt); + ret = xrt_subdev_pool_add(&xr->groups.pool, XRT_SUBDEV_GRP, xroot_root_cb, xr, dtb); + if (ret >= 0) { + schedule_work(&xr->groups.bringup_work); + } else { + atomic_dec(&xr->groups.bringup_pending_cnt); + atomic_inc(&xr->groups.bringup_failed_cnt); + xroot_err(xr, "failed to create group: %d", ret); + } + return ret; +} +EXPORT_SYMBOL_GPL(xroot_create_group); + +static int xroot_destroy_single_group(struct xroot *xr, int instance) +{ + struct xrt_device *xdev = NULL; + int ret; + + WARN_ON(instance < 0); + ret = xroot_get_group(xr, instance, &xdev); + if (ret) + return ret; + + xroot_group_trigger_event(xr, instance, XRT_EVENT_PRE_REMOVAL); + + /* Now tear down all children in this group. */ + ret = xleaf_call(xdev, XRT_GROUP_FINI_CHILDREN, NULL); + xroot_put_group(xr, xdev); + if (!ret) + ret = xrt_subdev_pool_del(&xr->groups.pool, XRT_SUBDEV_GRP, instance); + + return ret; +} + +static int xroot_destroy_group(struct xroot *xr, int instance) +{ + struct xrt_device *target = NULL; + struct xrt_device *deps = NULL; + int ret; + + WARN_ON(instance < 0); + /* + * Make sure target group exists and can't go away before + * we remove it's dependents + */ + ret = xroot_get_group(xr, instance, &target); + if (ret) + return ret; + + /* + * Remove all groups depend on target one. + * Assuming subdevs in higher group ID can depend on ones in + * lower ID groups, we remove them in the reservse order. + */ + while (xroot_get_group(xr, XROOT_GROUP_LAST, &deps) != -ENOENT) { + int inst = deps->instance; + + xroot_put_group(xr, deps); + /* Reached the target group instance, stop here. */ + if (instance == inst) + break; + xroot_destroy_single_group(xr, inst); + deps = NULL; + } + + /* Now we can remove the target group. */ + xroot_put_group(xr, target); + return xroot_destroy_single_group(xr, instance); +} + +static int xroot_lookup_group(struct xroot *xr, + struct xrt_root_lookup_group *arg) +{ + int rc = -ENOENT; + struct xrt_device *grp = NULL; + + while (rc < 0 && xroot_get_group(xr, XROOT_GROUP_LAST, &grp) != -ENOENT) { + if (arg->xpilp_match_cb(XRT_SUBDEV_GRP, grp, arg->xpilp_match_arg)) + rc = grp->instance; + xroot_put_group(xr, grp); + } + return rc; +} + +static void xroot_event_work(struct work_struct *work) +{ + struct xroot_evt *tmp; + struct xroot *xr = container_of(work, struct xroot, events.evt_work); + + mutex_lock(&xr->events.evt_lock); + while (!list_empty(&xr->events.evt_list)) { + tmp = list_first_entry(&xr->events.evt_list, struct xroot_evt, list); + list_del(&tmp->list); + mutex_unlock(&xr->events.evt_lock); + + xrt_subdev_pool_handle_event(&xr->groups.pool, &tmp->evt); + + if (tmp->async) + vfree(tmp); + else + complete(&tmp->comp); + + mutex_lock(&xr->events.evt_lock); + } + mutex_unlock(&xr->events.evt_lock); +} + +static void xroot_event_init(struct xroot *xr) +{ + INIT_LIST_HEAD(&xr->events.evt_list); + mutex_init(&xr->events.evt_lock); + INIT_WORK(&xr->events.evt_work, xroot_event_work); +} + +static void xroot_event_fini(struct xroot *xr) +{ + flush_scheduled_work(); + WARN_ON(!list_empty(&xr->events.evt_list)); +} + +static int xroot_get_leaf(struct xroot *xr, struct xrt_root_get_leaf *arg) +{ + int rc = -ENOENT; + struct xrt_device *grp = NULL; + + while (rc && xroot_get_group(xr, XROOT_GROUP_LAST, &grp) != -ENOENT) { + rc = xleaf_call(grp, XRT_GROUP_GET_LEAF, arg); + xroot_put_group(xr, grp); + } + return rc; +} + +static int xroot_put_leaf(struct xroot *xr, struct xrt_root_put_leaf *arg) +{ + int rc = -ENOENT; + struct xrt_device *grp = NULL; + + while (rc && xroot_get_group(xr, XROOT_GROUP_LAST, &grp) != -ENOENT) { + rc = xleaf_call(grp, XRT_GROUP_PUT_LEAF, arg); + xroot_put_group(xr, grp); + } + return rc; +} + +static int xroot_root_cb(struct device *dev, void *parg, enum xrt_root_cmd cmd, void *arg) +{ + struct xroot *xr = (struct xroot *)parg; + int rc = 0; + + switch (cmd) { + /* Leaf actions. */ + case XRT_ROOT_GET_LEAF: { + struct xrt_root_get_leaf *getleaf = (struct xrt_root_get_leaf *)arg; + + rc = xroot_get_leaf(xr, getleaf); + break; + } + case XRT_ROOT_PUT_LEAF: { + struct xrt_root_put_leaf *putleaf = (struct xrt_root_put_leaf *)arg; + + rc = xroot_put_leaf(xr, putleaf); + break; + } + case XRT_ROOT_GET_LEAF_HOLDERS: { + struct xrt_root_get_holders *holders = (struct xrt_root_get_holders *)arg; + + rc = xrt_subdev_pool_get_holders(&xr->groups.pool, + holders->xpigh_xdev, + holders->xpigh_holder_buf, + holders->xpigh_holder_buf_len); + break; + } + + /* Group actions. */ + case XRT_ROOT_CREATE_GROUP: + rc = xroot_create_group(xr, (char *)arg); + break; + case XRT_ROOT_REMOVE_GROUP: + rc = xroot_destroy_group(xr, (int)(uintptr_t)arg); + break; + case XRT_ROOT_LOOKUP_GROUP: { + struct xrt_root_lookup_group *getgrp = (struct xrt_root_lookup_group *)arg; + + rc = xroot_lookup_group(xr, getgrp); + break; + } + case XRT_ROOT_WAIT_GROUP_BRINGUP: + rc = xroot_wait_for_bringup(xr) ? 0 : -EINVAL; + break; + + /* Event actions. */ + case XRT_ROOT_EVENT_SYNC: + case XRT_ROOT_EVENT_ASYNC: { + bool async = (cmd == XRT_ROOT_EVENT_ASYNC); + struct xrt_event *evt = (struct xrt_event *)arg; + + rc = xroot_trigger_event(xr, evt, async); + break; + } + + /* Device info. */ + case XRT_ROOT_GET_RESOURCE: { + struct xrt_root_get_res *res = (struct xrt_root_get_res *)arg; + + if (xr->pf_cb.xpc_get_resource) { + rc = xr->pf_cb.xpc_get_resource(xr->dev, res); + } else { + xroot_err(xr, "get resource is not supported"); + rc = -EOPNOTSUPP; + } + break; + } + case XRT_ROOT_GET_ID: { + struct xrt_root_get_id *id = (struct xrt_root_get_id *)arg; + + if (xr->pf_cb.xpc_get_id) + xr->pf_cb.xpc_get_id(xr->dev, id); + else + memset(id, 0, sizeof(*id)); + break; + } + + /* MISC generic root driver functions. */ + case XRT_ROOT_HOT_RESET: { + if (xr->pf_cb.xpc_hot_reset) { + xr->pf_cb.xpc_hot_reset(xr->dev); + } else { + xroot_err(xr, "hot reset is not supported"); + rc = -EOPNOTSUPP; + } + break; + } + case XRT_ROOT_HWMON: { + struct xrt_root_hwmon *hwmon = (struct xrt_root_hwmon *)arg; + + if (hwmon->xpih_register) { + hwmon->xpih_hwmon_dev = + hwmon_device_register_with_info(xr->dev, + hwmon->xpih_name, + hwmon->xpih_drvdata, + NULL, + hwmon->xpih_groups); + } else { + hwmon_device_unregister(hwmon->xpih_hwmon_dev); + } + break; + } + + default: + xroot_err(xr, "unknown IOCTL cmd %d", cmd); + rc = -EINVAL; + break; + } + + return rc; +} + +static void xroot_bringup_group_work(struct work_struct *work) +{ + struct xrt_device *xdev = NULL; + struct xroot *xr = container_of(work, struct xroot, groups.bringup_work); + + while (xroot_get_group(xr, XROOT_GROUP_FIRST, &xdev) != -ENOENT) { + int r, i; + + i = xdev->instance; + r = xleaf_call(xdev, XRT_GROUP_INIT_CHILDREN, NULL); + xroot_put_group(xr, xdev); + if (r == -EEXIST) + continue; /* Already brough up, nothing to do. */ + if (r) + atomic_inc(&xr->groups.bringup_failed_cnt); + + xroot_group_trigger_event(xr, i, XRT_EVENT_POST_CREATION); + + if (atomic_dec_and_test(&xr->groups.bringup_pending_cnt)) + complete(&xr->groups.bringup_comp); + } +} + +static void xroot_groups_init(struct xroot *xr) +{ + xrt_subdev_pool_init(xr->dev, &xr->groups.pool); + INIT_WORK(&xr->groups.bringup_work, xroot_bringup_group_work); + atomic_set(&xr->groups.bringup_pending_cnt, 0); + atomic_set(&xr->groups.bringup_failed_cnt, 0); + init_completion(&xr->groups.bringup_comp); +} + +static void xroot_groups_fini(struct xroot *xr) +{ + flush_scheduled_work(); + xrt_subdev_pool_fini(&xr->groups.pool); +} + +int xroot_add_simple_node(void *root, char *dtb, const char *endpoint) +{ + struct xroot *xr = (struct xroot *)root; + struct device *dev = xr->dev; + struct xrt_md_endpoint ep = { 0 }; + int ret = 0; + + ep.ep_name = endpoint; + ret = xrt_md_add_endpoint(dev, dtb, &ep); + if (ret) + xroot_err(xr, "add %s failed, ret %d", endpoint, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xroot_add_simple_node); + +bool xroot_wait_for_bringup(void *root) +{ + struct xroot *xr = (struct xroot *)root; + + wait_for_completion(&xr->groups.bringup_comp); + return atomic_read(&xr->groups.bringup_failed_cnt) == 0; +} +EXPORT_SYMBOL_GPL(xroot_wait_for_bringup); + +int xroot_probe(struct device *dev, struct xroot_physical_function_callback *cb, void **root) +{ + struct xroot *xr = NULL; + + dev_info(dev, "%s: probing...", __func__); + + xr = devm_kzalloc(dev, sizeof(*xr), GFP_KERNEL); + if (!xr) + return -ENOMEM; + + xr->dev = dev; + xr->pf_cb = *cb; + xroot_groups_init(xr); + xroot_event_init(xr); + + *root = xr; + return 0; +} +EXPORT_SYMBOL_GPL(xroot_probe); + +void xroot_remove(void *root) +{ + struct xroot *xr = (struct xroot *)root; + struct xrt_device *grp = NULL; + + xroot_info(xr, "leaving..."); + + if (xroot_get_group(xr, XROOT_GROUP_FIRST, &grp) == 0) { + int instance = grp->instance; + + xroot_put_group(xr, grp); + xroot_destroy_group(xr, instance); + } + + xroot_event_fini(xr); + xroot_groups_fini(xr); +} +EXPORT_SYMBOL_GPL(xroot_remove); + +void xroot_broadcast(void *root, enum xrt_events evt) +{ + struct xroot *xr = (struct xroot *)root; + struct xrt_event e = { 0 }; + + /* Root pf driver only broadcasts below two events. */ + if (evt != XRT_EVENT_POST_CREATION && evt != XRT_EVENT_PRE_REMOVAL) { + xroot_info(xr, "invalid event %d", evt); + return; + } + + e.xe_evt = evt; + e.xe_subdev.xevt_subdev_id = XRT_ROOT; + e.xe_subdev.xevt_subdev_instance = 0; + xroot_trigger_event(xr, &e, false); +} +EXPORT_SYMBOL_GPL(xroot_broadcast); From patchwork Wed May 12 01:53:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435841 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2998C433ED for ; Wed, 12 May 2021 01:59:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B84B96192C for ; Wed, 12 May 2021 01:59:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229848AbhELCAZ (ORCPT ); Tue, 11 May 2021 22:00:25 -0400 Received: from mail-dm6nam11on2046.outbound.protection.outlook.com ([40.107.223.46]:56033 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230196AbhELCAX (ORCPT ); Tue, 11 May 2021 22:00:23 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=aHaWq8hpBPAPHM30Qk7ekbnzZ9C7OGjCqSDtcq6FS8Q9BdNGm5yjyVzhYmj06Iopz+szL0choBnKhBiU2KAUtvxX3Tv0sE3bWlbhWNnxBDnZjGyyT+zR9PoYkCfkAjGYVGXo9FzTGZBzj2xkh2iO1nmf6v3ODY+vNOyu/6VCY0Zp20iuwRNzhoboS1bSqhc+E2dWxrVk/Y9xW3qSojCWyBioNzYE8pVBv2qOyPuhhZWXSz5X5mqEZFnq+sG7jbcvBuc7hFIgB2Dwo9kpIS3/kXeBIRYu+Oe1t+QBor3nm/uo3pV4yNtaECtdIoz4+QxfpK/uUAZPJsdhG1PX9qhLeQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Qf3UZzc72eCQiDdDldm1ViikonO6NLeCIrav8se8DFI=; b=lKq5De/15qGl51VX1c1TeGVHR616iSJ4pMS5havoB3LfIKfB/W8mLWa3qByEUTtdwRhWBwtuWBP06xvMtOtu3BeIgkw8xiAB5ThR5g/UIhp4MnNvhsTEtbQ3Ggj/yP8bBah87/o+48Wwd2cwWTqAf8rZji623cNK8ig4Rjyd+TDwd83GI08/BwoexZjoOuYCHVeBIU2E52KSx2ZYS+VPLj0vsko3Hd0k2AH2/8YuUZK9dPY8I96wnr1eZi3f9iLtqnuNvI0g4k5fbzttcoFCbmY3St6yZkqjsFwpRbAnNOTYFFNm1WTsMj2XBn4Z3k0mLF1NJ95gARe7C1gaBCoX5Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Qf3UZzc72eCQiDdDldm1ViikonO6NLeCIrav8se8DFI=; b=HhNCGnoexkdfqU+AkzIextlXNLS0NyVB7jynvDi8F6nny1CSZDNUxhfC6sQkaloZkG83e60rVnERgMdNTMmq48kBHTZsaU4zfWHkpJAqqFtIK4UMXb+tyDT84NWGLDXJ/selgCzPUBz1oj8HSff538ODj2UOTTblpAB7hkxtqzc= Received: from BN0PR04CA0193.namprd04.prod.outlook.com (2603:10b6:408:e9::18) by CO6PR02MB7540.namprd02.prod.outlook.com (2603:10b6:303:b1::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4129.25; Wed, 12 May 2021 01:59:14 +0000 Received: from BN1NAM02FT046.eop-nam02.prod.protection.outlook.com (2603:10b6:408:e9:cafe::f8) by BN0PR04CA0193.outlook.office365.com (2603:10b6:408:e9::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.24 via Frontend Transport; Wed, 12 May 2021 01:59:14 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch02.xlnx.xilinx.com; Received: from xsj-pvapexch02.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT046.mail.protection.outlook.com (10.13.3.181) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 01:59:14 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:59:07 -0700 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:59:07 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35730 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lge9T-0001bV-75; Tue, 11 May 2021 18:59:07 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 6D07460012E; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 09/20] fpga: xrt: management physical function driver (root) Date: Tue, 11 May 2021 18:53:28 -0700 Message-ID: <20210512015339.5649-10-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ca1afed2-1f7e-46d8-729f-08d914e98b17 X-MS-TrafficTypeDiagnostic: CO6PR02MB7540: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:326; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: aZs3dwfd4Ur8uX4OzEE/Y/5sBZkimVosaxUSlUon99z6cga1V3tfFs4CM4cFvxnNNVHopjNJxcEiU56NISvnxmYNfVRpQ1yvnJIvMuZz6h6hb0G9M2S9gnFzFIzA0OtOiA9K4jt2AZTVP/ABqSd8vDbTdIRwTxycsdO6O/JQKbDnvtoIR0p2Rpm8DH4NDrMur2vIIBOaL8uRSJwpQ/a0KigaoGSpXnl6/xMLMh3IMHrhdl8kOtUkUFmxT1VpZuchAVALsvmv0vYOjK2zXnHlcaioedSrMW2QTY9EvPzv0LqSP+sIxRo11wtFtX2FwssErniy34SBVDoV4ji16Ynt8eeI2/9ORaj8LaYfFTZxhTf2Odih19Rms1bGdohB0TqxIUuzAD4KhsnFIFxPkJXFHr732dhRd5IBGCcW0wELmDgKXNy1g03RBKF+oSebhujk6Myafj2ULVeVIxl77CjP5GRqXXf1hQNz7VLKtDerKzJnKMNx/+vriAHG5H0ve9ImSxLPrdPRSoY2XBiqbBNKDVCUZGyzhfg/k1muR1b1Xs7aDxDhLe74sudjlPaxNffrK/lNDYyutjV2RgIR+75ocDlFtK6pKaZ9rURCPPugjGXj4RYirYqbIp77aDlmm/UBe8bYz22vYsPnMv1lfWqNyWDhNuQ+bV/OrV1ruySG7dE= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(136003)(346002)(376002)(396003)(39860400002)(46966006)(36840700001)(42186006)(316002)(83380400001)(36906005)(1076003)(54906003)(6666004)(6916009)(107886003)(44832011)(7636003)(36756003)(82310400003)(356005)(82740400003)(30864003)(426003)(478600001)(336012)(2616005)(2906002)(186003)(26005)(36860700001)(5660300002)(8676002)(8936002)(6266002)(70586007)(70206006)(4326008)(47076005); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 01:59:14.1731 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ca1afed2-1f7e-46d8-729f-08d914e98b17 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch02.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT046.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR02MB7540 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The PCIE device driver which attaches to management function on Alveo devices. It instantiates one or more group drivers which, in turn, instantiate xrt drivers. The instantiation of group and xrt drivers is completely dtb driven. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/mgmt/root.c | 420 +++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 drivers/fpga/xrt/mgmt/root.c diff --git a/drivers/fpga/xrt/mgmt/root.c b/drivers/fpga/xrt/mgmt/root.c new file mode 100644 index 000000000000..9f3c806a9eaa --- /dev/null +++ b/drivers/fpga/xrt/mgmt/root.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo Management Function Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include +#include +#include +#include + +#include "xroot.h" +#include "xmgmt.h" +#include "metadata.h" + +#define XMGMT_MODULE_NAME "xrt-mgmt" +#define XMGMT_DRIVER_VERSION "4.0.0" + +#define XMGMT_PDEV(xm) ((xm)->pdev) +#define XMGMT_DEV(xm) (&(XMGMT_PDEV(xm)->dev)) +#define xmgmt_err(xm, fmt, args...) \ + dev_err(XMGMT_DEV(xm), "%s: " fmt, __func__, ##args) +#define xmgmt_warn(xm, fmt, args...) \ + dev_warn(XMGMT_DEV(xm), "%s: " fmt, __func__, ##args) +#define xmgmt_info(xm, fmt, args...) \ + dev_info(XMGMT_DEV(xm), "%s: " fmt, __func__, ##args) +#define xmgmt_dbg(xm, fmt, args...) \ + dev_dbg(XMGMT_DEV(xm), "%s: " fmt, __func__, ##args) +#define XMGMT_DEV_ID(_pcidev) \ + ({ typeof(_pcidev) (pcidev) = (_pcidev); \ + ((pci_domain_nr((pcidev)->bus) << 16) | \ + PCI_DEVID((pcidev)->bus->number, 0)); }) +#define XRT_VSEC_ID 0x20 +#define XRT_MAX_READRQ 512 + +static struct class *xmgmt_class; + +/* PCI Device IDs */ +/* + * Golden image is preloaded on the device when it is shipped to customer. + * Then, customer can load other shells (from Xilinx or some other vendor). + * If something goes wrong with the shell, customer can always go back to + * golden and start over again. + */ +#define PCI_DEVICE_ID_U50_GOLDEN 0xD020 +#define PCI_DEVICE_ID_U50 0x5020 +static const struct pci_device_id xmgmt_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_U50_GOLDEN), }, /* Alveo U50 (golden) */ + { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_U50), }, /* Alveo U50 */ + { 0, } +}; + +struct xmgmt { + struct pci_dev *pdev; + void *root; + + bool ready; +}; + +static int xmgmt_config_pci(struct xmgmt *xm) +{ + struct pci_dev *pdev = XMGMT_PDEV(xm); + int rc; + + rc = pcim_enable_device(pdev); + if (rc < 0) { + xmgmt_err(xm, "failed to enable device: %d", rc); + return rc; + } + + rc = pci_enable_pcie_error_reporting(pdev); + if (rc) + xmgmt_warn(xm, "failed to enable AER: %d", rc); + + pci_set_master(pdev); + + rc = pcie_get_readrq(pdev); + if (rc > XRT_MAX_READRQ) + pcie_set_readrq(pdev, XRT_MAX_READRQ); + return 0; +} + +static int xmgmt_match_slot_and_save(struct device *dev, void *data) +{ + struct xmgmt *xm = data; + struct pci_dev *pdev = to_pci_dev(dev); + + if (XMGMT_DEV_ID(pdev) == XMGMT_DEV_ID(xm->pdev)) { + pci_cfg_access_lock(pdev); + pci_save_state(pdev); + } + + return 0; +} + +static void xmgmt_pci_save_config_all(struct xmgmt *xm) +{ + bus_for_each_dev(&pci_bus_type, NULL, xm, xmgmt_match_slot_and_save); +} + +static int xmgmt_match_slot_and_restore(struct device *dev, void *data) +{ + struct xmgmt *xm = data; + struct pci_dev *pdev = to_pci_dev(dev); + + if (XMGMT_DEV_ID(pdev) == XMGMT_DEV_ID(xm->pdev)) { + pci_restore_state(pdev); + pci_cfg_access_unlock(pdev); + } + + return 0; +} + +static void xmgmt_pci_restore_config_all(struct xmgmt *xm) +{ + bus_for_each_dev(&pci_bus_type, NULL, xm, xmgmt_match_slot_and_restore); +} + +static void xmgmt_root_hot_reset(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *bus; + u16 pci_cmd, devctl; + struct xmgmt *xm; + u8 pci_bctl; + int i, ret; + + xm = pci_get_drvdata(pdev); + xmgmt_info(xm, "hot reset start"); + xmgmt_pci_save_config_all(xm); + pci_disable_device(pdev); + bus = pdev->bus; + + /* + * When flipping the SBR bit, device can fall off the bus. This is + * usually no problem at all so long as drivers are working properly + * after SBR. However, some systems complain bitterly when the device + * falls off the bus. + * The quick solution is to temporarily disable the SERR reporting of + * switch port during SBR. + */ + + pci_read_config_word(bus->self, PCI_COMMAND, &pci_cmd); + pci_write_config_word(bus->self, PCI_COMMAND, (pci_cmd & ~PCI_COMMAND_SERR)); + pcie_capability_read_word(bus->self, PCI_EXP_DEVCTL, &devctl); + pcie_capability_write_word(bus->self, PCI_EXP_DEVCTL, (devctl & ~PCI_EXP_DEVCTL_FERE)); + pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl); + pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl | PCI_BRIDGE_CTL_BUS_RESET); + msleep(100); + pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); + ssleep(1); + + pcie_capability_write_word(bus->self, PCI_EXP_DEVCTL, devctl); + pci_write_config_word(bus->self, PCI_COMMAND, pci_cmd); + + ret = pci_enable_device(pdev); + if (ret) + xmgmt_err(xm, "failed to enable device, ret %d", ret); + + for (i = 0; i < 300; i++) { + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + if (pci_cmd != 0xffff) + break; + msleep(20); + } + if (i == 300) + xmgmt_err(xm, "timed out waiting for device to be online after reset"); + + xmgmt_info(xm, "waiting for %d ms", i * 20); + xmgmt_pci_restore_config_all(xm); + xmgmt_config_pci(xm); +} + +static int xmgmt_add_vsec_node(struct xmgmt *xm, char *dtb) +{ + struct pci_dev *pdev = XMGMT_PDEV(xm); + struct xrt_md_endpoint ep = { 0 }; + struct device *dev = DEV(pdev); + u32 off_low, off_high, header; + int cap = 0, ret = 0; + __be32 vsec_bar; + __be64 vsec_off; + + while ((cap = pci_find_next_ext_capability(pdev, cap, PCI_EXT_CAP_ID_VNDR))) { + pci_read_config_dword(pdev, cap + PCI_VNDR_HEADER, &header); + if (PCI_VNDR_HEADER_ID(header) == XRT_VSEC_ID) + break; + } + if (!cap) { + xmgmt_info(xm, "No Vendor Specific Capability."); + return -ENOENT; + } + + if (pci_read_config_dword(pdev, cap + 8, &off_low) || + pci_read_config_dword(pdev, cap + 12, &off_high)) { + xmgmt_err(xm, "pci_read vendor specific failed."); + return -EINVAL; + } + + ep.ep_name = XRT_MD_NODE_VSEC; + ret = xrt_md_add_endpoint(dev, dtb, &ep); + if (ret) { + xmgmt_err(xm, "add vsec metadata failed, ret %d", ret); + goto failed; + } + + vsec_bar = cpu_to_be32(off_low & 0xf); + ret = xrt_md_set_prop(dev, dtb, XRT_MD_NODE_VSEC, NULL, + XRT_MD_PROP_BAR_IDX, &vsec_bar, sizeof(vsec_bar)); + if (ret) { + xmgmt_err(xm, "add vsec bar idx failed, ret %d", ret); + goto failed; + } + + vsec_off = cpu_to_be64(((u64)off_high << 32) | (off_low & ~0xfU)); + ret = xrt_md_set_prop(dev, dtb, XRT_MD_NODE_VSEC, NULL, + XRT_MD_PROP_OFFSET, &vsec_off, sizeof(vsec_off)); + if (ret) { + xmgmt_err(xm, "add vsec offset failed, ret %d", ret); + goto failed; + } + +failed: + return ret; +} + +static int xmgmt_create_root_metadata(struct xmgmt *xm, char **root_dtb) +{ + char *dtb = NULL; + int ret; + + ret = xrt_md_create(XMGMT_DEV(xm), &dtb); + if (ret) { + xmgmt_err(xm, "create metadata failed, ret %d", ret); + goto failed; + } + + ret = xmgmt_add_vsec_node(xm, dtb); + if (ret == -ENOENT) { + /* + * We may be dealing with a MFG board. + * Try vsec-golden which will bring up all hard-coded leaves + * at hard-coded offsets. + */ + ret = xroot_add_simple_node(xm->root, dtb, XRT_MD_NODE_VSEC_GOLDEN); + } else if (ret == 0) { + ret = xroot_add_simple_node(xm->root, dtb, XRT_MD_NODE_MGMT_MAIN); + } + if (ret) + goto failed; + + *root_dtb = dtb; + return 0; + +failed: + vfree(dtb); + return ret; +} + +static ssize_t ready_show(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct xmgmt *xm = pci_get_drvdata(pdev); + + return sprintf(buf, "%d\n", xm->ready); +} +static DEVICE_ATTR_RO(ready); + +static struct attribute *xmgmt_root_attrs[] = { + &dev_attr_ready.attr, + NULL +}; + +static struct attribute_group xmgmt_root_attr_group = { + .attrs = xmgmt_root_attrs, +}; + +static void xmgmt_root_get_id(struct device *dev, struct xrt_root_get_id *rid) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + rid->xpigi_vendor_id = pdev->vendor; + rid->xpigi_device_id = pdev->device; + rid->xpigi_sub_vendor_id = pdev->subsystem_vendor; + rid->xpigi_sub_device_id = pdev->subsystem_device; +} + +static int xmgmt_root_get_resource(struct device *dev, struct xrt_root_get_res *res) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct xmgmt *xm; + + xm = pci_get_drvdata(pdev); + if (res->xpigr_region_id > PCI_STD_RESOURCE_END) { + xmgmt_err(xm, "Invalid bar idx %d", res->xpigr_region_id); + return -EINVAL; + } + + res->xpigr_res = &pdev->resource[res->xpigr_region_id]; + return 0; +} + +static struct xroot_physical_function_callback xmgmt_xroot_pf_cb = { + .xpc_get_id = xmgmt_root_get_id, + .xpc_get_resource = xmgmt_root_get_resource, + .xpc_hot_reset = xmgmt_root_hot_reset, +}; + +static int xmgmt_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int ret; + struct device *dev = &pdev->dev; + struct xmgmt *xm = devm_kzalloc(dev, sizeof(*xm), GFP_KERNEL); + char *dtb = NULL; + + if (!xm) + return -ENOMEM; + xm->pdev = pdev; + pci_set_drvdata(pdev, xm); + + ret = xmgmt_config_pci(xm); + if (ret) + goto failed; + + ret = xroot_probe(&pdev->dev, &xmgmt_xroot_pf_cb, &xm->root); + if (ret) + goto failed; + + ret = xmgmt_create_root_metadata(xm, &dtb); + if (ret) + goto failed_metadata; + + ret = xroot_create_group(xm->root, dtb); + vfree(dtb); + if (ret) + xmgmt_err(xm, "failed to create root group: %d", ret); + + if (!xroot_wait_for_bringup(xm->root)) + xmgmt_err(xm, "failed to bringup all groups"); + else + xm->ready = true; + + ret = sysfs_create_group(&pdev->dev.kobj, &xmgmt_root_attr_group); + if (ret) { + /* Warning instead of failing the probe. */ + xmgmt_warn(xm, "create xmgmt root attrs failed: %d", ret); + } + + xroot_broadcast(xm->root, XRT_EVENT_POST_CREATION); + xmgmt_info(xm, "%s started successfully", XMGMT_MODULE_NAME); + return 0; + +failed_metadata: + xroot_remove(xm->root); +failed: + pci_set_drvdata(pdev, NULL); + return ret; +} + +static void xmgmt_remove(struct pci_dev *pdev) +{ + struct xmgmt *xm = pci_get_drvdata(pdev); + + xroot_broadcast(xm->root, XRT_EVENT_PRE_REMOVAL); + sysfs_remove_group(&pdev->dev.kobj, &xmgmt_root_attr_group); + xroot_remove(xm->root); + pci_disable_pcie_error_reporting(xm->pdev); + xmgmt_info(xm, "%s cleaned up successfully", XMGMT_MODULE_NAME); +} + +static struct pci_driver xmgmt_driver = { + .name = XMGMT_MODULE_NAME, + .id_table = xmgmt_pci_ids, + .probe = xmgmt_probe, + .remove = xmgmt_remove, +}; + +static int __init xmgmt_init(void) +{ + int res = 0; + + res = xmgmt_register_leaf(); + if (res) + return res; + + xmgmt_class = class_create(THIS_MODULE, XMGMT_MODULE_NAME); + if (IS_ERR(xmgmt_class)) + return PTR_ERR(xmgmt_class); + + res = pci_register_driver(&xmgmt_driver); + if (res) { + class_destroy(xmgmt_class); + return res; + } + + return 0; +} + +static __exit void xmgmt_exit(void) +{ + pci_unregister_driver(&xmgmt_driver); + class_destroy(xmgmt_class); + xmgmt_unregister_leaf(); +} + +module_init(xmgmt_init); +module_exit(xmgmt_exit); + +MODULE_DEVICE_TABLE(pci, xmgmt_pci_ids); +MODULE_VERSION(XMGMT_DRIVER_VERSION); +MODULE_AUTHOR("XRT Team "); +MODULE_DESCRIPTION("Xilinx Alveo management function driver"); +MODULE_LICENSE("GPL v2"); From patchwork Wed May 12 01:53:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435840 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4BE1EC433ED for ; Wed, 12 May 2021 01:59:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2D6696192F for ; Wed, 12 May 2021 01:59:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229973AbhELCBD (ORCPT ); Tue, 11 May 2021 22:01:03 -0400 Received: from mail-bn8nam11on2069.outbound.protection.outlook.com ([40.107.236.69]:48864 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229945AbhELCBD (ORCPT ); Tue, 11 May 2021 22:01:03 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lXNIteHBdiKGUuQMsdWEFzlK0ur19V9RCfMUqDTbhLjlJEfU6GFe1Hk340uPFPSFmIMJT0M75sNHrYOD2EC5d0aJMRYIdIILGJ6lkRZ7InY3CQl5XZdDFzUb3ncP8vLjD6qff7ZwdTN62VOHmRiTylGRu0YBc+xKS9ECSEvueebc/K+WRO0Bh4MeOpIgvv5mcqiD9ckjzjdyxX7k/dzz25k2n3N0BoBi5d2u1mtqDuCMlnvIGQjsC7J7m49rXYA69UdT6uhCWlnWVX5aOTMe3m28btg2G4KUiSRIt27Ej0UIJf5YS0kCd8rqMQOFDyy9/AyAKDKn4nOn1LkegsjYLw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IfGg0cSy1pPKBMaBF7KqARl4Dptho6+k1qcM89bQ1/E=; b=hpUdvghvG8ya4TQ+7yPjzby6+7PpG9Fe0tQcrcnLvqJy9gKZxOegmGQ7fBvs5y9hD0oq5dT2Y9+H/fWERkA4Q4DJyga3AkY3UAA61a7BLp2weBTR5l8A4aI7XWhkUcU6BHDOLQnQ/wem//cSXGKqonYNOuOnXatUmca9Vg1THob2I7MipNRJg20H3Vy8YebXPXHwJAPOeIqMw1iC1x+yC4SofQv2aitgchmrmSzL9bEmufg/gD2xaZrhzVoNvVAkeaArN9A2n8HwWFg/3oooMqkA3ghnGiQQD//hgc7QaOeAq3orWGeAmFajUAPP9A92hCtRs1C9uQen28Zwnq/tdg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IfGg0cSy1pPKBMaBF7KqARl4Dptho6+k1qcM89bQ1/E=; b=NVqRGY5yQyMMCg9ItSaKUTX5wlvqVlJGS+aQr+B/C5fu6OnMpp0iJGmjdLXdhS4rQnBP93i0KeuyyQkIUXUOnSGiwPJL3+PqlIjux4PBUCW8Ks2vCUIasXXku2xLyur2WuU0bnNyMnbkY2ycbuXB8/6JKTTYFSfp1vAt0YPzikQ= Received: from BN6PR18CA0001.namprd18.prod.outlook.com (2603:10b6:404:121::11) by SN6PR02MB5615.namprd02.prod.outlook.com (2603:10b6:805:ea::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.26; Wed, 12 May 2021 01:59:52 +0000 Received: from BN1NAM02FT035.eop-nam02.prod.protection.outlook.com (2603:10b6:404:121:cafe::9) by BN6PR18CA0001.outlook.office365.com (2603:10b6:404:121::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4129.25 via Frontend Transport; Wed, 12 May 2021 01:59:52 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT035.mail.protection.outlook.com (10.13.2.81) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 01:59:51 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:59:31 -0700 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:59:31 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35734 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lge9r-0001dk-A9; Tue, 11 May 2021 18:59:31 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 8ED58600130; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 11/20] fpga: xrt: fpga-mgr and region implementation for xclbin download Date: Tue, 11 May 2021 18:53:30 -0700 Message-ID: <20210512015339.5649-12-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 7cf5df2e-6ef7-42f3-caac-08d914e9a193 X-MS-TrafficTypeDiagnostic: SN6PR02MB5615: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:608; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: sjkbyVNR+ZuS+ab/dgf3xpViXfgwJkhw1xyBaoxNQyUoCVOq1DMRZxH95otjUicr5WBSWCzX5W5VJOBdXOsf3+ZXtOdVutTx8whT/E0wW0bdLx2SDAy2YLkygFe7kBMrx9pOhGkzKnFNjogCl9aLwS0pbTGPijpOP/l1PgkMDxt54CZ0xc91XZfzoMXQlGj23VmOXBFZUjW3S3zgXES/xGOh5SyoOHaUpkf2htMJBFsKxZVvW6+jMzahzEt8KIVnBuMvmHLP3fq82YuW7IjjKws6bxHpIBS3Ci/hdtnJNpsuX+6hzRMlztmrv4CsScMBSH5d7eLOa2iNycR79gXNWZr9gY1EUfeJOke+jZxjZ1CPdnz6ndyy/kyqoWkHvGQ9TY6K3lFRGdX4HAEWQxzs/kC+kGcZN/+9FYtrG/OJ+n5QUcvsOX90v3i4QZvk6GiwpWAL1xVLryYUanUCwdt9XTqokIJPnZ1N8FDF/7RVFs6YkP4N1aC+y4XE3tdBBJKKFtK27ro+kP7rnBx5xCl6apW9P/jtIWiKGlrEwM8KnY+qZvcohjycRytW6VCrifEa0yA1HBLNDaC4XUJFcXSUYDj+zXRS6wmWMyRK5xvOdxNBUlZj+9p1rhwYWwcDX4DTF9/GAAGX+yP8W64R2mkoqmVUnHOGDQIM9NSti6oJp5Q= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch01.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(376002)(346002)(396003)(136003)(39850400004)(46966006)(36840700001)(8936002)(36860700001)(478600001)(7636003)(6266002)(30864003)(4326008)(356005)(186003)(316002)(2906002)(36906005)(8676002)(6666004)(47076005)(107886003)(5660300002)(82740400003)(83380400001)(26005)(1076003)(42186006)(36756003)(44832011)(336012)(70206006)(2616005)(6916009)(70586007)(82310400003)(54906003)(426003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 01:59:51.8909 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7cf5df2e-6ef7-42f3-caac-08d914e9a193 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT035.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR02MB5615 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org fpga-mgr and region implementation for xclbin download which will be called from main xrt driver Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/mgmt/xmgmt-main-region.c | 483 ++++++++++++++++++++++ drivers/fpga/xrt/mgmt/xrt-mgr.c | 190 +++++++++ drivers/fpga/xrt/mgmt/xrt-mgr.h | 16 + 3 files changed, 689 insertions(+) create mode 100644 drivers/fpga/xrt/mgmt/xmgmt-main-region.c create mode 100644 drivers/fpga/xrt/mgmt/xrt-mgr.c create mode 100644 drivers/fpga/xrt/mgmt/xrt-mgr.h diff --git a/drivers/fpga/xrt/mgmt/xmgmt-main-region.c b/drivers/fpga/xrt/mgmt/xmgmt-main-region.c new file mode 100644 index 000000000000..6e6a16b13258 --- /dev/null +++ b/drivers/fpga/xrt/mgmt/xmgmt-main-region.c @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Region Support for Xilinx Alveo + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: Lizhi.Hou@xilinx.com + */ + +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/axigate.h" +#include "xclbin-helper.h" +#include "xmgmt.h" + +struct xmgmt_bridge { + struct xrt_device *xdev; + const char *bridge_name; +}; + +struct xmgmt_region { + struct xrt_device *xdev; + struct fpga_region *region; + struct fpga_compat_id compat_id; + uuid_t interface_uuid; + struct fpga_bridge *bridge; + int group_instance; + uuid_t depend_uuid; + struct list_head list; +}; + +struct xmgmt_region_match_arg { + struct xrt_device *xdev; + uuid_t *uuids; + u32 uuid_num; +}; + +static int xmgmt_br_enable_set(struct fpga_bridge *bridge, bool enable) +{ + struct xmgmt_bridge *br_data = (struct xmgmt_bridge *)bridge->priv; + struct xrt_device *axigate_leaf; + int rc; + + axigate_leaf = xleaf_get_leaf_by_epname(br_data->xdev, br_data->bridge_name); + if (!axigate_leaf) { + xrt_err(br_data->xdev, "failed to get leaf %s", + br_data->bridge_name); + return -ENOENT; + } + + if (enable) + rc = xleaf_call(axigate_leaf, XRT_AXIGATE_OPEN, NULL); + else + rc = xleaf_call(axigate_leaf, XRT_AXIGATE_CLOSE, NULL); + + if (rc) { + xrt_err(br_data->xdev, "failed to %s gate %s, rc %d", + (enable ? "free" : "freeze"), br_data->bridge_name, + rc); + } + + xleaf_put_leaf(br_data->xdev, axigate_leaf); + + return rc; +} + +static const struct fpga_bridge_ops xmgmt_bridge_ops = { + .enable_set = xmgmt_br_enable_set +}; + +static void xmgmt_destroy_bridge(struct fpga_bridge *br) +{ + struct xmgmt_bridge *br_data = br->priv; + + if (!br_data) + return; + + xrt_info(br_data->xdev, "destroy fpga bridge %s", br_data->bridge_name); + fpga_bridge_unregister(br); + + devm_kfree(DEV(br_data->xdev), br_data); + + fpga_bridge_free(br); +} + +static struct fpga_bridge *xmgmt_create_bridge(struct xrt_device *xdev, + char *dtb) +{ + struct fpga_bridge *br = NULL; + struct xmgmt_bridge *br_data; + const char *gate; + int rc; + + br_data = devm_kzalloc(DEV(xdev), sizeof(*br_data), GFP_KERNEL); + if (!br_data) + return NULL; + br_data->xdev = xdev; + + br_data->bridge_name = XRT_MD_NODE_GATE_ULP; + rc = xrt_md_find_endpoint(&xdev->dev, dtb, XRT_MD_NODE_GATE_ULP, + NULL, &gate); + if (rc) { + br_data->bridge_name = XRT_MD_NODE_GATE_PLP; + rc = xrt_md_find_endpoint(&xdev->dev, dtb, XRT_MD_NODE_GATE_PLP, + NULL, &gate); + } + if (rc) { + xrt_err(xdev, "failed to get axigate, rc %d", rc); + goto failed; + } + + br = fpga_bridge_create(DEV(xdev), br_data->bridge_name, + &xmgmt_bridge_ops, br_data); + if (!br) { + xrt_err(xdev, "failed to create bridge"); + goto failed; + } + + rc = fpga_bridge_register(br); + if (rc) { + xrt_err(xdev, "failed to register bridge, rc %d", rc); + goto failed; + } + + xrt_info(xdev, "created fpga bridge %s", br_data->bridge_name); + + return br; + +failed: + if (br) + fpga_bridge_free(br); + if (br_data) + devm_kfree(DEV(xdev), br_data); + + return NULL; +} + +static void xmgmt_destroy_region(struct fpga_region *region) +{ + struct xmgmt_region *r_data = region->priv; + + xrt_info(r_data->xdev, "destroy fpga region %llx.%llx", + region->compat_id->id_h, region->compat_id->id_l); + + fpga_region_unregister(region); + + if (r_data->group_instance > 0) + xleaf_destroy_group(r_data->xdev, r_data->group_instance); + + if (r_data->bridge) + xmgmt_destroy_bridge(r_data->bridge); + + if (r_data->region->info) { + fpga_image_info_free(r_data->region->info); + r_data->region->info = NULL; + } + + fpga_region_free(region); + + devm_kfree(DEV(r_data->xdev), r_data); +} + +static int xmgmt_region_match(struct device *dev, const void *data) +{ + const struct xmgmt_region_match_arg *arg = data; + const struct fpga_region *match_region; + uuid_t compat_uuid; + int i; + + if (dev->parent != &arg->xdev->dev) + return false; + + match_region = to_fpga_region(dev); + /* + * The device tree provides both parent and child uuids for an + * xclbin in one array. Here we try both uuids to see if it matches + * with target region's compat_id. Strictly speaking we should + * only match xclbin's parent uuid with target region's compat_id + * but given the uuids by design are unique comparing with both + * does not hurt. + */ + import_uuid(&compat_uuid, (const char *)match_region->compat_id); + for (i = 0; i < arg->uuid_num; i++) { + if (uuid_equal(&compat_uuid, &arg->uuids[i])) + return true; + } + + return false; +} + +static int xmgmt_region_match_base(struct device *dev, const void *data) +{ + const struct xmgmt_region_match_arg *arg = data; + const struct fpga_region *match_region; + const struct xmgmt_region *r_data; + + if (dev->parent != &arg->xdev->dev) + return false; + + match_region = to_fpga_region(dev); + r_data = match_region->priv; + if (uuid_is_null(&r_data->depend_uuid)) + return true; + + return false; +} + +static int xmgmt_region_match_by_uuid(struct device *dev, const void *data) +{ + const struct xmgmt_region_match_arg *arg = data; + const struct fpga_region *match_region; + const struct xmgmt_region *r_data; + + if (dev->parent != &arg->xdev->dev) + return false; + + if (arg->uuid_num != 1) + return false; + + match_region = to_fpga_region(dev); + r_data = match_region->priv; + if (uuid_equal(&r_data->depend_uuid, arg->uuids)) + return true; + + return false; +} + +static void xmgmt_region_cleanup(struct fpga_region *region) +{ + struct xmgmt_region *r_data = region->priv, *pdata, *temp; + struct xrt_device *xdev = r_data->xdev; + struct xmgmt_region_match_arg arg = { 0 }; + struct fpga_region *match_region = NULL; + struct device *start_dev = NULL; + LIST_HEAD(free_list); + uuid_t compat_uuid; + + list_add_tail(&r_data->list, &free_list); + arg.xdev = xdev; + arg.uuid_num = 1; + arg.uuids = &compat_uuid; + + /* find all regions depending on this region */ + list_for_each_entry_safe(pdata, temp, &free_list, list) { + import_uuid(arg.uuids, (const char *)pdata->region->compat_id); + start_dev = NULL; + while ((match_region = fpga_region_class_find(start_dev, &arg, + xmgmt_region_match_by_uuid))) { + pdata = match_region->priv; + list_add_tail(&pdata->list, &free_list); + start_dev = &match_region->dev; + put_device(&match_region->dev); + } + } + + list_del(&r_data->list); + + list_for_each_entry_safe_reverse(pdata, temp, &free_list, list) + xmgmt_destroy_region(pdata->region); + + if (r_data->group_instance > 0) { + xleaf_destroy_group(xdev, r_data->group_instance); + r_data->group_instance = -1; + } + if (r_data->region->info) { + fpga_image_info_free(r_data->region->info); + r_data->region->info = NULL; + } +} + +void xmgmt_region_cleanup_all(struct xrt_device *xdev) +{ + struct xmgmt_region_match_arg arg = { 0 }; + struct fpga_region *base_region; + + arg.xdev = xdev; + + while ((base_region = fpga_region_class_find(NULL, &arg, xmgmt_region_match_base))) { + put_device(&base_region->dev); + + xmgmt_region_cleanup(base_region); + xmgmt_destroy_region(base_region); + } +} + +/* + * Program a region with a xclbin image. Bring up the subdevs and the + * group object to contain the subdevs. + */ +static int xmgmt_region_program(struct fpga_region *region, const void *xclbin, char *dtb) +{ + const struct axlf *xclbin_obj = xclbin; + struct fpga_image_info *info; + struct xrt_device *xdev; + struct xmgmt_region *r_data; + int rc; + + r_data = region->priv; + xdev = r_data->xdev; + + info = fpga_image_info_alloc(&xdev->dev); + if (!info) + return -ENOMEM; + + info->buf = xclbin; + info->count = xclbin_obj->header.length; + info->flags |= FPGA_MGR_PARTIAL_RECONFIG; + region->info = info; + rc = fpga_region_program_fpga(region); + if (rc) { + xrt_err(xdev, "programming xclbin failed, rc %d", rc); + return rc; + } + + /* free bridges to allow reprogram */ + if (region->get_bridges) + fpga_bridges_put(®ion->bridge_list); + + /* + * Next bringup the subdevs for this region which will be managed by + * its own group object. + */ + r_data->group_instance = xleaf_create_group(xdev, dtb); + if (r_data->group_instance < 0) { + xrt_err(xdev, "failed to create group, rc %d", + r_data->group_instance); + rc = r_data->group_instance; + return rc; + } + + rc = xleaf_wait_for_group_bringup(xdev); + if (rc) + xrt_err(xdev, "group bringup failed, rc %d", rc); + return rc; +} + +static int xmgmt_get_bridges(struct fpga_region *region) +{ + struct xmgmt_region *r_data = region->priv; + struct device *dev = &r_data->xdev->dev; + + return fpga_bridge_get_to_list(dev, region->info, ®ion->bridge_list); +} + +/* + * Program/create FPGA regions based on input xclbin file. + * 1. Identify a matching existing region for this xclbin + * 2. Tear down any previous objects for the found region + * 3. Program this region with input xclbin + * 4. Iterate over this region's interface uuids to determine if it defines any + * child region. Create fpga_region for the child region. + */ +int xmgmt_process_xclbin(struct xrt_device *xdev, + struct fpga_manager *fmgr, + const struct axlf *xclbin, + enum provider_kind kind) +{ + struct fpga_region *region, *compat_region = NULL; + struct xmgmt_region_match_arg arg = { 0 }; + struct xmgmt_region *r_data; + uuid_t compat_uuid; + char *dtb = NULL; + int rc, i; + + rc = xrt_xclbin_get_metadata(DEV(xdev), xclbin, &dtb); + if (rc) { + xrt_err(xdev, "failed to get dtb: %d", rc); + goto failed; + } + + rc = xrt_md_get_interface_uuids(DEV(xdev), dtb, 0, NULL); + if (rc < 0) { + xrt_err(xdev, "failed to get intf uuid"); + rc = -EINVAL; + goto failed; + } + arg.uuid_num = rc; + arg.uuids = kcalloc(arg.uuid_num, sizeof(uuid_t), GFP_KERNEL); + if (!arg.uuids) { + rc = -ENOMEM; + goto failed; + } + arg.xdev = xdev; + + rc = xrt_md_get_interface_uuids(DEV(xdev), dtb, arg.uuid_num, arg.uuids); + if (rc != arg.uuid_num) { + xrt_err(xdev, "only get %d uuids, expect %d", rc, arg.uuid_num); + rc = -EINVAL; + goto failed; + } + + /* if this is not base firmware, search for a compatible region */ + if (kind != XMGMT_BLP) { + compat_region = fpga_region_class_find(NULL, &arg, xmgmt_region_match); + if (!compat_region) { + xrt_err(xdev, "failed to get compatible region"); + rc = -ENOENT; + goto failed; + } + + xmgmt_region_cleanup(compat_region); + + rc = xmgmt_region_program(compat_region, xclbin, dtb); + if (rc) { + xrt_err(xdev, "failed to program region"); + goto failed; + } + } + + if (compat_region) + import_uuid(&compat_uuid, (const char *)compat_region->compat_id); + + /* create all the new regions contained in this xclbin */ + for (i = 0; i < arg.uuid_num; i++) { + if (compat_region && uuid_equal(&compat_uuid, &arg.uuids[i])) { + /* region for this interface already exists */ + continue; + } + + region = fpga_region_create(DEV(xdev), fmgr, xmgmt_get_bridges); + if (!region) { + xrt_err(xdev, "failed to create fpga region"); + rc = -EFAULT; + goto failed; + } + r_data = devm_kzalloc(DEV(xdev), sizeof(*r_data), GFP_KERNEL); + if (!r_data) { + rc = -ENOMEM; + fpga_region_free(region); + goto failed; + } + r_data->xdev = xdev; + r_data->region = region; + r_data->group_instance = -1; + uuid_copy(&r_data->interface_uuid, &arg.uuids[i]); + if (compat_region) + import_uuid(&r_data->depend_uuid, (const char *)compat_region->compat_id); + r_data->bridge = xmgmt_create_bridge(xdev, dtb); + if (!r_data->bridge) { + xrt_err(xdev, "failed to create fpga bridge"); + rc = -EFAULT; + devm_kfree(DEV(xdev), r_data); + fpga_region_free(region); + goto failed; + } + + region->compat_id = &r_data->compat_id; + export_uuid((char *)region->compat_id, &r_data->interface_uuid); + region->priv = r_data; + + rc = fpga_region_register(region); + if (rc) { + xrt_err(xdev, "failed to register fpga region"); + xmgmt_destroy_bridge(r_data->bridge); + fpga_region_free(region); + devm_kfree(DEV(xdev), r_data); + goto failed; + } + + xrt_info(xdev, "created fpga region %llx.%llx", + region->compat_id->id_h, region->compat_id->id_l); + } + + if (compat_region) + put_device(&compat_region->dev); + vfree(dtb); + kfree(arg.uuids); + return 0; + +failed: + if (compat_region) { + put_device(&compat_region->dev); + xmgmt_region_cleanup(compat_region); + } + + vfree(dtb); + kfree(arg.uuids); + return rc; +} diff --git a/drivers/fpga/xrt/mgmt/xrt-mgr.c b/drivers/fpga/xrt/mgmt/xrt-mgr.c new file mode 100644 index 000000000000..41263a033d9d --- /dev/null +++ b/drivers/fpga/xrt/mgmt/xrt-mgr.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Manager Support for Xilinx Alveo + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: Sonal.Santan@xilinx.com + */ + +#include +#include +#include +#include +#include + +#include "xclbin-helper.h" +#include "xleaf.h" +#include "xrt-mgr.h" +#include "xleaf/axigate.h" +#include "xleaf/icap.h" +#include "xmgmt.h" + +struct xfpga_class { + struct xrt_device *xdev; + char name[64]; +}; + +/* + * xclbin download plumbing -- find the download subsystem, ICAP and + * pass the xclbin for heavy lifting + */ +static int xmgmt_download_bitstream(struct xrt_device *xdev, + const struct axlf *xclbin) + +{ + struct xclbin_bit_head_info bit_header = { 0 }; + struct xrt_device *icap_leaf = NULL; + struct xrt_icap_wr arg; + char *bitstream = NULL; + u64 bit_len; + int ret; + + ret = xrt_xclbin_get_section(DEV(xdev), xclbin, BITSTREAM, (void **)&bitstream, &bit_len); + if (ret) { + xrt_err(xdev, "bitstream not found"); + return -ENOENT; + } + ret = xrt_xclbin_parse_bitstream_header(DEV(xdev), bitstream, + XCLBIN_HWICAP_BITFILE_BUF_SZ, + &bit_header); + if (ret) { + ret = -EINVAL; + xrt_err(xdev, "invalid bitstream header"); + goto fail; + } + if (bit_header.header_length + bit_header.bitstream_length > bit_len) { + ret = -EINVAL; + xrt_err(xdev, "invalid bitstream length. header %d, bitstream %d, section len %lld", + bit_header.header_length, bit_header.bitstream_length, bit_len); + goto fail; + } + + icap_leaf = xleaf_get_leaf_by_id(xdev, XRT_SUBDEV_ICAP, XRT_INVALID_DEVICE_INST); + if (!icap_leaf) { + ret = -ENODEV; + xrt_err(xdev, "icap does not exist"); + goto fail; + } + arg.xiiw_bit_data = bitstream + bit_header.header_length; + arg.xiiw_data_len = bit_header.bitstream_length; + ret = xleaf_call(icap_leaf, XRT_ICAP_WRITE, &arg); + if (ret) { + xrt_err(xdev, "write bitstream failed, ret = %d", ret); + xleaf_put_leaf(xdev, icap_leaf); + goto fail; + } + + xleaf_put_leaf(xdev, icap_leaf); + vfree(bitstream); + + return 0; + +fail: + vfree(bitstream); + + return ret; +} + +/* + * There is no HW prep work we do here since we need the full + * xclbin for its sanity check. + */ +static int xmgmt_pr_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + const struct axlf *bin = (const struct axlf *)buf; + struct xfpga_class *obj = mgr->priv; + + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { + xrt_info(obj->xdev, "%s only supports partial reconfiguration\n", obj->name); + return -EINVAL; + } + + if (count < sizeof(struct axlf)) + return -EINVAL; + + if (count > bin->header.length) + return -EINVAL; + + xrt_info(obj->xdev, "Prepare download of xclbin %pUb of length %lld B", + &bin->header.uuid, bin->header.length); + + return 0; +} + +/* + * The implementation requries full xclbin image before we can start + * programming the hardware via ICAP subsystem. The full image is required + * for checking the validity of xclbin and walking the sections to + * discover the bitstream. + */ +static int xmgmt_pr_write(struct fpga_manager *mgr, + const char *buf, size_t count) +{ + const struct axlf *bin = (const struct axlf *)buf; + struct xfpga_class *obj = mgr->priv; + + if (bin->header.length != count) + return -EINVAL; + + return xmgmt_download_bitstream((void *)obj->xdev, bin); +} + +static int xmgmt_pr_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + const struct axlf *bin = (const struct axlf *)info->buf; + struct xfpga_class *obj = mgr->priv; + + xrt_info(obj->xdev, "Finished download of xclbin %pUb", + &bin->header.uuid); + return 0; +} + +static enum fpga_mgr_states xmgmt_pr_state(struct fpga_manager *mgr) +{ + return FPGA_MGR_STATE_UNKNOWN; +} + +static const struct fpga_manager_ops xmgmt_pr_ops = { + .initial_header_size = sizeof(struct axlf), + .write_init = xmgmt_pr_write_init, + .write = xmgmt_pr_write, + .write_complete = xmgmt_pr_write_complete, + .state = xmgmt_pr_state, +}; + +struct fpga_manager *xmgmt_fmgr_probe(struct xrt_device *xdev) +{ + struct xfpga_class *obj = devm_kzalloc(DEV(xdev), sizeof(struct xfpga_class), + GFP_KERNEL); + struct fpga_manager *fmgr = NULL; + int ret = 0; + + if (!obj) + return ERR_PTR(-ENOMEM); + + snprintf(obj->name, sizeof(obj->name), "Xilinx Alveo FPGA Manager"); + obj->xdev = xdev; + fmgr = fpga_mgr_create(&xdev->dev, + obj->name, + &xmgmt_pr_ops, + obj); + if (!fmgr) + return ERR_PTR(-ENOMEM); + + ret = fpga_mgr_register(fmgr); + if (ret) { + fpga_mgr_free(fmgr); + return ERR_PTR(ret); + } + return fmgr; +} + +int xmgmt_fmgr_remove(struct fpga_manager *fmgr) +{ + fpga_mgr_unregister(fmgr); + return 0; +} diff --git a/drivers/fpga/xrt/mgmt/xrt-mgr.h b/drivers/fpga/xrt/mgmt/xrt-mgr.h new file mode 100644 index 000000000000..a3d1ab1c34f0 --- /dev/null +++ b/drivers/fpga/xrt/mgmt/xrt-mgr.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: Sonal.Santan@xilinx.com + */ + +#ifndef _XRT_MGR_H_ +#define _XRT_MGR_H_ + +#include + +struct fpga_manager *xmgmt_fmgr_probe(struct xrt_device *xdev); +int xmgmt_fmgr_remove(struct fpga_manager *fmgr); + +#endif /* _XRT_MGR_H_ */ From patchwork Wed May 12 01:53:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435839 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 74BE7C433B4 for ; Wed, 12 May 2021 02:00:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5A210616E9 for ; Wed, 12 May 2021 02:00:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229945AbhELCBO (ORCPT ); Tue, 11 May 2021 22:01:14 -0400 Received: from mail-bn8nam11on2041.outbound.protection.outlook.com ([40.107.236.41]:14976 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230370AbhELCBL (ORCPT ); Tue, 11 May 2021 22:01:11 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WHinleQkOWziCxr5F5gzoOz67+tcwv70aSxXTfpLSw2ueFNQRuKA1hd0eWUt5/u7ARImnYZqrIAkWPTnk8yV6dhauBI4af+pUatLQE/BpwLubpjFqAc6epXFr9gZBhiMXl7APNcXWl9IgJQpEs/nPS7UZfc9QAci6XlWUksziE6vfy+WZxRg0mUPCsR1EVgrii9fvo6+C34sz/1rT09KcmjW76U/SYfRd0ITLvwbK+VU1joJjWqO2KKD7ibTCp7abGW4UTxYvNaaR8O0N9hRgKfzxbx7URmMh7ospu/v1hO/B+Wqfom3k3OQBrlvJHsqgC5/XvBM1PimapI/9NQHyA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=V9mJsve++LQwM6u/mJHRmEXlxHFFBqypjeFWgYcz4aQ=; b=nmLr9VP7yzOeClkzVXc0ZMTvBUlsI7nLs7pkIBqTPX+z5a3NClqy8mVW+/QRQYa1XT8fjN5RbuCCmu5bd3eB1nOWOR3O6ncbReU3rt+V5Sp1E2zJS6Z0SjojXVbVtbZo+vEtDExDp2GXeLnxMHXQFbVWZ2y73Fz5bt0oPAd9M/URucE7Zats1Gk1SkYCkapDyQOR0N336njatYVsxZWdIOj9S9JllifgWnTTPXEC3uMQXdyy2dksmWTJElALuVxWhLnLTJWZRoWOeMt5+tQDX6YRhrVlSaocausbiS+hiw0lcmgIViyC1pyTjVCXNwFgcWaUAPnhpgW6tVW/J5R3ZA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=V9mJsve++LQwM6u/mJHRmEXlxHFFBqypjeFWgYcz4aQ=; b=XEdwGvOYvNZ1RhCAyNDHvjrOPL2oT5LkYbWeYmn5KYfMmezjxVlP8PIAUTOw2hqRrK2Lsq/Gamb0cTgWWp3+cHlg4fdYMKYNyQa9jLpDQxMqRFgcW8zZlZt3TRTDOrAFlsqgyk5244FUAwAjuruU6AvP7cPSsC1xPY4qZwMQKaw= Received: from BN6PR18CA0003.namprd18.prod.outlook.com (2603:10b6:404:121::13) by BN6PR02MB2323.namprd02.prod.outlook.com (2603:10b6:404:36::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.27; Wed, 12 May 2021 02:00:01 +0000 Received: from BN1NAM02FT035.eop-nam02.prod.protection.outlook.com (2603:10b6:404:121:cafe::f) by BN6PR18CA0003.outlook.office365.com (2603:10b6:404:121::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 02:00:00 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT035.mail.protection.outlook.com (10.13.2.81) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 02:00:00 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 18:59:43 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 18:59:43 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35736 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lgeA3-0005ba-Bj; Tue, 11 May 2021 18:59:43 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 994BA60012F; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 12/20] fpga: xrt: VSEC driver Date: Tue, 11 May 2021 18:53:31 -0700 Message-ID: <20210512015339.5649-13-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 86ff74dd-9a9d-46e5-227c-08d914e9a6ed X-MS-TrafficTypeDiagnostic: BN6PR02MB2323: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:4714; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: BOWcNV7yKbu5cw3DvLllr7QTvR2kCwnSoTOT5KsJ5jgCQYURt8pnVJBB2EJrN49e3K+2lNVEZRkjkMw9ziS7tjYFx4hT4rgOr9JN96gXSTQ+STFOCb1iCyG40iOlLkDcTbDAvnsUMgoQF8Ld2HdPBAy4uJvYMluQwI04W9zF5demD2LblHA/P2d5MXA3pPBTKp1zZVWLNPCNwWdydzg7VQhGsXqm7xeLvFmcP/fZ7RKH4M/7A2Te1j4Dr5yMYNLmLz9+RxSBDoRWWLsqFALtNIn5LJU0/2RnXdV6gRWHA7wEiGhyAWqaFTPsCje32MiXa0hDOnEQ0o9fVWUSiMz6eEV8MkOEKjFvOULv/FL/L4BWzLVhvacG/+ydn7PwP1b7p1wKdq9M6vMjjykmoYtwYANuuryQ6kNuAvIhxBRi1BXHNhclyEhxnKYwf8yJWH6AKwwjyTiMogbjkcMIJRgn75iC+kgYgJvD+pNCpEnM+dls5dvMLBjeMm+sGKEfpyoXAEjDnfGtulxG7Zg3QE+wQScwGgJitYcmqPfTH8d7BW6TlDVQYepCVaDGDZBePidLoK0d7A3ImvPa0vk4v/CV24oovjl/mY7i/JJ4MAZwzDyKMdBbi2DNzlna1eI5vf/GX+p/YBDaotIT/BK8wZg2nY3OYiuPNmlkkoyh7uLibEM= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch01.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(136003)(396003)(376002)(346002)(39860400002)(46966006)(36840700001)(186003)(36860700001)(82310400003)(336012)(426003)(2906002)(6666004)(1076003)(44832011)(83380400001)(70206006)(6916009)(6266002)(107886003)(5660300002)(2616005)(8676002)(70586007)(8936002)(82740400003)(356005)(478600001)(7636003)(47076005)(4326008)(316002)(54906003)(36906005)(42186006)(36756003)(26005); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 02:00:00.8650 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 86ff74dd-9a9d-46e5-227c-08d914e9a6ed X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT035.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN6PR02MB2323 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add VSEC driver. VSEC is a hardware function discovered by walking PCI Express configure space. A xrt device node will be created for it. VSEC provides board logic UUID and few offset of other hardware functions. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/lib/xleaf/vsec.c | 372 ++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 drivers/fpga/xrt/lib/xleaf/vsec.c diff --git a/drivers/fpga/xrt/lib/xleaf/vsec.c b/drivers/fpga/xrt/lib/xleaf/vsec.c new file mode 100644 index 000000000000..a6fa4f2ec832 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/vsec.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA VSEC Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#include +#include "metadata.h" +#include "xdevice.h" +#include "xleaf.h" + +#define XRT_VSEC "xrt_vsec" + +#define VSEC_TYPE_UUID 0x50 +#define VSEC_TYPE_FLASH 0x51 +#define VSEC_TYPE_PLATINFO 0x52 +#define VSEC_TYPE_MAILBOX 0x53 +#define VSEC_TYPE_END 0xff + +#define VSEC_UUID_LEN 16 + +#define VSEC_REG_FORMAT 0x0 +#define VSEC_REG_LENGTH 0x4 +#define VSEC_REG_ENTRY 0x8 + +struct xrt_vsec_header { + u32 format; + u32 length; + u32 entry_sz; + u32 rsvd; +} __packed; + +struct xrt_vsec_entry { + u8 type; + u8 bar_rev; + u16 off_lo; + u32 off_hi; + u8 ver_type; + u8 minor; + u8 major; + u8 rsvd0; + u32 rsvd1; +} __packed; + +struct vsec_device { + u8 type; + char *ep_name; + ulong size; + char *compat; +}; + +static struct vsec_device vsec_devs[] = { + { + .type = VSEC_TYPE_UUID, + .ep_name = XRT_MD_NODE_BLP_ROM, + .size = VSEC_UUID_LEN, + .compat = "vsec-uuid", + }, + { + .type = VSEC_TYPE_FLASH, + .ep_name = XRT_MD_NODE_FLASH_VSEC, + .size = 4096, + .compat = "vsec-flash", + }, + { + .type = VSEC_TYPE_PLATINFO, + .ep_name = XRT_MD_NODE_PLAT_INFO, + .size = 4, + .compat = "vsec-platinfo", + }, + { + .type = VSEC_TYPE_MAILBOX, + .ep_name = XRT_MD_NODE_MAILBOX_VSEC, + .size = 48, + .compat = "vsec-mbx", + }, +}; + +XRT_DEFINE_REGMAP_CONFIG(vsec_regmap_config); + +struct xrt_vsec { + struct xrt_device *xdev; + struct regmap *regmap; + u32 length; + + char *metadata; + char uuid[VSEC_UUID_LEN]; + int group; +}; + +static inline int vsec_read_entry(struct xrt_vsec *vsec, u32 index, struct xrt_vsec_entry *entry) +{ + int ret; + + ret = regmap_bulk_read(vsec->regmap, sizeof(struct xrt_vsec_header) + + index * sizeof(struct xrt_vsec_entry), entry, + sizeof(struct xrt_vsec_entry) / + vsec_regmap_config.reg_stride); + + return ret; +} + +static inline u32 vsec_get_bar(struct xrt_vsec_entry *entry) +{ + return (entry->bar_rev >> 4) & 0xf; +} + +static inline u64 vsec_get_bar_off(struct xrt_vsec_entry *entry) +{ + return entry->off_lo | ((u64)entry->off_hi << 16); +} + +static inline u32 vsec_get_rev(struct xrt_vsec_entry *entry) +{ + return entry->bar_rev & 0xf; +} + +static char *type2epname(u32 type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vsec_devs); i++) { + if (vsec_devs[i].type == type) + return (vsec_devs[i].ep_name); + } + + return NULL; +} + +static ulong type2size(u32 type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vsec_devs); i++) { + if (vsec_devs[i].type == type) + return (vsec_devs[i].size); + } + + return 0; +} + +static char *type2compat(u32 type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vsec_devs); i++) { + if (vsec_devs[i].type == type) + return (vsec_devs[i].compat); + } + + return NULL; +} + +static int xrt_vsec_add_node(struct xrt_vsec *vsec, + void *md_blob, struct xrt_vsec_entry *p_entry) +{ + struct xrt_md_endpoint ep; + char compat_ver[64]; + int ret; + + if (!type2epname(p_entry->type)) + return -EINVAL; + + /* + * VSEC may have more than 1 mailbox instance for the card + * which has more than 1 physical function. + * This is not supported for now. Assuming only one mailbox + */ + + snprintf(compat_ver, sizeof(compat_ver) - 1, "%d-%d.%d.%d", + p_entry->ver_type, p_entry->major, p_entry->minor, + vsec_get_rev(p_entry)); + ep.ep_name = type2epname(p_entry->type); + ep.bar_index = vsec_get_bar(p_entry); + ep.bar_off = vsec_get_bar_off(p_entry); + ep.size = type2size(p_entry->type); + ep.compat = type2compat(p_entry->type); + ep.compat_ver = compat_ver; + ret = xrt_md_add_endpoint(DEV(vsec->xdev), vsec->metadata, &ep); + if (ret) + xrt_err(vsec->xdev, "add ep failed, ret %d", ret); + + return ret; +} + +static int xrt_vsec_create_metadata(struct xrt_vsec *vsec) +{ + struct xrt_vsec_entry entry; + int i, ret; + + ret = xrt_md_create(&vsec->xdev->dev, &vsec->metadata); + if (ret) { + xrt_err(vsec->xdev, "create metadata failed"); + return ret; + } + + for (i = 0; i * sizeof(entry) < vsec->length - + sizeof(struct xrt_vsec_header); i++) { + ret = vsec_read_entry(vsec, i, &entry); + if (ret) { + xrt_err(vsec->xdev, "failed read entry %d, ret %d", i, ret); + goto fail; + } + + if (entry.type == VSEC_TYPE_END) + break; + ret = xrt_vsec_add_node(vsec, vsec->metadata, &entry); + if (ret) + goto fail; + } + + return 0; + +fail: + vfree(vsec->metadata); + vsec->metadata = NULL; + return ret; +} + +static int xrt_vsec_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + int ret = 0; + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + default: + ret = -EINVAL; + xrt_err(xdev, "should never been called"); + break; + } + + return ret; +} + +static int xrt_vsec_mapio(struct xrt_vsec *vsec) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(vsec->xdev); + struct resource *res = NULL; + void __iomem *base = NULL; + const __be64 *bar_off; + const __be32 *bar; + u64 addr; + int ret; + + if (!pdata || xrt_md_size(DEV(vsec->xdev), pdata->xsp_dtb) == XRT_MD_INVALID_LENGTH) { + xrt_err(vsec->xdev, "empty metadata"); + return -EINVAL; + } + + ret = xrt_md_get_prop(DEV(vsec->xdev), pdata->xsp_dtb, XRT_MD_NODE_VSEC, + NULL, XRT_MD_PROP_BAR_IDX, (const void **)&bar, NULL); + if (ret) { + xrt_err(vsec->xdev, "failed to get bar idx, ret %d", ret); + return -EINVAL; + } + + ret = xrt_md_get_prop(DEV(vsec->xdev), pdata->xsp_dtb, XRT_MD_NODE_VSEC, + NULL, XRT_MD_PROP_OFFSET, (const void **)&bar_off, NULL); + if (ret) { + xrt_err(vsec->xdev, "failed to get bar off, ret %d", ret); + return -EINVAL; + } + + xrt_info(vsec->xdev, "Map vsec at bar %d, offset 0x%llx", + be32_to_cpu(*bar), be64_to_cpu(*bar_off)); + + xleaf_get_root_res(vsec->xdev, be32_to_cpu(*bar), &res); + if (!res) { + xrt_err(vsec->xdev, "failed to get bar addr"); + return -EINVAL; + } + + addr = res->start + be64_to_cpu(*bar_off); + + base = devm_ioremap(&vsec->xdev->dev, addr, vsec_regmap_config.max_register); + if (!base) { + xrt_err(vsec->xdev, "Map failed"); + return -EIO; + } + + vsec->regmap = devm_regmap_init_mmio(&vsec->xdev->dev, base, &vsec_regmap_config); + if (IS_ERR(vsec->regmap)) { + xrt_err(vsec->xdev, "regmap %pR failed", res); + return PTR_ERR(vsec->regmap); + } + + ret = regmap_read(vsec->regmap, VSEC_REG_LENGTH, &vsec->length); + if (ret) { + xrt_err(vsec->xdev, "failed to read length %d", ret); + return ret; + } + + return 0; +} + +static void xrt_vsec_remove(struct xrt_device *xdev) +{ + struct xrt_vsec *vsec; + + vsec = xrt_get_drvdata(xdev); + + if (vsec->group >= 0) + xleaf_destroy_group(xdev, vsec->group); + vfree(vsec->metadata); +} + +static int xrt_vsec_probe(struct xrt_device *xdev) +{ + struct xrt_vsec *vsec; + int ret = 0; + + vsec = devm_kzalloc(&xdev->dev, sizeof(*vsec), GFP_KERNEL); + if (!vsec) + return -ENOMEM; + + vsec->xdev = xdev; + vsec->group = -1; + xrt_set_drvdata(xdev, vsec); + + ret = xrt_vsec_mapio(vsec); + if (ret) + goto failed; + + ret = xrt_vsec_create_metadata(vsec); + if (ret) { + xrt_err(xdev, "create metadata failed, ret %d", ret); + goto failed; + } + ret = xleaf_create_group(xdev, vsec->metadata); + if (ret < 0) { + xrt_err(xdev, "create group failed, ret %d", vsec->group); + goto failed; + } + vsec->group = ret; + + return 0; + +failed: + xrt_vsec_remove(xdev); + + return ret; +} + +static struct xrt_dev_endpoints xrt_vsec_endpoints[] = { + { + .xse_names = (struct xrt_dev_ep_names []){ + { .ep_name = XRT_MD_NODE_VSEC }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_driver xrt_vsec_driver = { + .driver = { + .name = XRT_VSEC, + }, + .subdev_id = XRT_SUBDEV_VSEC, + .endpoints = xrt_vsec_endpoints, + .probe = xrt_vsec_probe, + .remove = xrt_vsec_remove, + .leaf_call = xrt_vsec_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(vsec); From patchwork Wed May 12 01:53:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435838 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5D897C433B4 for ; Wed, 12 May 2021 02:00:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3F4A66191D for ; Wed, 12 May 2021 02:00:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230372AbhELCBo (ORCPT ); Tue, 11 May 2021 22:01:44 -0400 Received: from mail-bn8nam12on2051.outbound.protection.outlook.com ([40.107.237.51]:51377 "EHLO NAM12-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230104AbhELCBo (ORCPT ); Tue, 11 May 2021 22:01:44 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=abgWO8kRKo66w2JSbqxJtBH0JjBp8bTQyoZ4p3AyPnMlPQn46W+srb9V+oJbNhtVH+GOy7Zmje8/C3RKR/9Gp9WcP9J4Uke3uxgNc9QktPmBO97H70IrETRs/bais/OqEnyuZs8o6GBjmNSn33Gr4vmOX3LqQsw9TOl/YDTRc7sGrP6HrTOhLnP++eKuGz53dmvvVbx2M29EZONLgDN7Gp/vUP1ZdshKfQteOitrYbaU/5sCscR+dBUMEvSe8sm8UbutPgKZ/NFe4/RyZmQIj+/wHElBBAxVVXFjW++rLhDdGXybqSrus6DtI4JwXtrNADm+GauOEovAeBmlsiz59w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=H73oNWFUlPijWaqmttCUfHvL9wgxRm1nQnYKC4IQPPo=; b=W4b+0QL+91cOFlzZ9usMGy8r6hDTTunFJTUZapvBCd7CiRRxlTW8B/wkoHV9sTwSipI90JpvxbVSShcr41Z2y+PaivSRAsz+Uj3324aRwNFsTa1pE5bkBpw9GisjXTR5HnorPKKlAISv/PdzBp/e60XhqZqZfwaSk5PFTlRWHLobri97xEpuTdplz+dYBp3DJHn19Wf4stFM+QoWE3BEvslDcrJFeGXeSucHASseFhXuc7si514EyANJEYPibqLD47go5DiQfPO6ZgtonRVnzdHUzy2DpuaKdpiPgZQuqzbLLfWOFGq+h6BdogP9wJuTc+CA0kowac4FSV6obFTOGg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=H73oNWFUlPijWaqmttCUfHvL9wgxRm1nQnYKC4IQPPo=; b=GMlUTdw/geB3oN7BX5nF3PyE8PmIkIT3kCPqUexCNj5iV8Df+itm8GJpgMFsCpQyQ+h6EN0X8mzL4TdJDczJmeaEuGSMF//84XelkZjbhR7nIqbVxcTCs6gXJLIhn3Vtsm8yrVBwoiH1dzDTeTCet7meZqXSn3SSEcMETP9kjQU= Received: from BN9PR03CA0465.namprd03.prod.outlook.com (2603:10b6:408:139::20) by DM6PR02MB4410.namprd02.prod.outlook.com (2603:10b6:5:1e::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.26; Wed, 12 May 2021 02:00:34 +0000 Received: from BN1NAM02FT056.eop-nam02.prod.protection.outlook.com (2603:10b6:408:139:cafe::93) by BN9PR03CA0465.outlook.office365.com (2603:10b6:408:139::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 02:00:34 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT056.mail.protection.outlook.com (10.13.2.164) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 02:00:34 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 19:00:08 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 19:00:08 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35740 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lgeAR-0005mm-I5; Tue, 11 May 2021 19:00:08 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id B8D5A600131; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 14/20] fpga: xrt: ICAP driver Date: Tue, 11 May 2021 18:53:33 -0700 Message-ID: <20210512015339.5649-15-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: ed849bf1-7d25-48d9-1463-08d914e9baff X-MS-TrafficTypeDiagnostic: DM6PR02MB4410: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:6430; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: S9fMjDssK4rwaiUO6BfzhFu84GApe5ZCsiB2dfjZRXintGIIVaHJraP+rkLbcjtJbkS3BM2Xpx4MGj7d0idR04pusung1mUkjQxA2WbOmvqkYODU7n7dKorjzNB3CkD7sz8Y6OTjTIXH390FRKDmD712WTmZzI+Cyq5n6rpHgeaaahfzc3BcunISTXcsNQqwugJhdFUqiMDmVORQTGdJ6GigH5FCvvIWhtSza2APtnuev/vioVUFidZhwlZ5xK4whhqlhDRIxW+hl4SXzlUXfrKeRMZYFMysjWy3UeAi4h9A1sJUVMPPzLp3ev+8Q7xAgyQLWvjI3pxeQejEcGHC2uZj40PJJyi9L10UUYKGhhyrQIt1XeiCkeiN3kWlpPOD41uABmICJUA1S1QrcycxvdW5WSD9NASUfPULZc/wYztoVj3pwnTAmjYw173AnNQX4EOSqQqkluv3r3gXtPwt6UCPG4bIIY9CCtqzdWnmIPL0Oyvx2em0nBkw7WhIT1WwOGiDxUhpMulq2WtiR83f83+aMI06KqjWPBZT6BBu9ATgcYJ/QGKgZiWZGSblPHCnW9K2/hZm0PVbS1VOOe8aVjQP45T2HE87y7IeEPcPhv5GDkBJFbfznvv9jqiFLq3ikxNUsEVqY5unPhAaMp0wWH7NskSDImtek5jXgsHbZl7ShCRSZ4gimIIFI0qQv5TpyxOoqnl5yYO12K8aplAqTHXHFPn5By9N1RnQpCRoXUc= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch01.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(346002)(376002)(396003)(136003)(39850400004)(46966006)(36840700001)(8936002)(478600001)(7636003)(47076005)(8676002)(54906003)(36860700001)(6666004)(4326008)(966005)(186003)(356005)(5660300002)(6266002)(316002)(36906005)(82740400003)(1076003)(42186006)(36756003)(44832011)(70206006)(82310400003)(6916009)(2906002)(336012)(26005)(107886003)(426003)(70586007)(83380400001)(2616005); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 02:00:34.5381 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ed849bf1-7d25-48d9-1463-08d914e9baff X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT056.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR02MB4410 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org ICAP stands for Hardware Internal Configuration Access Port. ICAP is discovered by walking the firmware metadata. A xrt device node will be created for it. FPGA bitstream is written to hardware through ICAP. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/xleaf/icap.h | 27 +++ drivers/fpga/xrt/lib/xleaf/icap.c | 328 ++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/icap.h create mode 100644 drivers/fpga/xrt/lib/xleaf/icap.c diff --git a/drivers/fpga/xrt/include/xleaf/icap.h b/drivers/fpga/xrt/include/xleaf/icap.h new file mode 100644 index 000000000000..96d39a8934fa --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/icap.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_ICAP_H_ +#define _XRT_ICAP_H_ + +#include "xleaf.h" + +/* + * ICAP driver leaf calls. + */ +enum xrt_icap_leaf_cmd { + XRT_ICAP_WRITE = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_ICAP_GET_IDCODE, +}; + +struct xrt_icap_wr { + void *xiiw_bit_data; + u32 xiiw_data_len; +}; + +#endif /* _XRT_ICAP_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/icap.c b/drivers/fpga/xrt/lib/xleaf/icap.c new file mode 100644 index 000000000000..071923f61537 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/icap.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA ICAP Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + * Sonal Santan + * Max Zhen + */ + +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/icap.h" +#include "xclbin-helper.h" + +#define XRT_ICAP "xrt_icap" + +#define ICAP_ERR(icap, fmt, arg...) \ + xrt_err((icap)->xdev, fmt "\n", ##arg) +#define ICAP_WARN(icap, fmt, arg...) \ + xrt_warn((icap)->xdev, fmt "\n", ##arg) +#define ICAP_INFO(icap, fmt, arg...) \ + xrt_info((icap)->xdev, fmt "\n", ##arg) +#define ICAP_DBG(icap, fmt, arg...) \ + xrt_dbg((icap)->xdev, fmt "\n", ##arg) + +/* + * AXI-HWICAP IP register layout. Please see + * https://www.xilinx.com/support/documentation/ip_documentation/axi_hwicap/v3_0/pg134-axi-hwicap.pdf + */ +#define ICAP_REG_GIER 0x1C +#define ICAP_REG_ISR 0x20 +#define ICAP_REG_IER 0x28 +#define ICAP_REG_WF 0x100 +#define ICAP_REG_RF 0x104 +#define ICAP_REG_SZ 0x108 +#define ICAP_REG_CR 0x10C +#define ICAP_REG_SR 0x110 +#define ICAP_REG_WFV 0x114 +#define ICAP_REG_RFO 0x118 +#define ICAP_REG_ASR 0x11C + +#define ICAP_STATUS_EOS 0x4 +#define ICAP_STATUS_DONE 0x1 + +/* + * Canned command sequence to obtain IDCODE of the FPGA + */ +static const __be32 idcode_stream[] = { + /* dummy word */ + cpu_to_be32(0xffffffff), + /* sync word */ + cpu_to_be32(0xaa995566), + /* NOP word */ + cpu_to_be32(0x20000000), + /* NOP word */ + cpu_to_be32(0x20000000), + /* ID code */ + cpu_to_be32(0x28018001), + /* NOP word */ + cpu_to_be32(0x20000000), + /* NOP word */ + cpu_to_be32(0x20000000), +}; + +XRT_DEFINE_REGMAP_CONFIG(icap_regmap_config); + +struct icap { + struct xrt_device *xdev; + struct regmap *regmap; + struct mutex icap_lock; /* icap dev lock */ + u32 idcode; +}; + +static int wait_for_done(const struct icap *icap) +{ + int i = 0; + int ret; + u32 w; + + for (i = 0; i < 10; i++) { + /* + * it requires few micro seconds for ICAP to process incoming data. + * Polling every 5us for 10 times would be good enough. + */ + udelay(5); + ret = regmap_read(icap->regmap, ICAP_REG_SR, &w); + if (ret) + return ret; + ICAP_INFO(icap, "XHWICAP_SR: %x", w); + if (w & (ICAP_STATUS_EOS | ICAP_STATUS_DONE)) + return 0; + } + + ICAP_ERR(icap, "bitstream download timeout"); + return -ETIMEDOUT; +} + +static int icap_write(const struct icap *icap, const __be32 *word_buf, int size) +{ + u32 value = 0; + int ret; + int i; + + for (i = 0; i < size; i++) { + value = be32_to_cpu(word_buf[i]); + ret = regmap_write(icap->regmap, ICAP_REG_WF, value); + if (ret) + return ret; + } + + ret = regmap_write(icap->regmap, ICAP_REG_CR, 0x1); + if (ret) + return ret; + + for (i = 0; i < 20; i++) { + ret = regmap_read(icap->regmap, ICAP_REG_CR, &value); + if (ret) + return ret; + + if ((value & 0x1) == 0) + return 0; + ndelay(50); + } + + ICAP_ERR(icap, "writing %d dwords timeout", size); + return -EIO; +} + +static int bitstream_helper(struct icap *icap, const __be32 *word_buffer, + u32 word_count) +{ + int wr_fifo_vacancy = 0; + u32 word_written = 0; + u32 remain_word; + int err = 0; + + WARN_ON(!mutex_is_locked(&icap->icap_lock)); + for (remain_word = word_count; remain_word > 0; + remain_word -= word_written, word_buffer += word_written) { + err = regmap_read(icap->regmap, ICAP_REG_WFV, &wr_fifo_vacancy); + if (err) { + ICAP_ERR(icap, "read wr_fifo_vacancy failed %d", err); + break; + } + if (wr_fifo_vacancy <= 0) { + ICAP_ERR(icap, "no vacancy: %d", wr_fifo_vacancy); + err = -EIO; + break; + } + word_written = (wr_fifo_vacancy < remain_word) ? + wr_fifo_vacancy : remain_word; + if (icap_write(icap, word_buffer, word_written) != 0) { + ICAP_ERR(icap, "write failed remain %d, written %d", + remain_word, word_written); + err = -EIO; + break; + } + } + + return err; +} + +static int icap_download(struct icap *icap, const char *buffer, + unsigned long length) +{ + u32 num_chars_read = XCLBIN_HWICAP_BITFILE_BUF_SZ; + u32 byte_read; + int err = 0; + + if (length % sizeof(u32)) { + ICAP_ERR(icap, "invalid bitstream length %ld", length); + return -EINVAL; + } + + mutex_lock(&icap->icap_lock); + for (byte_read = 0; byte_read < length; byte_read += num_chars_read) { + num_chars_read = length - byte_read; + if (num_chars_read > XCLBIN_HWICAP_BITFILE_BUF_SZ) + num_chars_read = XCLBIN_HWICAP_BITFILE_BUF_SZ; + + err = bitstream_helper(icap, (__be32 *)buffer, num_chars_read / sizeof(u32)); + if (err) + goto failed; + buffer += num_chars_read; + } + + /* there is not any cleanup needs to be done if writing ICAP timeout. */ + err = wait_for_done(icap); + +failed: + mutex_unlock(&icap->icap_lock); + + return err; +} + +/* + * Discover the FPGA IDCODE using special sequence of canned commands + */ +static int icap_probe_chip(struct icap *icap) +{ + int err; + u32 val = 0; + + regmap_read(icap->regmap, ICAP_REG_SR, &val); + if (val != ICAP_STATUS_DONE) + return -ENODEV; + /* Read ICAP FIFO vacancy */ + regmap_read(icap->regmap, ICAP_REG_WFV, &val); + if (val < 8) + return -ENODEV; + err = icap_write(icap, idcode_stream, ARRAY_SIZE(idcode_stream)); + if (err) + return err; + err = wait_for_done(icap); + if (err) + return err; + + /* Tell config engine how many words to transfer to read FIFO */ + regmap_write(icap->regmap, ICAP_REG_SZ, 0x1); + /* Switch the ICAP to read mode */ + regmap_write(icap->regmap, ICAP_REG_CR, 0x2); + err = wait_for_done(icap); + if (err) + return err; + + /* Read IDCODE from Read FIFO */ + regmap_read(icap->regmap, ICAP_REG_RF, &icap->idcode); + return 0; +} + +static int +xrt_icap_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + struct xrt_icap_wr *wr_arg = arg; + struct icap *icap; + int ret = 0; + + icap = xrt_get_drvdata(xdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + case XRT_ICAP_WRITE: + ret = icap_download(icap, wr_arg->xiiw_bit_data, + wr_arg->xiiw_data_len); + break; + case XRT_ICAP_GET_IDCODE: + *(u32 *)arg = icap->idcode; + break; + default: + ICAP_ERR(icap, "unknown command %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int xrt_icap_probe(struct xrt_device *xdev) +{ + void __iomem *base = NULL; + struct resource *res; + struct icap *icap; + int result = 0; + + icap = devm_kzalloc(&xdev->dev, sizeof(*icap), GFP_KERNEL); + if (!icap) + return -ENOMEM; + + icap->xdev = xdev; + xrt_set_drvdata(xdev, icap); + mutex_init(&icap->icap_lock); + + xrt_info(xdev, "probing"); + res = xrt_get_resource(xdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + base = devm_ioremap_resource(&xdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + icap->regmap = devm_regmap_init_mmio(&xdev->dev, base, &icap_regmap_config); + if (IS_ERR(icap->regmap)) { + ICAP_ERR(icap, "init mmio failed"); + return PTR_ERR(icap->regmap); + } + /* Disable ICAP interrupts */ + regmap_write(icap->regmap, ICAP_REG_GIER, 0); + + result = icap_probe_chip(icap); + if (result) + xrt_err(xdev, "Failed to probe FPGA"); + else + xrt_info(xdev, "Discovered FPGA IDCODE %x", icap->idcode); + return result; +} + +static struct xrt_dev_endpoints xrt_icap_endpoints[] = { + { + .xse_names = (struct xrt_dev_ep_names[]) { + { .ep_name = XRT_MD_NODE_FPGA_CONFIG }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_driver xrt_icap_driver = { + .driver = { + .name = XRT_ICAP, + }, + .subdev_id = XRT_SUBDEV_ICAP, + .endpoints = xrt_icap_endpoints, + .probe = xrt_icap_probe, + .leaf_call = xrt_icap_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(icap); From patchwork Wed May 12 01:53:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435837 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 532A4C43460 for ; Wed, 12 May 2021 02:01:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 32BDE616E9 for ; Wed, 12 May 2021 02:01:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230183AbhELCCR (ORCPT ); Tue, 11 May 2021 22:02:17 -0400 Received: from mail-co1nam11on2074.outbound.protection.outlook.com ([40.107.220.74]:36161 "EHLO NAM11-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230172AbhELCCQ (ORCPT ); Tue, 11 May 2021 22:02:16 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Q6VRY0dAzxb8CVIWJ6wTrUKrJEGnUgn6uBziArcQhpRGCDRm4JhzfkSyTuuz/GTxsSTPCmk5/T3hO8HWri1qzaMRK/9fUJXgf9RwGU+FxYpgcfD/P3iLoh0U9XL3KzF2cQTOusg27NsVStJZ59V/sHCP/1OITnCL37hdp2LFX9MRD+Dumoics41Uq4XeLaqf9kbscn70xtFKAXu6I3XK67hEPuMNepNEe1WYqM+U4EGR9E4MLvWq8WBeweiPSr9DFqWBjhbI+jb2veA8zrQY4k70mnl4XChmNDLf5SNmwecb8DiewNjlqm9/fLm80DtiGfX62kkC9tfTJNTMwvRS9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=UF2746tPR4L0dSWfP0X6nQnsHIVIbqNag7Dad97Nycw=; b=b3mAWDYnpV2bHIFYBOgFZOhFDlLsNXgKmIT+T7zc3hkZdcckzLl2yTSvA1Hn8K5HjzOCiA2f04zyTzYZpfxf0DiibGKFNIRkiYnB8NT64n5npWiBQlSTNAM60rtsZfYcTnGntXLNoKYn21kxwhgsv2rza9N0uwIB8cetNdQnshZgcg71ynH79r+yEWMGVd3f2RpZUZluP4xbEPQeV/Cx6CdjdDZWvhcZRYVNHfYsvQXi2ZWksQB6DBxFU1cOtOURyhbreQy1kQpA6RQtRk44qsdHMmZQ7bQi7BzAUbydXypctYe0O5mXzE0Vo1PsFsjojIlqoer4AOILKOpab+ZWkA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=UF2746tPR4L0dSWfP0X6nQnsHIVIbqNag7Dad97Nycw=; b=fp8ekv+fc6QXD3P8tf9PuY4IhmRk0LFT/N3E1ZAQprrti5rXrX7TR6lLqaf/w6jCnSDrZ0hixNE03o6iG37GuxN0aSqBxlS7Vhx9xHLD3O6gNgR43avpaV417kguye7MzH+2zKou38MMZrX5lE//hndAG2YvO6scklgsYQDBlSg= Received: from BN6PR1401CA0023.namprd14.prod.outlook.com (2603:10b6:405:4b::33) by CO6PR02MB7748.namprd02.prod.outlook.com (2603:10b6:303:a6::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25; Wed, 12 May 2021 02:01:08 +0000 Received: from BN1NAM02FT005.eop-nam02.prod.protection.outlook.com (2603:10b6:405:4b:cafe::78) by BN6PR1401CA0023.outlook.office365.com (2603:10b6:405:4b::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.25 via Frontend Transport; Wed, 12 May 2021 02:01:08 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by BN1NAM02FT005.mail.protection.outlook.com (10.13.2.124) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 02:01:08 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 19:00:32 -0700 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 19:00:32 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35744 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lgeAq-0006AI-Nk; Tue, 11 May 2021 19:00:32 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id DC9CB600133; Tue, 11 May 2021 18:53:45 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 16/20] fpga: xrt: clock driver Date: Tue, 11 May 2021 18:53:35 -0700 Message-ID: <20210512015339.5649-17-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: db50471f-c605-4bb0-fd0e-08d914e9cf07 X-MS-TrafficTypeDiagnostic: CO6PR02MB7748: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1923; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: /aqocu1WAI8Q6x+7nqlM3cpy/osuJWG3ZIKOIp6OWTknNVlUVYQLw1ZP1lqfrrTTfU78MVefWTW5x4+lNGguoeLTFxE6qcQ+akiS9+BCcwVQUPbw7TTUs5p3ikqJaBoF4ZFsxEw/g4xfLo5N4dod4J21DYU0mOlxDrslIBFS60d3+VeUOb1ySvllJzD8aV8ojT3sjYuuK5iE3OwlSiwAuRzx4q6htMdFqiFkhQne6dA331gyGx3JG7D1ZrYeD525OFnHEqluPWlguPtheDfRryUD3XNwP7wRo2xGTnYDiekIMgCTMeMb+b+Q5HHfU8jdcRwwKmuyn7S1GV7NQ7tuInwAlOAvNOQMNaGQxfwmZ4wBsDwXIbQTQ52q7Qzf55bmXZJHJ+6geixBzLXP5j3c5QKv3eH9Xjbt6bLVcpb+vY//8nT3O5Jd5tl84RuPEe9VofxjMEHO2MH0LFiKEybGfIdXvA/Xl7ru3Gd+4q0CWaiV37WU6rytROOH02DPHUBg/kp/r8cXlsQMmYoJ/fMPUr3VWqBKQ2+LoV3PmrOUT3jIe/dPPMSunb2vyxpYT3xylee9g2bpod3jH2OaIRtKhw6nUzMXiFS/4+m+t7KOSvVkFKzQMpNQZc7Rk1nAUnluxXppKuAOkMHe3DG3btV43GlSnu6sBkTTybePigPOhIE= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch01.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(396003)(39850400004)(376002)(346002)(136003)(46966006)(36840700001)(44832011)(36756003)(36860700001)(82310400003)(1076003)(478600001)(6266002)(42186006)(82740400003)(426003)(26005)(36906005)(30864003)(6916009)(83380400001)(54906003)(2616005)(4326008)(5660300002)(70586007)(8676002)(336012)(7636003)(107886003)(2906002)(186003)(70206006)(6666004)(47076005)(356005)(316002)(8936002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 02:01:08.1489 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: db50471f-c605-4bb0-fd0e-08d914e9cf07 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch01.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: BN1NAM02FT005.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR02MB7748 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add clock driver. Clock is a hardware function discovered by walking xclbin metadata. A xrt device node will be created for it. Other part of driver configures clock through clock driver. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/xleaf/clock.h | 29 ++ drivers/fpga/xrt/lib/xleaf/clock.c | 652 +++++++++++++++++++++++++ 2 files changed, 681 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/clock.h create mode 100644 drivers/fpga/xrt/lib/xleaf/clock.c diff --git a/drivers/fpga/xrt/include/xleaf/clock.h b/drivers/fpga/xrt/include/xleaf/clock.h new file mode 100644 index 000000000000..6858473fd096 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/clock.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_CLOCK_H_ +#define _XRT_CLOCK_H_ + +#include "xleaf.h" +#include + +/* + * CLOCK driver leaf calls. + */ +enum xrt_clock_leaf_cmd { + XRT_CLOCK_SET = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_CLOCK_GET, + XRT_CLOCK_VERIFY, +}; + +struct xrt_clock_get { + u16 freq; + u32 freq_cnter; +}; + +#endif /* _XRT_CLOCK_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/clock.c b/drivers/fpga/xrt/lib/xleaf/clock.c new file mode 100644 index 000000000000..ba672fe99a47 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/clock.c @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Clock Wizard Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + * Sonal Santan + * David Zhang + */ + +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/clock.h" +#include "xleaf/clkfreq.h" + +/* XRT_CLOCK_MAX_NUM_CLOCKS should be a concept from XCLBIN_ in the future */ +#define XRT_CLOCK_MAX_NUM_CLOCKS 4 +#define XRT_CLOCK_STATUS_MASK 0xffff +#define XRT_CLOCK_STATUS_MEASURE_START 0x1 +#define XRT_CLOCK_STATUS_MEASURE_DONE 0x2 + +#define XRT_CLOCK_STATUS_REG 0x4 +#define XRT_CLOCK_CLKFBOUT_REG 0x200 +#define XRT_CLOCK_CLKOUT0_REG 0x208 +#define XRT_CLOCK_LOAD_SADDR_SEN_REG 0x25C +#define XRT_CLOCK_DEFAULT_EXPIRE_SECS 1 + +#define CLOCK_ERR(clock, fmt, arg...) \ + xrt_err((clock)->xdev, fmt "\n", ##arg) +#define CLOCK_WARN(clock, fmt, arg...) \ + xrt_warn((clock)->xdev, fmt "\n", ##arg) +#define CLOCK_INFO(clock, fmt, arg...) \ + xrt_info((clock)->xdev, fmt "\n", ##arg) +#define CLOCK_DBG(clock, fmt, arg...) \ + xrt_dbg((clock)->xdev, fmt "\n", ##arg) + +#define XRT_CLOCK "xrt_clock" + +XRT_DEFINE_REGMAP_CONFIG(clock_regmap_config); + +struct clock { + struct xrt_device *xdev; + struct regmap *regmap; + struct mutex clock_lock; /* clock dev lock */ + + const char *clock_ep_name; +}; + +/* + * Precomputed table with config0 and config2 register values together with + * target frequency. The steps are approximately 5 MHz apart. Table is + * generated by platform creation tool. + */ +static const struct xmgmt_ocl_clockwiz { + /* target frequency */ + u16 ocl; + /* config0 register */ + u32 config0; + /* config2 register */ + u32 config2; +} frequency_table[] = { + /*1275.000*/ { 10, 0x02EE0C01, 0x0001F47F }, + /*1575.000*/ { 15, 0x02EE0F01, 0x00000069}, + /*1600.000*/ { 20, 0x00001001, 0x00000050}, + /*1600.000*/ { 25, 0x00001001, 0x00000040}, + /*1575.000*/ { 30, 0x02EE0F01, 0x0001F434}, + /*1575.000*/ { 35, 0x02EE0F01, 0x0000002D}, + /*1600.000*/ { 40, 0x00001001, 0x00000028}, + /*1575.000*/ { 45, 0x02EE0F01, 0x00000023}, + /*1600.000*/ { 50, 0x00001001, 0x00000020}, + /*1512.500*/ { 55, 0x007D0F01, 0x0001F41B}, + /*1575.000*/ { 60, 0x02EE0F01, 0x0000FA1A}, + /*1462.500*/ { 65, 0x02710E01, 0x0001F416}, + /*1575.000*/ { 70, 0x02EE0F01, 0x0001F416}, + /*1575.000*/ { 75, 0x02EE0F01, 0x00000015}, + /*1600.000*/ { 80, 0x00001001, 0x00000014}, + /*1487.500*/ { 85, 0x036B0E01, 0x0001F411}, + /*1575.000*/ { 90, 0x02EE0F01, 0x0001F411}, + /*1425.000*/ { 95, 0x00FA0E01, 0x0000000F}, + /*1600.000*/ { 100, 0x00001001, 0x00000010}, + /*1575.000*/ { 105, 0x02EE0F01, 0x0000000F}, + /*1512.500*/ { 110, 0x007D0F01, 0x0002EE0D}, + /*1437.500*/ { 115, 0x01770E01, 0x0001F40C}, + /*1575.000*/ { 120, 0x02EE0F01, 0x00007D0D}, + /*1562.500*/ { 125, 0x02710F01, 0x0001F40C}, + /*1462.500*/ { 130, 0x02710E01, 0x0000FA0B}, + /*1350.000*/ { 135, 0x01F40D01, 0x0000000A}, + /*1575.000*/ { 140, 0x02EE0F01, 0x0000FA0B}, + /*1450.000*/ { 145, 0x01F40E01, 0x0000000A}, + /*1575.000*/ { 150, 0x02EE0F01, 0x0001F40A}, + /*1550.000*/ { 155, 0x01F40F01, 0x0000000A}, + /*1600.000*/ { 160, 0x00001001, 0x0000000A}, + /*1237.500*/ { 165, 0x01770C01, 0x0001F407}, + /*1487.500*/ { 170, 0x036B0E01, 0x0002EE08}, + /*1575.000*/ { 175, 0x02EE0F01, 0x00000009}, + /*1575.000*/ { 180, 0x02EE0F01, 0x0002EE08}, + /*1387.500*/ { 185, 0x036B0D01, 0x0001F407}, + /*1425.000*/ { 190, 0x00FA0E01, 0x0001F407}, + /*1462.500*/ { 195, 0x02710E01, 0x0001F407}, + /*1600.000*/ { 200, 0x00001001, 0x00000008}, + /*1537.500*/ { 205, 0x01770F01, 0x0001F407}, + /*1575.000*/ { 210, 0x02EE0F01, 0x0001F407}, + /*1075.000*/ { 215, 0x02EE0A01, 0x00000005}, + /*1512.500*/ { 220, 0x007D0F01, 0x00036B06}, + /*1575.000*/ { 225, 0x02EE0F01, 0x00000007}, + /*1437.500*/ { 230, 0x01770E01, 0x0000FA06}, + /*1175.000*/ { 235, 0x02EE0B01, 0x00000005}, + /*1500.000*/ { 240, 0x00000F01, 0x0000FA06}, + /*1225.000*/ { 245, 0x00FA0C01, 0x00000005}, + /*1562.500*/ { 250, 0x02710F01, 0x0000FA06}, + /*1275.000*/ { 255, 0x02EE0C01, 0x00000005}, + /*1462.500*/ { 260, 0x02710E01, 0x00027105}, + /*1325.000*/ { 265, 0x00FA0D01, 0x00000005}, + /*1350.000*/ { 270, 0x01F40D01, 0x00000005}, + /*1512.500*/ { 275, 0x007D0F01, 0x0001F405}, + /*1575.000*/ { 280, 0x02EE0F01, 0x00027105}, + /*1425.000*/ { 285, 0x00FA0E01, 0x00000005}, + /*1450.000*/ { 290, 0x01F40E01, 0x00000005}, + /*1475.000*/ { 295, 0x02EE0E01, 0x00000005}, + /*1575.000*/ { 300, 0x02EE0F01, 0x0000FA05}, + /*1525.000*/ { 305, 0x00FA0F01, 0x00000005}, + /*1550.000*/ { 310, 0x01F40F01, 0x00000005}, + /*1575.000*/ { 315, 0x02EE0F01, 0x00000005}, + /*1600.000*/ { 320, 0x00001001, 0x00000005}, + /*1462.500*/ { 325, 0x02710E01, 0x0001F404}, + /*1237.500*/ { 330, 0x01770C01, 0x0002EE03}, + /* 837.500*/ { 335, 0x01770801, 0x0001F402}, + /*1487.500*/ { 340, 0x036B0E01, 0x00017704}, + /* 862.500*/ { 345, 0x02710801, 0x0001F402}, + /*1575.000*/ { 350, 0x02EE0F01, 0x0001F404}, + /* 887.500*/ { 355, 0x036B0801, 0x0001F402}, + /*1575.000*/ { 360, 0x02EE0F01, 0x00017704}, + /* 912.500*/ { 365, 0x007D0901, 0x0001F402}, + /*1387.500*/ { 370, 0x036B0D01, 0x0002EE03}, + /*1500.000*/ { 375, 0x00000F01, 0x00000004}, + /*1425.000*/ { 380, 0x00FA0E01, 0x0002EE03}, + /* 962.500*/ { 385, 0x02710901, 0x0001F402}, + /*1462.500*/ { 390, 0x02710E01, 0x0002EE03}, + /* 987.500*/ { 395, 0x036B0901, 0x0001F402}, + /*1600.000*/ { 400, 0x00001001, 0x00000004}, + /*1012.500*/ { 405, 0x007D0A01, 0x0001F402}, + /*1537.500*/ { 410, 0x01770F01, 0x0002EE03}, + /*1037.500*/ { 415, 0x01770A01, 0x0001F402}, + /*1575.000*/ { 420, 0x02EE0F01, 0x0002EE03}, + /*1487.500*/ { 425, 0x036B0E01, 0x0001F403}, + /*1075.000*/ { 430, 0x02EE0A01, 0x0001F402}, + /*1087.500*/ { 435, 0x036B0A01, 0x0001F402}, + /*1375.000*/ { 440, 0x02EE0D01, 0x00007D03}, + /*1112.500*/ { 445, 0x007D0B01, 0x0001F402}, + /*1575.000*/ { 450, 0x02EE0F01, 0x0001F403}, + /*1137.500*/ { 455, 0x01770B01, 0x0001F402}, + /*1437.500*/ { 460, 0x01770E01, 0x00007D03}, + /*1162.500*/ { 465, 0x02710B01, 0x0001F402}, + /*1175.000*/ { 470, 0x02EE0B01, 0x0001F402}, + /*1425.000*/ { 475, 0x00FA0E01, 0x00000003}, + /*1500.000*/ { 480, 0x00000F01, 0x00007D03}, + /*1212.500*/ { 485, 0x007D0C01, 0x0001F402}, + /*1225.000*/ { 490, 0x00FA0C01, 0x0001F402}, + /*1237.500*/ { 495, 0x01770C01, 0x0001F402}, + /*1562.500*/ { 500, 0x02710F01, 0x00007D03}, + /*1262.500*/ { 505, 0x02710C01, 0x0001F402}, + /*1275.000*/ { 510, 0x02EE0C01, 0x0001F402}, + /*1287.500*/ { 515, 0x036B0C01, 0x0001F402}, + /*1300.000*/ { 520, 0x00000D01, 0x0001F402}, + /*1575.000*/ { 525, 0x02EE0F01, 0x00000003}, + /*1325.000*/ { 530, 0x00FA0D01, 0x0001F402}, + /*1337.500*/ { 535, 0x01770D01, 0x0001F402}, + /*1350.000*/ { 540, 0x01F40D01, 0x0001F402}, + /*1362.500*/ { 545, 0x02710D01, 0x0001F402}, + /*1512.500*/ { 550, 0x007D0F01, 0x0002EE02}, + /*1387.500*/ { 555, 0x036B0D01, 0x0001F402}, + /*1400.000*/ { 560, 0x00000E01, 0x0001F402}, + /*1412.500*/ { 565, 0x007D0E01, 0x0001F402}, + /*1425.000*/ { 570, 0x00FA0E01, 0x0001F402}, + /*1437.500*/ { 575, 0x01770E01, 0x0001F402}, + /*1450.000*/ { 580, 0x01F40E01, 0x0001F402}, + /*1462.500*/ { 585, 0x02710E01, 0x0001F402}, + /*1475.000*/ { 590, 0x02EE0E01, 0x0001F402}, + /*1487.500*/ { 595, 0x036B0E01, 0x0001F402}, + /*1575.000*/ { 600, 0x02EE0F01, 0x00027102}, + /*1512.500*/ { 605, 0x007D0F01, 0x0001F402}, + /*1525.000*/ { 610, 0x00FA0F01, 0x0001F402}, + /*1537.500*/ { 615, 0x01770F01, 0x0001F402}, + /*1550.000*/ { 620, 0x01F40F01, 0x0001F402}, + /*1562.500*/ { 625, 0x02710F01, 0x0001F402}, + /*1575.000*/ { 630, 0x02EE0F01, 0x0001F402}, + /*1587.500*/ { 635, 0x036B0F01, 0x0001F402}, + /*1600.000*/ { 640, 0x00001001, 0x0001F402}, + /*1290.000*/ { 645, 0x01F44005, 0x00000002}, + /*1462.500*/ { 650, 0x02710E01, 0x0000FA02} +}; + +static u32 find_matching_freq_config(unsigned short freq, + const struct xmgmt_ocl_clockwiz *table, + int size) +{ + u32 end = size - 1; + u32 start = 0; + u32 idx; + + if (freq < table[0].ocl) + return 0; + + if (freq > table[size - 1].ocl) + return size - 1; + + while (start < end) { + idx = (start + end) / 2; + if (freq == table[idx].ocl) + break; + if (freq < table[idx].ocl) + end = idx; + else + start = idx + 1; + } + if (freq < table[idx].ocl) + idx--; + + return idx; +} + +static u32 find_matching_freq(u32 freq, + const struct xmgmt_ocl_clockwiz *freq_table, + int freq_table_size) +{ + int idx = find_matching_freq_config(freq, freq_table, freq_table_size); + + return freq_table[idx].ocl; +} + +static inline int clock_wiz_busy(struct clock *clock, int cycle, int interval) +{ + u32 val = 0; + int count; + int ret; + + for (count = 0; count < cycle; count++) { + ret = regmap_read(clock->regmap, XRT_CLOCK_STATUS_REG, &val); + if (ret) { + CLOCK_ERR(clock, "read status failed %d", ret); + return ret; + } + if (val == 1) + break; + + mdelay(interval); + } + if (val != 1) { + CLOCK_ERR(clock, "clockwiz is (%u) busy after %d ms", + val, cycle * interval); + return -EBUSY; + } + + return 0; +} + +static int get_freq(struct clock *clock, u16 *freq) +{ + u32 mul_frac0 = 0; + u32 div_frac1 = 0; + u32 mul0, div0; + u64 input; + u32 div1; + u32 val; + int ret; + + WARN_ON(!mutex_is_locked(&clock->clock_lock)); + + ret = regmap_read(clock->regmap, XRT_CLOCK_STATUS_REG, &val); + if (ret) { + CLOCK_ERR(clock, "read status failed %d", ret); + return ret; + } + + if ((val & 0x1) == 0) { + CLOCK_ERR(clock, "clockwiz is busy %x", val); + *freq = 0; + return -EBUSY; + } + + ret = regmap_read(clock->regmap, XRT_CLOCK_CLKFBOUT_REG, &val); + if (ret) { + CLOCK_ERR(clock, "read clkfbout failed %d", ret); + return ret; + } + + div0 = val & 0xff; + mul0 = (val & 0xff00) >> 8; + if (val & BIT(26)) { + mul_frac0 = val >> 16; + mul_frac0 &= 0x3ff; + } + + /* + * Multiply both numerator (mul0) and the denominator (div0) with 1000 + * to account for fractional portion of multiplier + */ + mul0 *= 1000; + mul0 += mul_frac0; + div0 *= 1000; + + ret = regmap_read(clock->regmap, XRT_CLOCK_CLKOUT0_REG, &val); + if (ret) { + CLOCK_ERR(clock, "read clkout0 failed %d", ret); + return ret; + } + + div1 = val & 0xff; + if (val & BIT(18)) { + div_frac1 = val >> 8; + div_frac1 &= 0x3ff; + } + + /* + * Multiply both numerator (mul0) and the denominator (div1) with + * 1000 to account for fractional portion of divider + */ + + div1 *= 1000; + div1 += div_frac1; + div0 *= div1; + mul0 *= 1000; + if (div0 == 0) { + CLOCK_ERR(clock, "clockwiz 0 divider"); + return 0; + } + + input = mul0 * 100; + do_div(input, div0); + *freq = (u16)input; + + return 0; +} + +static int set_freq(struct clock *clock, u16 freq) +{ + int err = 0; + u32 idx = 0; + u32 val = 0; + u32 config; + + mutex_lock(&clock->clock_lock); + idx = find_matching_freq_config(freq, frequency_table, + ARRAY_SIZE(frequency_table)); + + CLOCK_INFO(clock, "New: %d Mhz", freq); + err = clock_wiz_busy(clock, 20, 50); + if (err) + goto fail; + + config = frequency_table[idx].config0; + err = regmap_write(clock->regmap, XRT_CLOCK_CLKFBOUT_REG, config); + if (err) { + CLOCK_ERR(clock, "write clkfbout failed %d", err); + goto fail; + } + + config = frequency_table[idx].config2; + err = regmap_write(clock->regmap, XRT_CLOCK_CLKOUT0_REG, config); + if (err) { + CLOCK_ERR(clock, "write clkout0 failed %d", err); + goto fail; + } + + mdelay(10); + err = regmap_write(clock->regmap, XRT_CLOCK_LOAD_SADDR_SEN_REG, 7); + if (err) { + CLOCK_ERR(clock, "write load_saddr_sen failed %d", err); + goto fail; + } + + mdelay(1); + err = regmap_write(clock->regmap, XRT_CLOCK_LOAD_SADDR_SEN_REG, 2); + if (err) { + CLOCK_ERR(clock, "write saddr failed %d", err); + goto fail; + } + + CLOCK_INFO(clock, "clockwiz waiting for locked signal"); + + err = clock_wiz_busy(clock, 100, 100); + if (err) { + CLOCK_ERR(clock, "clockwiz MMCM/PLL did not lock"); + /* restore */ + regmap_write(clock->regmap, XRT_CLOCK_LOAD_SADDR_SEN_REG, 4); + mdelay(10); + regmap_write(clock->regmap, XRT_CLOCK_LOAD_SADDR_SEN_REG, 0); + goto fail; + } + regmap_read(clock->regmap, XRT_CLOCK_CLKFBOUT_REG, &val); + CLOCK_INFO(clock, "clockwiz CONFIG(0) 0x%x", val); + regmap_read(clock->regmap, XRT_CLOCK_CLKOUT0_REG, &val); + CLOCK_INFO(clock, "clockwiz CONFIG(2) 0x%x", val); + +fail: + mutex_unlock(&clock->clock_lock); + return err; +} + +static int get_freq_counter(struct clock *clock, u32 *freq) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(clock->xdev); + struct xrt_device *xdev = clock->xdev; + struct xrt_device *counter_leaf; + const void *counter; + int err; + + WARN_ON(!mutex_is_locked(&clock->clock_lock)); + + err = xrt_md_get_prop(DEV(xdev), pdata->xsp_dtb, clock->clock_ep_name, + NULL, XRT_MD_PROP_CLK_CNT, &counter, NULL); + if (err) { + xrt_err(xdev, "no counter specified"); + return err; + } + + counter_leaf = xleaf_get_leaf_by_epname(xdev, counter); + if (!counter_leaf) { + xrt_err(xdev, "can't find counter"); + return -ENOENT; + } + + err = xleaf_call(counter_leaf, XRT_CLKFREQ_READ, freq); + if (err) + xrt_err(xdev, "can't read counter"); + xleaf_put_leaf(clock->xdev, counter_leaf); + + return err; +} + +static int clock_get_freq(struct clock *clock, u16 *freq, u32 *freq_cnter) +{ + int err = 0; + + mutex_lock(&clock->clock_lock); + + if (err == 0 && freq) + err = get_freq(clock, freq); + + if (err == 0 && freq_cnter) + err = get_freq_counter(clock, freq_cnter); + + mutex_unlock(&clock->clock_lock); + return err; +} + +static int clock_verify_freq(struct clock *clock) +{ + u32 lookup_freq, clock_freq_counter, request_in_khz, tolerance; + int err = 0; + u16 freq; + + mutex_lock(&clock->clock_lock); + + err = get_freq(clock, &freq); + if (err) { + xrt_err(clock->xdev, "get freq failed, %d", err); + goto end; + } + + err = get_freq_counter(clock, &clock_freq_counter); + if (err) { + xrt_err(clock->xdev, "get freq counter failed, %d", err); + goto end; + } + + lookup_freq = find_matching_freq(freq, frequency_table, + ARRAY_SIZE(frequency_table)); + request_in_khz = lookup_freq * 1000; + tolerance = lookup_freq * 50; + if (tolerance < abs(clock_freq_counter - request_in_khz)) { + CLOCK_ERR(clock, + "set clock(%s) failed, request %ukhz, actual %dkhz", + clock->clock_ep_name, request_in_khz, clock_freq_counter); + err = -EDOM; + } else { + CLOCK_INFO(clock, "verified clock (%s)", clock->clock_ep_name); + } + +end: + mutex_unlock(&clock->clock_lock); + return err; +} + +static int clock_init(struct clock *clock) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(clock->xdev); + const __be16 *freq; + int err = 0; + + err = xrt_md_get_prop(DEV(clock->xdev), pdata->xsp_dtb, + clock->clock_ep_name, NULL, XRT_MD_PROP_CLK_FREQ, + (const void **)&freq, NULL); + if (err) { + xrt_info(clock->xdev, "no default freq"); + return 0; + } + + err = set_freq(clock, be16_to_cpu(*freq)); + + return err; +} + +static ssize_t freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct clock *clock = xrt_get_drvdata(to_xrt_dev(dev)); + ssize_t count; + u16 freq = 0; + + count = clock_get_freq(clock, &freq, NULL); + if (count < 0) + return count; + + count = snprintf(buf, 64, "%u\n", freq); + + return count; +} +static DEVICE_ATTR_RO(freq); + +static struct attribute *clock_attrs[] = { + &dev_attr_freq.attr, + NULL, +}; + +static struct attribute_group clock_attr_group = { + .attrs = clock_attrs, +}; + +static int +xrt_clock_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + struct clock *clock; + int ret = 0; + + clock = xrt_get_drvdata(xdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + case XRT_CLOCK_SET: { + u16 freq = (u16)(uintptr_t)arg; + + ret = set_freq(clock, freq); + break; + } + case XRT_CLOCK_VERIFY: + ret = clock_verify_freq(clock); + break; + case XRT_CLOCK_GET: { + struct xrt_clock_get *get = + (struct xrt_clock_get *)arg; + + ret = clock_get_freq(clock, &get->freq, &get->freq_cnter); + break; + } + default: + xrt_err(xdev, "unsupported cmd %d", cmd); + return -EINVAL; + } + + return ret; +} + +static void clock_remove(struct xrt_device *xdev) +{ + sysfs_remove_group(&xdev->dev.kobj, &clock_attr_group); +} + +static int clock_probe(struct xrt_device *xdev) +{ + struct clock *clock = NULL; + void __iomem *base = NULL; + struct resource *res; + int ret; + + clock = devm_kzalloc(&xdev->dev, sizeof(*clock), GFP_KERNEL); + if (!clock) + return -ENOMEM; + + xrt_set_drvdata(xdev, clock); + clock->xdev = xdev; + mutex_init(&clock->clock_lock); + + res = xrt_get_resource(xdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -EINVAL; + goto failed; + } + + base = devm_ioremap_resource(&xdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto failed; + } + + clock->regmap = devm_regmap_init_mmio(&xdev->dev, base, &clock_regmap_config); + if (IS_ERR(clock->regmap)) { + CLOCK_ERR(clock, "regmap %pR failed", res); + ret = PTR_ERR(clock->regmap); + goto failed; + } + clock->clock_ep_name = res->name; + + ret = clock_init(clock); + if (ret) + goto failed; + + ret = sysfs_create_group(&xdev->dev.kobj, &clock_attr_group); + if (ret) { + CLOCK_ERR(clock, "create clock attrs failed: %d", ret); + goto failed; + } + + CLOCK_INFO(clock, "successfully initialized Clock subdev"); + + return 0; + +failed: + return ret; +} + +static struct xrt_dev_endpoints xrt_clock_endpoints[] = { + { + .xse_names = (struct xrt_dev_ep_names[]) { + { .compat = "clkwiz" }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_driver xrt_clock_driver = { + .driver = { + .name = XRT_CLOCK, + }, + .subdev_id = XRT_SUBDEV_CLOCK, + .endpoints = xrt_clock_endpoints, + .probe = clock_probe, + .remove = clock_remove, + .leaf_call = xrt_clock_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(clock); From patchwork Wed May 12 01:53:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 435836 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C34E7C43462 for ; Wed, 12 May 2021 02:01:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A4A9961938 for ; Wed, 12 May 2021 02:01:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230153AbhELCCd (ORCPT ); Tue, 11 May 2021 22:02:33 -0400 Received: from mail-bn8nam11on2083.outbound.protection.outlook.com ([40.107.236.83]:26080 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230388AbhELCCc (ORCPT ); Tue, 11 May 2021 22:02:32 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lDJsbWm6wlFUd3Rdkc2qJ4EeZUNiEsDEDclhTnaXTtJ6CvY8mqGjzbuahxIKDHoRBe4rxsdvLA1JVxCETeX++d0cN8MW+SLWtULaHxFshHZbVmJxnu5Jtt9nub7JvKDBH4aDTywPtSJS8BdylroGozgJc6P6LgAHue1N7M8/Jdch8yLRalmqVRtb+5QBnmfnzq8q/A7br+2hVaCXeB6JKt6wVSepDhzFe9c+QQsx9kj24V0GqbRED41PF/AexHFxhfiVumS3i2Ez/bGhZCANj6yQI1uttq1B5gon6+Fwu6WbLtD7rgXrayUAHStnQC5muGlXVaejzfff8t/wmtVrYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bwGScXAKq1YCjyZe/LJC51PdA34ZIXAEmS7y0o7dfMs=; b=DVnVJmZTm5qCaPJW2CpVOTHy2Ydkw3n0Fsg4RJh7MAoF3FpQcb0OnKMff8x7FypNOBsgUpmvTsBSrFwF6tCF1AtBha8WtjT/U/yITuQLVhoeWaIXUOJBf5+0NnnesSS9pa/JlBuwpuFyrOwrbN8QHZDJ5uAU6a7lkxjyrSzhu5PYDIQ3GxQJ1XAMpZMSl6UBeikgaWtE79TDlZITw1yCon9AQfCmu/qEdROt5HAHnKdJjeSqXepA1Mj3NrzwWWEphqduefRp2QYPOEFSr4Fpiat8R/sjmzpuYALRJUYSX2my5XcLM1vN6qjE79z5QlEb7lD6m6XtlnCDIKhC/wLNtg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=kernel.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector2-xilinx-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bwGScXAKq1YCjyZe/LJC51PdA34ZIXAEmS7y0o7dfMs=; b=pg6moR9plHraclRcN6JT0Zl/QzydmD5hC7yMo8lKFuYUqgcy/xzYof1992RG8gIZv6DPQTezDX8mgzVTY3Qfvj/GKp4xWJ++6EuD97rlcXw52oviCHSb5LQBxTx3F4cxPzIbp6Wnb1F+nabcBMuexiMKwSAF5DCD/M8KiDJO50k= Received: from DM5PR21CA0014.namprd21.prod.outlook.com (2603:10b6:3:ac::24) by BYAPR02MB4886.namprd02.prod.outlook.com (2603:10b6:a03:46::32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4108.29; Wed, 12 May 2021 02:01:20 +0000 Received: from DM3NAM02FT023.eop-nam02.prod.protection.outlook.com (2603:10b6:3:ac:cafe::3) by DM5PR21CA0014.outlook.office365.com (2603:10b6:3:ac::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4150.0 via Frontend Transport; Wed, 12 May 2021 02:01:20 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=pass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.62.198 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.62.198; helo=xsj-pvapexch02.xlnx.xilinx.com; Received: from xsj-pvapexch02.xlnx.xilinx.com (149.199.62.198) by DM3NAM02FT023.mail.protection.outlook.com (10.13.5.127) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4065.21 via Frontend Transport; Wed, 12 May 2021 02:01:20 +0000 Received: from xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Tue, 11 May 2021 19:00:56 -0700 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch02.xlnx.xilinx.com (172.19.86.41) with Microsoft SMTP Server id 15.1.2176.2 via Frontend Transport; Tue, 11 May 2021 19:00:56 -0700 Envelope-to: mdf@kernel.org, robh@kernel.org, trix@redhat.com, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Received: from [172.19.72.212] (port=35748 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lgeBE-0002Ju-R6; Tue, 11 May 2021 19:00:56 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 09F84600135; Tue, 11 May 2021 18:53:46 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V6 XRT Alveo 18/20] fpga: xrt: DDR calibration driver Date: Tue, 11 May 2021 18:53:37 -0700 Message-ID: <20210512015339.5649-19-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210512015339.5649-1-lizhi.hou@xilinx.com> References: <20210512015339.5649-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 01db50a0-4609-4549-6ae6-08d914e9d648 X-MS-TrafficTypeDiagnostic: BYAPR02MB4886: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:311; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: kepnUP814vH2+Ukt6WeuJN9COuT2fwvmcKercsw+2LM2l+i3rlTLynFXTQL7n8GHsO6TlVGJxBvujYMcBv9ep0ryOsCMfLD7W5vSaGysLj+ZynZrSn3KUKbY6amHntdS2n1le7kCoyMPw6tb0IgKpJPmtXx56TJbmQIShqa0rKPg73IoJj9IpZVcT0pTXbBuFLRfOqjQkOOUBOn//plClgErkywpGPsf0V/SWDgsCU97Y7Kxn3IJlZgxqPfPOI+JxzsV2Wdma7RYM9OwHV+CsK7zxGto0fAEhUElUeKX2Nfvq4aJwJaLsPIc24LQM08gxg+4QxTk153eghQ/t7Ppyu1G8G2jzY9auiSirmZfMLGPHj77IAiKn7r35kuC3+dNCO+qjKJW20GQVOtgdEfs7vAksl0tHfz+CfVA/5Fjwafe/VRwNbEXoM8CnzsVetz1K0ADs2c3S6PQoKLUkbPpwgvWxNQxhA8f3+BvRNhYJGSohPYZenI4Vrq5a8EJMfI0/WlImKikRfwn2OGdbyHK4rUvPM/f2rVbIyqoJUj5zbpnCCS3mXmOcKAxvbTi78y7akoJWJkmsye8augOTAxcd0S273uS194JbeGGpYUuHhSXsc1n57Sm10wozcPM8uzQis/PMne4kthkvSw1Q4KGgTIxSoB83bwHteyegXES8OY= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(346002)(136003)(376002)(39850400004)(396003)(46966006)(36840700001)(2616005)(426003)(6916009)(336012)(54906003)(44832011)(316002)(36756003)(70586007)(1076003)(107886003)(70206006)(356005)(186003)(5660300002)(6266002)(82740400003)(4326008)(42186006)(7636003)(2906002)(36906005)(6666004)(8676002)(26005)(8936002)(478600001)(47076005)(82310400003)(36860700001)(83380400001); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 May 2021 02:01:20.3741 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 01db50a0-4609-4549-6ae6-08d914e9d648 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.62.198]; Helo=[xsj-pvapexch02.xlnx.xilinx.com] X-MS-Exchange-CrossTenant-AuthSource: DM3NAM02FT023.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB4886 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add DDR calibration driver. DDR calibration is a hardware function discovered by walking firmware metadata. A xrt device node will be created for it. Hardware provides DDR calibration status through this function. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- .../fpga/xrt/include/xleaf/ddr_calibration.h | 28 +++ drivers/fpga/xrt/lib/xleaf/ddr_calibration.c | 210 ++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/ddr_calibration.h create mode 100644 drivers/fpga/xrt/lib/xleaf/ddr_calibration.c diff --git a/drivers/fpga/xrt/include/xleaf/ddr_calibration.h b/drivers/fpga/xrt/include/xleaf/ddr_calibration.h new file mode 100644 index 000000000000..878740c26ca2 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/ddr_calibration.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_DDR_CALIBRATION_H_ +#define _XRT_DDR_CALIBRATION_H_ + +#include "xleaf.h" +#include + +/* + * Memory calibration driver leaf calls. + */ +enum xrt_calib_results { + XRT_CALIB_UNKNOWN = 0, + XRT_CALIB_SUCCEEDED, + XRT_CALIB_FAILED, +}; + +enum xrt_calib_leaf_cmd { + XRT_CALIB_RESULT = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ +}; + +#endif /* _XRT_DDR_CALIBRATION_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c b/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c new file mode 100644 index 000000000000..36a0937c9195 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA memory calibration driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * memory calibration + * + * Authors: + * Lizhi Hou + */ +#include +#include +#include "xclbin-helper.h" +#include "metadata.h" +#include "xleaf/ddr_calibration.h" + +#define XRT_CALIB "xrt_calib" + +#define XRT_CALIB_STATUS_REG 0 +#define XRT_CALIB_READ_RETRIES 20 +#define XRT_CALIB_READ_INTERVAL 500 /* ms */ + +XRT_DEFINE_REGMAP_CONFIG(calib_regmap_config); + +struct calib_cache { + struct list_head link; + const char *ep_name; + char *data; + u32 data_size; +}; + +struct calib { + struct xrt_device *xdev; + struct regmap *regmap; + struct mutex lock; /* calibration dev lock */ + struct list_head cache_list; + u32 cache_num; + enum xrt_calib_results result; +}; + +static void __calib_cache_clean_nolock(struct calib *calib) +{ + struct calib_cache *cache, *temp; + + list_for_each_entry_safe(cache, temp, &calib->cache_list, link) { + vfree(cache->data); + list_del(&cache->link); + vfree(cache); + } + calib->cache_num = 0; +} + +static void calib_cache_clean(struct calib *calib) +{ + mutex_lock(&calib->lock); + __calib_cache_clean_nolock(calib); + mutex_unlock(&calib->lock); +} + +static int calib_calibration(struct calib *calib) +{ + u32 times = XRT_CALIB_READ_RETRIES; + u32 status; + int ret; + + while (times != 0) { + ret = regmap_read(calib->regmap, XRT_CALIB_STATUS_REG, &status); + if (ret) { + xrt_err(calib->xdev, "failed to read status reg %d", ret); + return ret; + } + + if (status & BIT(0)) + break; + msleep(XRT_CALIB_READ_INTERVAL); + times--; + } + + if (!times) { + xrt_err(calib->xdev, + "MIG calibration timeout after bitstream download"); + return -ETIMEDOUT; + } + + xrt_info(calib->xdev, "took %dms", (XRT_CALIB_READ_RETRIES - times) * + XRT_CALIB_READ_INTERVAL); + return 0; +} + +static void xrt_calib_event_cb(struct xrt_device *xdev, void *arg) +{ + struct calib *calib = xrt_get_drvdata(xdev); + struct xrt_event *evt = (struct xrt_event *)arg; + enum xrt_events e = evt->xe_evt; + enum xrt_subdev_id id; + int ret; + + id = evt->xe_subdev.xevt_subdev_id; + + switch (e) { + case XRT_EVENT_POST_CREATION: + if (id == XRT_SUBDEV_UCS) { + ret = calib_calibration(calib); + if (ret) + calib->result = XRT_CALIB_FAILED; + else + calib->result = XRT_CALIB_SUCCEEDED; + } + break; + default: + xrt_dbg(xdev, "ignored event %d", e); + break; + } +} + +static void xrt_calib_remove(struct xrt_device *xdev) +{ + struct calib *calib = xrt_get_drvdata(xdev); + + calib_cache_clean(calib); +} + +static int xrt_calib_probe(struct xrt_device *xdev) +{ + void __iomem *base = NULL; + struct resource *res; + struct calib *calib; + int err = 0; + + calib = devm_kzalloc(&xdev->dev, sizeof(*calib), GFP_KERNEL); + if (!calib) + return -ENOMEM; + + calib->xdev = xdev; + xrt_set_drvdata(xdev, calib); + + res = xrt_get_resource(xdev, IORESOURCE_MEM, 0); + if (!res) { + err = -EINVAL; + goto failed; + } + + base = devm_ioremap_resource(&xdev->dev, res); + if (IS_ERR(base)) { + err = PTR_ERR(base); + goto failed; + } + + calib->regmap = devm_regmap_init_mmio(&xdev->dev, base, &calib_regmap_config); + if (IS_ERR(calib->regmap)) { + xrt_err(xdev, "Map iomem failed"); + err = PTR_ERR(calib->regmap); + goto failed; + } + + mutex_init(&calib->lock); + INIT_LIST_HEAD(&calib->cache_list); + + return 0; + +failed: + return err; +} + +static int +xrt_calib_leaf_call(struct xrt_device *xdev, u32 cmd, void *arg) +{ + struct calib *calib = xrt_get_drvdata(xdev); + int ret = 0; + + switch (cmd) { + case XRT_XLEAF_EVENT: + xrt_calib_event_cb(xdev, arg); + break; + case XRT_CALIB_RESULT: { + enum xrt_calib_results *r = (enum xrt_calib_results *)arg; + *r = calib->result; + break; + } + default: + xrt_err(xdev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } + return ret; +} + +static struct xrt_dev_endpoints xrt_calib_endpoints[] = { + { + .xse_names = (struct xrt_dev_ep_names[]) { + { .ep_name = XRT_MD_NODE_DDR_CALIB }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_driver xrt_calib_driver = { + .driver = { + .name = XRT_CALIB, + }, + .subdev_id = XRT_SUBDEV_CALIB, + .endpoints = xrt_calib_endpoints, + .probe = xrt_calib_probe, + .remove = xrt_calib_remove, + .leaf_call = xrt_calib_leaf_call, +}; + +XRT_LEAF_INIT_FINI_FUNC(calib);