From patchwork Wed Mar 24 05:29:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408379 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, URIBL_BLOCKED, 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 54B8EC433DB for ; Wed, 24 Mar 2021 05:33:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2A78F619E0 for ; Wed, 24 Mar 2021 05:33:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235266AbhCXFdW (ORCPT ); Wed, 24 Mar 2021 01:33:22 -0400 Received: from mail-bn8nam11on2040.outbound.protection.outlook.com ([40.107.236.40]:46817 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235256AbhCXFcw (ORCPT ); Wed, 24 Mar 2021 01:32:52 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WGiQaIi5EDBrNS0WnziKK/+z0hfTEzM8NDinvvksiSiW/39knabTmFSPBvIhz2zfkcPLh+gjvWX+ORkta926AFS960FW4ZxlB4cvt40jtq9kDxZDRlBX2x/K6dqcDkbuFs8RIxy23dVOcO9eu2LXG7XJo5mZsSvm/BUMQpuKewTra4NbHmqqqfWpXz8au3myecLfgTykkSmvxKDUVR5iOPLJr/pCESHTBvNbe8uSlGOgIeoisMRfCbtUPRWoT2PoDyx+XqdFbW4ksmQfNr938GaLuRwWIRCFmtalAa81mQryo3TjOidGEDtLt4k3CvnQB0fLNmxdkKPSFrZXHgtx4A== 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=NayytgDCo7sd0eWzc6k2eNt5Kti1QHC70tpR+cezanI=; b=TrRUko+n+EvtYsJq4CzkzTY/8anxjygEYEE3owxTgCImydMhzogFslmT9NKRN1gRoDZRiv2HN2hQcMN77Us8qIob8AFqgEjnI/Oxzh1WQts9L8oYWRhYTszyRe3Y4HQeigzNL9FVtfkqPNQWTqwdqLyMv+JYxVgymE8gEwJEfZwYQBr9jeAbcFhAcRUzs4TCiBy8lH0v29u7++fqh3ywXYkSsmWxfgwhgK5ivIbpvr0lWVQvOb7u+rLVAVlKW7tAsEP9m4k+iqgS0uW4ErA9c3mu0qY9tjSyBf4gr2wmesihYWj3Qi5Vs+Jz2+3sHUNbyLc9ACB2y3NnWfxotexjjg== 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=NayytgDCo7sd0eWzc6k2eNt5Kti1QHC70tpR+cezanI=; b=nhENJNejLyaKFAJlrBjnfeqj7Rvkfg+qHiUFasdOuiNsmQf0AaYyQtPaISwn1bNNozD6Vyaz+z7k3NVlFp69HA2LhJO22BmXmvODTMtgHBbKE9M/s+kkXq5CIbJ3CKgqdlm3P9OHYbXBeQ0Kls4Cpd8i11sdaR3G4Q/5XFoPo9Q= Received: from SN6PR16CA0056.namprd16.prod.outlook.com (2603:10b6:805:ca::33) by DM5PR02MB2682.namprd02.prod.outlook.com (2603:10b6:3:108::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:32:47 +0000 Received: from SN1NAM02FT057.eop-nam02.prod.protection.outlook.com (2603:10b6:805:ca:cafe::2c) by SN6PR16CA0056.outlook.office365.com (2603:10b6:805:ca::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:32:47 +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 SN1NAM02FT057.mail.protection.outlook.com (10.152.73.105) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:32:47 +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.2106.2; Tue, 23 Mar 2021 22:32:46 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:32:46 -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=51024 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOw8L-0004QB-U9; Tue, 23 Mar 2021 22:32:45 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id A7C9060011E; Tue, 23 Mar 2021 22:29:55 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 02/20] fpga: xrt: driver metadata helper functions Date: Tue, 23 Mar 2021 22:29:29 -0700 Message-ID: <20210324052947.27889-3-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 3980548e-2f99-4831-af82-08d8ee864207 X-MS-TrafficTypeDiagnostic: DM5PR02MB2682: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3173; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: s4V9mMKUxsA16ib73kM0+ur9DjFYMel69AT/wtONEYYRIZPPtsoTD5l8pI+9dwcq7X1FSRXCKDnn8OF/nkxdLOZTsj7/eqnaFDM/NiJ0PoiaGDqIsL+8Arg5cWtU9lf6UV9EEk5qxKjzfx0K2yCPlfmsh2HZNnvFGOG1yubWFb8ksBxTeH7wLoc5OKdXKkHVOrcm4cCcM3pnJcW18hEB89Fo0RwKHFgU2u/flQrJ87NUrdtdHQX20b+iUilh3N/LKTbD86zrGgqBhfaPkvjmJhbm4IwIZWUeutzebcdIZ7py1vJoxO3RRvbJLaVHnGnxdlbIrj5XswIKu2OZUSlbf+rzGdJPr0PvbzdwiV9jJd+gDV93TEHOqFpwoLT4ThDU3AWACHTyhLIGMYOGn9UuET2d25WA3NV9Bi2ChZAuOiO5GbX5zECk1lqykFKxr4Hrgmb2/6S8e3r4aw4Gjq+hG5DQPCYAUwE0uF2PLcGzOqnsvHavC/3V3rm2yRInj+gjjYOOoJEZMqpEsE8ZvcZSf6vvYCK8zIBR+5L6oYGVW3ICdpiFWm1gK/9iwxgt/saoI/rmWu38P+3AqIsJI2PqwuFbfzFnrHhfwp8NL9xLAT3d3iEYyg3lTWPzx6vD48HkxT5kUPm8xPCKiPkOdYysVOEsz6OjiIB5JksbCemygwY= 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)(376002)(396003)(39860400002)(136003)(46966006)(36840700001)(426003)(8676002)(70586007)(356005)(44832011)(30864003)(8936002)(316002)(36860700001)(2906002)(7636003)(83380400001)(42186006)(36906005)(70206006)(54906003)(2616005)(1076003)(82740400003)(82310400003)(107886003)(6666004)(26005)(6266002)(47076005)(478600001)(6916009)(336012)(4326008)(186003)(36756003)(5660300002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:32:47.2953 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3980548e-2f99-4831-af82-08d8ee864207 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: SN1NAM02FT057.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR02MB2682 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org XRT drivers use device tree as metadata format to discover HW subsystems behind PCIe BAR. Thus libfdt functions are called for the driver to parse device tree blob. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/include/metadata.h | 233 ++++++++++++ drivers/fpga/xrt/metadata/metadata.c | 545 +++++++++++++++++++++++++++ 2 files changed, 778 insertions(+) create mode 100644 drivers/fpga/xrt/include/metadata.h create mode 100644 drivers/fpga/xrt/metadata/metadata.c diff --git a/drivers/fpga/xrt/include/metadata.h b/drivers/fpga/xrt/include/metadata.h new file mode 100644 index 000000000000..479e47960c61 --- /dev/null +++ b/drivers/fpga/xrt/include/metadata.h @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_METADATA_H +#define _XRT_METADATA_H + +#include +#include +#include + +#define XRT_MD_INVALID_LENGTH (~0UL) + +/* metadata properties */ +#define XRT_MD_PROP_BAR_IDX "pcie_bar_mapping" +#define XRT_MD_PROP_COMPATIBLE "compatible" +#define XRT_MD_PROP_HWICAP "axi_hwicap" +#define XRT_MD_PROP_INTERFACE_UUID "interface_uuid" +#define XRT_MD_PROP_INTERRUPTS "interrupts" +#define XRT_MD_PROP_IO_OFFSET "reg" +#define XRT_MD_PROP_LOGIC_UUID "logic_uuid" +#define XRT_MD_PROP_PDI_CONFIG "pdi_config_mem" +#define XRT_MD_PROP_PF_NUM "pcie_physical_function" +#define XRT_MD_PROP_VERSION_MAJOR "firmware_version_major" + +/* non IP nodes */ +#define XRT_MD_NODE_ENDPOINTS "addressable_endpoints" +#define XRT_MD_NODE_FIRMWARE "firmware" +#define XRT_MD_NODE_INTERFACES "interfaces" +#define XRT_MD_NODE_PARTITION_INFO "partition_info" + +/* + * IP nodes + * AF: AXI Firewall + * CMC: Card Management Controller + * ERT: Embedded Runtime + * PLP: Provider Reconfigurable Partition + * ULP: User Reconfigurable Partition + */ +#define XRT_MD_NODE_ADDR_TRANSLATOR "ep_remap_data_c2h_00" +#define XRT_MD_NODE_AF_BLP_CTRL_MGMT "ep_firewall_blp_ctrl_mgmt_00" +#define XRT_MD_NODE_AF_BLP_CTRL_USER "ep_firewall_blp_ctrl_user_00" +#define XRT_MD_NODE_AF_CTRL_DEBUG "ep_firewall_ctrl_debug_00" +#define XRT_MD_NODE_AF_CTRL_MGMT "ep_firewall_ctrl_mgmt_00" +#define XRT_MD_NODE_AF_CTRL_USER "ep_firewall_ctrl_user_00" +#define XRT_MD_NODE_AF_DATA_C2H "ep_firewall_data_c2h_00" +#define XRT_MD_NODE_AF_DATA_H2C "ep_firewall_data_h2c_00" +#define XRT_MD_NODE_AF_DATA_M2M "ep_firewall_data_m2m_00" +#define XRT_MD_NODE_AF_DATA_P2P "ep_firewall_data_p2p_00" +#define XRT_MD_NODE_CLKFREQ_HBM "ep_freq_cnt_aclk_hbm_00" +#define XRT_MD_NODE_CLKFREQ_K1 "ep_freq_cnt_aclk_kernel_00" +#define XRT_MD_NODE_CLKFREQ_K2 "ep_freq_cnt_aclk_kernel_01" +#define XRT_MD_NODE_CLK_KERNEL1 "ep_aclk_kernel_00" +#define XRT_MD_NODE_CLK_KERNEL2 "ep_aclk_kernel_01" +#define XRT_MD_NODE_CLK_KERNEL3 "ep_aclk_hbm_00" +#define XRT_MD_NODE_CLK_SHUTDOWN "ep_aclk_shutdown_00" +#define XRT_MD_NODE_CMC_FW_MEM "ep_cmc_firmware_mem_00" +#define XRT_MD_NODE_CMC_MUTEX "ep_cmc_mutex_00" +#define XRT_MD_NODE_CMC_REG "ep_cmc_regmap_00" +#define XRT_MD_NODE_CMC_RESET "ep_cmc_reset_00" +#define XRT_MD_NODE_DDR_CALIB "ep_ddr_mem_calib_00" +#define XRT_MD_NODE_DDR4_RESET_GATE "ep_ddr_mem_srsr_gate_00" +#define XRT_MD_NODE_ERT_BASE "ep_ert_base_address_00" +#define XRT_MD_NODE_ERT_CQ_MGMT "ep_ert_command_queue_mgmt_00" +#define XRT_MD_NODE_ERT_CQ_USER "ep_ert_command_queue_user_00" +#define XRT_MD_NODE_ERT_FW_MEM "ep_ert_firmware_mem_00" +#define XRT_MD_NODE_ERT_RESET "ep_ert_reset_00" +#define XRT_MD_NODE_ERT_SCHED "ep_ert_sched_00" +#define XRT_MD_NODE_FLASH "ep_card_flash_program_00" +#define XRT_MD_NODE_FPGA_CONFIG "ep_fpga_configuration_00" +#define XRT_MD_NODE_GAPPING "ep_gapping_demand_00" +#define XRT_MD_NODE_GATE_PLP "ep_pr_isolate_plp_00" +#define XRT_MD_NODE_GATE_ULP "ep_pr_isolate_ulp_00" +#define XRT_MD_NODE_KDMA_CTRL "ep_kdma_ctrl_00" +#define XRT_MD_NODE_MAILBOX_MGMT "ep_mailbox_mgmt_00" +#define XRT_MD_NODE_MAILBOX_USER "ep_mailbox_user_00" +#define XRT_MD_NODE_MAILBOX_XRT "ep_mailbox_user_to_ert_00" +#define XRT_MD_NODE_MSIX "ep_msix_00" +#define XRT_MD_NODE_P2P "ep_p2p_00" +#define XRT_MD_NODE_PCIE_MON "ep_pcie_link_mon_00" +#define XRT_MD_NODE_PMC_INTR "ep_pmc_intr_00" +#define XRT_MD_NODE_PMC_MUX "ep_pmc_mux_00" +#define XRT_MD_NODE_QDMA "ep_qdma_00" +#define XRT_MD_NODE_QDMA4 "ep_qdma4_00" +#define XRT_MD_NODE_REMAP_P2P "ep_remap_p2p_00" +#define XRT_MD_NODE_STM "ep_stream_traffic_manager_00" +#define XRT_MD_NODE_STM4 "ep_stream_traffic_manager4_00" +#define XRT_MD_NODE_SYSMON "ep_cmp_sysmon_00" +#define XRT_MD_NODE_XDMA "ep_xdma_00" +#define XRT_MD_NODE_XVC_PUB "ep_debug_bscan_user_00" +#define XRT_MD_NODE_XVC_PRI "ep_debug_bscan_mgmt_00" +#define XRT_MD_NODE_UCS_CONTROL_STATUS "ep_ucs_control_status_00" + +/* endpoint regmaps */ +#define XRT_MD_REGMAP_DDR_SRSR "drv_ddr_srsr" +#define XRT_MD_REGMAP_CLKFREQ "freq_cnt" + +/* driver defined endpoints */ +#define XRT_MD_NODE_BLP_ROM "drv_ep_blp_rom_00" +#define XRT_MD_NODE_DDR_SRSR "drv_ep_ddr_srsr" +#define XRT_MD_NODE_FLASH_VSEC "drv_ep_card_flash_program_00" +#define XRT_MD_NODE_GOLDEN_VER "drv_ep_golden_ver_00" +#define XRT_MD_NODE_MAILBOX_VSEC "drv_ep_mailbox_vsec_00" +#define XRT_MD_NODE_MGMT_MAIN "drv_ep_mgmt_main_00" +#define XRT_MD_NODE_PLAT_INFO "drv_ep_platform_info_mgmt_00" +#define XRT_MD_NODE_PARTITION_INFO_BLP "partition_info_0" +#define XRT_MD_NODE_PARTITION_INFO_PLP "partition_info_1" +#define XRT_MD_NODE_TEST "drv_ep_test_00" +#define XRT_MD_NODE_VSEC "drv_ep_vsec_00" +#define XRT_MD_NODE_VSEC_GOLDEN "drv_ep_vsec_golden_00" + +/* driver defined properties */ +#define XRT_MD_PROP_OFFSET "drv_offset" +#define XRT_MD_PROP_CLK_FREQ "drv_clock_frequency" +#define XRT_MD_PROP_CLK_CNT "drv_clock_frequency_counter" +#define XRT_MD_PROP_VBNV "vbnv" +#define XRT_MD_PROP_VROM "vrom" +#define XRT_MD_PROP_PARTITION_LEVEL "partition_level" + +struct xrt_md_endpoint { + const char *ep_name; + u32 bar; + u64 bar_off; + ulong size; + char *regmap; + char *regmap_ver; +}; + +/* Note: res_id is defined by leaf driver and must start with 0. */ +struct xrt_iores_map { + char *res_name; + int res_id; +}; + +static inline int xrt_md_res_name2id(const struct xrt_iores_map *res_map, + int entry_num, const char *res_name) +{ + int i; + + for (i = 0; i < entry_num; i++) { + if (!strncmp(res_name, res_map->res_name, strlen(res_map->res_name) + 1)) + return res_map->res_id; + res_map++; + } + return -1; +} + +static inline const char * +xrt_md_res_id2name(const struct xrt_iores_map *res_map, int entry_num, int id) +{ + int i; + + for (i = 0; i < entry_num; i++) { + if (res_map->res_id == id) + return res_map->res_name; + res_map++; + } + return NULL; +} + +unsigned long xrt_md_size(struct device *dev, const char *blob); +int xrt_md_create(struct device *dev, char **blob); +char *xrt_md_dup(struct device *dev, const char *blob); +int xrt_md_add_endpoint(struct device *dev, char *blob, + struct xrt_md_endpoint *ep); +int xrt_md_del_endpoint(struct device *dev, char *blob, const char *ep_name, + const char *regmap_name); +int xrt_md_get_prop(struct device *dev, const char *blob, const char *ep_name, + const char *regmap_name, const char *prop, + const void **val, int *size); +int xrt_md_set_prop(struct device *dev, char *blob, const char *ep_name, + const char *regmap_name, const char *prop, + const void *val, int size); +int xrt_md_copy_endpoint(struct device *dev, char *blob, const char *src_blob, + const char *ep_name, const char *regmap_name, + const char *new_ep_name); +int xrt_md_get_next_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + char **next_ep, char **next_regmap); +int xrt_md_get_compatible_endpoint(struct device *dev, const char *blob, + const char *regmap_name, const char **ep_name); +int xrt_md_find_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + const char **epname); +int xrt_md_pack(struct device *dev, char *blob); +int xrt_md_get_interface_uuids(struct device *dev, const char *blob, + u32 num_uuids, uuid_t *intf_uuids); + +/* + * The firmware provides a 128 bit hash string as a unique id to the + * partition/interface. + * Existing hw does not yet use the cononical form, so it is necessary to + * use a translation function. + */ +static inline void xrt_md_trans_uuid2str(const uuid_t *uuid, char *uuidstr) +{ + int i, p; + u8 tmp[UUID_SIZE]; + + BUILD_BUG_ON(UUID_SIZE != 16); + export_uuid(tmp, uuid); + for (p = 0, i = UUID_SIZE - 1; i >= 0; p++, i--) + snprintf(&uuidstr[p * 2], 3, "%02x", tmp[i]); +} + +static inline int xrt_md_trans_str2uuid(struct device *dev, const char *uuidstr, uuid_t *p_uuid) +{ + u8 p[UUID_SIZE]; + const char *str; + char tmp[3] = { 0 }; + int i, ret; + + BUILD_BUG_ON(UUID_SIZE != 16); + str = uuidstr + strlen(uuidstr) - 2; + + for (i = 0; i < sizeof(*p_uuid) && str >= uuidstr; i++) { + tmp[0] = *str; + tmp[1] = *(str + 1); + ret = kstrtou8(tmp, 16, &p[i]); + if (ret) + return -EINVAL; + str -= 2; + } + import_uuid(p_uuid, p); + + return 0; +} + +#endif diff --git a/drivers/fpga/xrt/metadata/metadata.c b/drivers/fpga/xrt/metadata/metadata.c new file mode 100644 index 000000000000..3b2be50fcb02 --- /dev/null +++ b/drivers/fpga/xrt/metadata/metadata.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Metadata parse APIs + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#include +#include "libfdt.h" +#include "metadata.h" + +#define MAX_BLOB_SIZE (4096 * 25) +#define MAX_DEPTH 5 + +static int xrt_md_setprop(struct device *dev, char *blob, int offset, + const char *prop, const void *val, int size) +{ + int ret; + + ret = fdt_setprop(blob, offset, prop, val, size); + if (ret) + dev_err(dev, "failed to set prop %d", ret); + + return ret; +} + +static int xrt_md_add_node(struct device *dev, char *blob, int parent_offset, + const char *ep_name) +{ + int ret; + + ret = fdt_add_subnode(blob, parent_offset, ep_name); + if (ret < 0 && ret != -FDT_ERR_EXISTS) + dev_err(dev, "failed to add node %s. %d", ep_name, ret); + + return ret; +} + +static int xrt_md_get_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + int *ep_offset) +{ + const char *name; + int offset; + + for (offset = fdt_next_node(blob, -1, NULL); + offset >= 0; + offset = fdt_next_node(blob, offset, NULL)) { + name = fdt_get_name(blob, offset, NULL); + if (!name || strncmp(name, ep_name, strlen(ep_name) + 1)) + continue; + if (!regmap_name || + !fdt_node_check_compatible(blob, offset, regmap_name)) + break; + } + if (offset < 0) + return -ENODEV; + + *ep_offset = offset; + + return 0; +} + +static inline int xrt_md_get_node(struct device *dev, const char *blob, + const char *name, const char *regmap_name, + int *offset) +{ + int ret = 0; + + if (name) { + ret = xrt_md_get_endpoint(dev, blob, name, regmap_name, + offset); + if (ret) { + dev_err(dev, "cannot get node %s, regmap %s, ret = %d", + name, regmap_name, ret); + return -EINVAL; + } + } else { + ret = fdt_next_node(blob, -1, NULL); + if (ret < 0) { + dev_err(dev, "internal error, ret = %d", ret); + return -EINVAL; + } + *offset = ret; + } + + return 0; +} + +static int xrt_md_overlay(struct device *dev, char *blob, int target, + const char *overlay_blob, int overlay_offset, + int depth) +{ + int property, subnode; + int ret; + + if (!blob || !overlay_blob) { + dev_err(dev, "blob is NULL"); + return -EINVAL; + } + + if (depth > MAX_DEPTH) { + dev_err(dev, "meta data depth beyond %d", MAX_DEPTH); + return -EINVAL; + } + + if (target < 0) { + target = fdt_next_node(blob, -1, NULL); + if (target < 0) { + dev_err(dev, "invalid target"); + return -EINVAL; + } + } + if (overlay_offset < 0) { + overlay_offset = fdt_next_node(overlay_blob, -1, NULL); + if (overlay_offset < 0) { + dev_err(dev, "invalid overlay"); + return -EINVAL; + } + } + + fdt_for_each_property_offset(property, overlay_blob, overlay_offset) { + const char *name; + const void *prop; + int prop_len; + + prop = fdt_getprop_by_offset(overlay_blob, property, &name, + &prop_len); + if (!prop || prop_len >= MAX_BLOB_SIZE || prop_len < 0) { + dev_err(dev, "internal error"); + return -EINVAL; + } + + ret = xrt_md_setprop(dev, blob, target, name, prop, + prop_len); + if (ret) { + dev_err(dev, "setprop failed, ret = %d", ret); + return ret; + } + } + + fdt_for_each_subnode(subnode, overlay_blob, overlay_offset) { + const char *name = fdt_get_name(overlay_blob, subnode, NULL); + int nnode; + + nnode = xrt_md_add_node(dev, blob, target, name); + if (nnode == -FDT_ERR_EXISTS) + nnode = fdt_subnode_offset(blob, target, name); + if (nnode < 0) { + dev_err(dev, "add node failed, ret = %d", nnode); + return nnode; + } + + ret = xrt_md_overlay(dev, blob, nnode, overlay_blob, subnode, depth + 1); + if (ret) + return ret; + } + + return 0; +} + +unsigned long xrt_md_size(struct device *dev, const char *blob) +{ + unsigned long len = (long)fdt_totalsize(blob); + + if (len > MAX_BLOB_SIZE) + return XRT_MD_INVALID_LENGTH; + + return len; +} +EXPORT_SYMBOL_GPL(xrt_md_size); + +int xrt_md_create(struct device *dev, char **blob) +{ + int ret = 0; + + if (!blob) { + dev_err(dev, "blob is NULL"); + return -EINVAL; + } + + *blob = vzalloc(MAX_BLOB_SIZE); + if (!*blob) + return -ENOMEM; + + ret = fdt_create_empty_tree(*blob, MAX_BLOB_SIZE); + if (ret) { + dev_err(dev, "format blob failed, ret = %d", ret); + goto failed; + } + + ret = fdt_next_node(*blob, -1, NULL); + if (ret < 0) { + dev_err(dev, "No Node, ret = %d", ret); + goto failed; + } + + ret = fdt_add_subnode(*blob, 0, XRT_MD_NODE_ENDPOINTS); + if (ret < 0) { + dev_err(dev, "add node failed, ret = %d", ret); + goto failed; + } + + return 0; + +failed: + vfree(*blob); + *blob = NULL; + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_create); + +char *xrt_md_dup(struct device *dev, const char *blob) +{ + char *dup_blob; + int ret; + + ret = xrt_md_create(dev, &dup_blob); + if (ret) + return NULL; + ret = xrt_md_overlay(dev, dup_blob, -1, blob, -1, 0); + if (ret) { + vfree(dup_blob); + return NULL; + } + + return dup_blob; +} +EXPORT_SYMBOL_GPL(xrt_md_dup); + +int xrt_md_del_endpoint(struct device *dev, char *blob, const char *ep_name, + const char *regmap_name) +{ + int ep_offset; + int ret; + + ret = xrt_md_get_endpoint(dev, blob, ep_name, regmap_name, &ep_offset); + if (ret) { + dev_err(dev, "can not find ep %s", ep_name); + return -EINVAL; + } + + ret = fdt_del_node(blob, ep_offset); + if (ret) + dev_err(dev, "delete node %s failed, ret %d", ep_name, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_del_endpoint); + +static int __xrt_md_add_endpoint(struct device *dev, char *blob, + struct xrt_md_endpoint *ep, int *offset, + const char *parent) +{ + int parent_offset = 0; + u32 val, count = 0; + int ep_offset = 0; + u64 io_range[2]; + char comp[128]; + int ret = 0; + + if (!ep->ep_name) { + dev_err(dev, "empty name"); + return -EINVAL; + } + + if (parent) { + ret = xrt_md_get_endpoint(dev, blob, parent, NULL, &parent_offset); + if (ret) { + dev_err(dev, "invalid blob, ret = %d", ret); + return -EINVAL; + } + } + + ep_offset = xrt_md_add_node(dev, blob, parent_offset, ep->ep_name); + if (ep_offset < 0) { + dev_err(dev, "add endpoint failed, ret = %d", ret); + return -EINVAL; + } + if (offset) + *offset = ep_offset; + + if (ep->size != 0) { + val = cpu_to_be32(ep->bar); + ret = xrt_md_setprop(dev, blob, ep_offset, XRT_MD_PROP_BAR_IDX, + &val, sizeof(u32)); + if (ret) { + dev_err(dev, "set %s failed, ret %d", + XRT_MD_PROP_BAR_IDX, ret); + goto failed; + } + io_range[0] = cpu_to_be64((u64)ep->bar_off); + io_range[1] = cpu_to_be64((u64)ep->size); + ret = xrt_md_setprop(dev, blob, ep_offset, XRT_MD_PROP_IO_OFFSET, + io_range, sizeof(io_range)); + if (ret) { + dev_err(dev, "set %s failed, ret %d", + XRT_MD_PROP_IO_OFFSET, ret); + goto failed; + } + } + + if (ep->regmap) { + if (ep->regmap_ver) { + count = snprintf(comp, sizeof(comp) - 1, + "%s-%s", ep->regmap, ep->regmap_ver); + count++; + } + if (count > sizeof(comp)) { + ret = -EINVAL; + goto failed; + } + + count += snprintf(comp + count, sizeof(comp) - count - 1, + "%s", ep->regmap); + count++; + if (count > sizeof(comp)) { + ret = -EINVAL; + goto failed; + } + + ret = xrt_md_setprop(dev, blob, ep_offset, XRT_MD_PROP_COMPATIBLE, + comp, count); + if (ret) { + dev_err(dev, "set %s failed, ret %d", + XRT_MD_PROP_COMPATIBLE, ret); + goto failed; + } + } + +failed: + if (ret) + xrt_md_del_endpoint(dev, blob, ep->ep_name, NULL); + + return ret; +} + +int xrt_md_add_endpoint(struct device *dev, char *blob, + struct xrt_md_endpoint *ep) +{ + return __xrt_md_add_endpoint(dev, blob, ep, NULL, XRT_MD_NODE_ENDPOINTS); +} +EXPORT_SYMBOL_GPL(xrt_md_add_endpoint); + +int xrt_md_find_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + const char **epname) +{ + int offset; + int ret; + + ret = xrt_md_get_endpoint(dev, blob, ep_name, regmap_name, + &offset); + if (!ret && epname) + *epname = fdt_get_name(blob, offset, NULL); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_find_endpoint); + +int xrt_md_get_prop(struct device *dev, const char *blob, const char *ep_name, + const char *regmap_name, const char *prop, + const void **val, int *size) +{ + int offset; + int ret; + + if (!val) { + dev_err(dev, "val is null"); + return -EINVAL; + } + + *val = NULL; + ret = xrt_md_get_node(dev, blob, ep_name, regmap_name, &offset); + if (ret) + return ret; + + *val = fdt_getprop(blob, offset, prop, size); + if (!*val) { + dev_dbg(dev, "get ep %s, prop %s failed", ep_name, prop); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_md_get_prop); + +int xrt_md_set_prop(struct device *dev, char *blob, + const char *ep_name, const char *regmap_name, + const char *prop, const void *val, int size) +{ + int offset; + int ret; + + ret = xrt_md_get_node(dev, blob, ep_name, regmap_name, &offset); + if (ret) + return ret; + + ret = xrt_md_setprop(dev, blob, offset, prop, val, size); + if (ret) + dev_err(dev, "set prop %s failed, ret = %d", prop, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_set_prop); + +int xrt_md_copy_endpoint(struct device *dev, char *blob, const char *src_blob, + const char *ep_name, const char *regmap_name, + const char *new_ep_name) +{ + const char *newepnm = new_ep_name ? new_ep_name : ep_name; + struct xrt_md_endpoint ep = {0}; + int offset, target; + const char *parent; + int ret; + + ret = xrt_md_get_endpoint(dev, src_blob, ep_name, regmap_name, + &offset); + if (ret) + return -EINVAL; + + ret = xrt_md_get_endpoint(dev, blob, newepnm, regmap_name, &target); + if (ret) { + ep.ep_name = newepnm; + parent = fdt_parent_offset(src_blob, offset) == 0 ? NULL : XRT_MD_NODE_ENDPOINTS; + ret = __xrt_md_add_endpoint(dev, blob, &ep, &target, parent); + if (ret) + return -EINVAL; + } + + ret = xrt_md_overlay(dev, blob, target, src_blob, offset, 0); + if (ret) + dev_err(dev, "overlay failed, ret = %d", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_copy_endpoint); + +int xrt_md_get_next_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + char **next_ep, char **next_regmap) +{ + int offset, ret; + + *next_ep = NULL; + *next_regmap = NULL; + if (!ep_name) { + ret = xrt_md_get_endpoint(dev, blob, XRT_MD_NODE_ENDPOINTS, NULL, + &offset); + } else { + ret = xrt_md_get_endpoint(dev, blob, ep_name, regmap_name, + &offset); + } + + if (ret) + return -EINVAL; + + offset = ep_name ? fdt_next_subnode(blob, offset) : + fdt_first_subnode(blob, offset); + if (offset < 0) + return -EINVAL; + + *next_ep = (char *)fdt_get_name(blob, offset, NULL); + *next_regmap = (char *)fdt_stringlist_get(blob, offset, XRT_MD_PROP_COMPATIBLE, + 0, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_md_get_next_endpoint); + +int xrt_md_get_compatible_endpoint(struct device *dev, const char *blob, + const char *regmap_name, const char **ep_name) +{ + int ep_offset; + + ep_offset = fdt_node_offset_by_compatible(blob, -1, regmap_name); + if (ep_offset < 0) { + *ep_name = NULL; + return -ENOENT; + } + + *ep_name = fdt_get_name(blob, ep_offset, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_md_get_compatible_endpoint); + +int xrt_md_pack(struct device *dev, char *blob) +{ + int ret; + + ret = fdt_pack(blob); + if (ret) + dev_err(dev, "pack failed %d", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_pack); + +int xrt_md_get_interface_uuids(struct device *dev, const char *blob, + u32 num_uuids, uuid_t *interface_uuids) +{ + int offset, count = 0; + const char *uuid_str; + int ret; + + ret = xrt_md_get_endpoint(dev, blob, XRT_MD_NODE_INTERFACES, NULL, &offset); + if (ret) + return -ENOENT; + + for (offset = fdt_first_subnode(blob, offset); + offset >= 0; + offset = fdt_next_subnode(blob, offset), count++) { + uuid_str = fdt_getprop(blob, offset, XRT_MD_PROP_INTERFACE_UUID, + NULL); + if (!uuid_str) { + dev_err(dev, "empty interface uuid node"); + return -EINVAL; + } + + if (!num_uuids) + continue; + + if (count == num_uuids) { + dev_err(dev, "too many interface uuid in blob"); + return -EINVAL; + } + + if (interface_uuids && count < num_uuids) { + ret = xrt_md_trans_str2uuid(dev, uuid_str, + &interface_uuids[count]); + if (ret) + return -EINVAL; + } + } + if (!count) + count = -ENOENT; + + return count; +} +EXPORT_SYMBOL_GPL(xrt_md_get_interface_uuids); From patchwork Wed Mar 24 05:29: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: 408378 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, URIBL_BLOCKED, 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 328F3C433C1 for ; Wed, 24 Mar 2021 05:34:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DF47F619E9 for ; Wed, 24 Mar 2021 05:34:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235285AbhCXFdy (ORCPT ); Wed, 24 Mar 2021 01:33:54 -0400 Received: from mail-eopbgr690071.outbound.protection.outlook.com ([40.107.69.71]:36654 "EHLO NAM04-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235278AbhCXFd3 (ORCPT ); Wed, 24 Mar 2021 01:33:29 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JrhbmkKuAOCgtQ72QixyUSxUnNrvon0+e3RznESVgS3RugJKofTZXm7qR1YUobBhEjDdWyOdDhCE6FtxtHL+VWfiH2DZIfHbq7txIfx/g97B+8vkZ23eQ19ywL14SnXPN9d+SKoGFCtZ2Icmy6pILHn6HLIgbELw+MnIxwLs19hpnZKhjUITQhtpO1uoz/9mj8PuzJIyV3pi87Pew8t5GDj3ZJCpG8psmRzF9OSNSJGfHNTttlHlea7aJqODsZos3fG5PW7oN569fvI88gJhtHreDqwKLXsxNfK6sYfqPaO2ilrI2DKloZbfsyaQoQbFY/0MO+DAQPK2fmbhT3HkxQ== 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=TcgMHpgYqNrYHHDKDvNYH/JZKzTNQl6apRp93jgHv5k=; b=fWUHdKfiXWbqS3Pyj9lxNhECjZ9d53NuB4EtENIOKQyU2YR2owNIylzdb8JOIfjEXbtllySfRBLi043vmlnNBHeIH2SxJukT20Ajlz0F1V072kEXUZQmNw/NFx97yomPKRTWdn3E6wErxEsNTAgA1RNT/s4/BndUaLpn1tIiTzfGfUk3Vy1LEosCQbmz9bKULIe01Zez63sPruQ9p7PsUzvm46FVTX8ihMTzXe26IPzcQzq3mweSjvlzNwWdXwv8/Kb2UXzAOavl3VLr9nIq3dGGcJ1DvUevAzZWyYGO1rdawAWdwfONYgAC3XREvRe7uTf5gxA0t8MWDh8zqb0Kfg== 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=TcgMHpgYqNrYHHDKDvNYH/JZKzTNQl6apRp93jgHv5k=; b=EMkYtQTe1ufbrMiYmNtf2T9sd/EiBp9jpIcEhMeT6QgeBdx8ARdKs0s9GhcojcviF1hykBlgyvB0EZZBs5exD24vChZnKlGVZmi/4A1RKMplFQo6MIWFUhJhUJaLmy1U6r8Rv0++GtHObmvPJo4kS85oJiX3aN/PGiZR1cLyNCI= Received: from SN6PR16CA0037.namprd16.prod.outlook.com (2603:10b6:805:ca::14) by CH2PR02MB6214.namprd02.prod.outlook.com (2603:10b6:610:9::29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:33:26 +0000 Received: from SN1NAM02FT017.eop-nam02.prod.protection.outlook.com (2603:10b6:805:ca:cafe::81) by SN6PR16CA0037.outlook.office365.com (2603:10b6:805:ca::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:33:26 +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 SN1NAM02FT017.mail.protection.outlook.com (10.152.72.115) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3955.24 via Frontend Transport; Wed, 24 Mar 2021 05:33:26 +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.2106.2; Tue, 23 Mar 2021 22:33:10 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:33:10 -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=51028 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOw8k-0004SU-16; Tue, 23 Mar 2021 22:33:10 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id D9A6A60011F; Tue, 23 Mar 2021 22:29:55 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 04/20] fpga: xrt: xrt-lib platform driver manager Date: Tue, 23 Mar 2021 22:29:31 -0700 Message-ID: <20210324052947.27889-5-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: bf626620-ac9e-405f-f215-08d8ee865959 X-MS-TrafficTypeDiagnostic: CH2PR02MB6214: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:125; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: MNeIAPBBJ+qrXa9X1omwA+Vqu8+8YzfrO6uXDPK/nV3HV/MxwIOzvm4QOq5LO6lJkOpXl4mbUorSGog5DeEQYAKp5dwfrq7JXEoPzMs9NOvzf5H5fsoSCQYKKYjMuVZT5ZV155wsNgg7G2ZnaJgjl/dPrxMopnpIStgCS++a1CmsI2GTXyyfG2AVnzdOluWMmdaH8SjN2Std6fXZssouwqtaCj4DOmXnglaAqL4FWDuJMk3Pa8/f+n5mDj/F0ITY7c78jDuSx6W24X0iVJExCLybOpM34o0qsdolMjs2ceKBUVPN9NH1ghqBXZRhrrBq4pZ5fb4Rq6rFOEUvoYwrrtis904tLoeW8zDCXK4khfyR5gZNBHUXgkbCaeabhRQPWjcdrf+svNaGa3k3jAJIPxpOY7MU9RxYd/Hoyl01jCDq0SBXEWRFj80/ADeWqH+7mP3wsN6dVbcAGYvsDM+Jt8g/RysACpNl//DRONonYPILShPFQYEn8PBHX/ag2BssEOhhvlsh6GgtHGbNur3WGsWSpL0xTe07GXrKmtlJsL7CG1hzXNvPof9KG64DBdmbMUc9gIvZwpto14jUa7O/M0qM4nid+t0Cq5ciGJcH4R/EJHaNrbxcXd7Yvmz3M6PgJKwkhuj1P03vCBWTgFOQmnW+fguI3oUE10KVWFh+kik= 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)(376002)(396003)(39850400004)(136003)(36840700001)(46966006)(6916009)(42186006)(426003)(83380400001)(336012)(7636003)(316002)(107886003)(8676002)(5660300002)(30864003)(2616005)(6266002)(36906005)(1076003)(54906003)(70586007)(82740400003)(36860700001)(70206006)(186003)(2906002)(6666004)(356005)(82310400003)(26005)(47076005)(36756003)(44832011)(478600001)(8936002)(4326008); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:33:26.4216 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: bf626620-ac9e-405f-f215-08d8ee865959 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: SN1NAM02FT017.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR02MB6214 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org xrt-lib kernel module infrastructure code to register and manage all leaf driver modules. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/include/subdev_id.h | 38 ++++ drivers/fpga/xrt/include/xleaf.h | 264 +++++++++++++++++++++++++ drivers/fpga/xrt/lib/lib-drv.c | 277 +++++++++++++++++++++++++++ drivers/fpga/xrt/lib/lib-drv.h | 17 ++ 4 files changed, 596 insertions(+) create mode 100644 drivers/fpga/xrt/include/subdev_id.h create mode 100644 drivers/fpga/xrt/include/xleaf.h create mode 100644 drivers/fpga/xrt/lib/lib-drv.c create mode 100644 drivers/fpga/xrt/lib/lib-drv.h diff --git a/drivers/fpga/xrt/include/subdev_id.h b/drivers/fpga/xrt/include/subdev_id.h new file mode 100644 index 000000000000..42fbd6f5e80a --- /dev/null +++ b/drivers/fpga/xrt/include/subdev_id.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_SUBDEV_ID_H_ +#define _XRT_SUBDEV_ID_H_ + +/* + * Every subdev driver has an ID for others to refer to it. There can be multiple number of + * instances of a subdev driver. A tuple is a unique identification + * of a specific instance of a subdev driver. + */ +enum xrt_subdev_id { + XRT_SUBDEV_GRP = 0, + XRT_SUBDEV_VSEC = 1, + XRT_SUBDEV_VSEC_GOLDEN = 2, + XRT_SUBDEV_DEVCTL = 3, + XRT_SUBDEV_AXIGATE = 4, + XRT_SUBDEV_ICAP = 5, + XRT_SUBDEV_TEST = 6, + XRT_SUBDEV_MGMT_MAIN = 7, + XRT_SUBDEV_QSPI = 8, + XRT_SUBDEV_MAILBOX = 9, + XRT_SUBDEV_CMC = 10, + XRT_SUBDEV_CALIB = 11, + XRT_SUBDEV_CLKFREQ = 12, + XRT_SUBDEV_CLOCK = 13, + XRT_SUBDEV_SRSR = 14, + XRT_SUBDEV_UCS = 15, + XRT_SUBDEV_NUM = 16, /* Total number of subdevs. */ + XRT_ROOT = -1, /* Special ID for root driver. */ +}; + +#endif /* _XRT_SUBDEV_ID_H_ */ diff --git a/drivers/fpga/xrt/include/xleaf.h b/drivers/fpga/xrt/include/xleaf.h new file mode 100644 index 000000000000..acb500df04b0 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf.h @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + * Sonal Santan + */ + +#ifndef _XRT_XLEAF_H_ +#define _XRT_XLEAF_H_ + +#include +#include +#include +#include "subdev_id.h" +#include "xroot.h" +#include "events.h" + +/* All subdev drivers should use below common routines to print out msg. */ +#define DEV(pdev) (&(pdev)->dev) +#define DEV_PDATA(pdev) \ + ((struct xrt_subdev_platdata *)dev_get_platdata(DEV(pdev))) +#define DEV_DRVDATA(pdev) \ + ((struct xrt_subdev_drvdata *) \ + platform_get_device_id(pdev)->driver_data) +#define FMT_PRT(prt_fn, pdev, fmt, args...) \ + ({typeof(pdev) (_pdev) = (pdev); \ + prt_fn(DEV(_pdev), "%s %s: " fmt, \ + DEV_PDATA(_pdev)->xsp_root_name, __func__, ##args); }) +#define xrt_err(pdev, fmt, args...) FMT_PRT(dev_err, pdev, fmt, ##args) +#define xrt_warn(pdev, fmt, args...) FMT_PRT(dev_warn, pdev, fmt, ##args) +#define xrt_info(pdev, fmt, args...) FMT_PRT(dev_info, pdev, fmt, ##args) +#define xrt_dbg(pdev, fmt, args...) FMT_PRT(dev_dbg, pdev, fmt, ##args) + +enum { + /* Starting cmd for common leaf cmd implemented by all leaves. */ + XRT_XLEAF_COMMON_BASE = 0, + /* Starting cmd for leaves' specific leaf cmds. */ + XRT_XLEAF_CUSTOM_BASE = 64, +}; + +enum xrt_xleaf_common_leaf_cmd { + XRT_XLEAF_EVENT = XRT_XLEAF_COMMON_BASE, +}; + +/* + * If populated by subdev driver, infra will handle the mechanics of + * char device (un)registration. + */ +enum xrt_subdev_file_mode { + /* Infra create cdev, default file name */ + XRT_SUBDEV_FILE_DEFAULT = 0, + /* Infra create cdev, need to encode inst num in file name */ + XRT_SUBDEV_FILE_MULTI_INST, + /* No auto creation of cdev by infra, leaf handles it by itself */ + XRT_SUBDEV_FILE_NO_AUTO, +}; + +struct xrt_subdev_file_ops { + const struct file_operations xsf_ops; + dev_t xsf_dev_t; + const char *xsf_dev_name; + enum xrt_subdev_file_mode xsf_mode; +}; + +/* + * Subdev driver callbacks populated by subdev driver. + */ +struct xrt_subdev_drv_ops { + /* + * Per driver instance callback. The pdev points to the instance. + * If defined, these are called by other leaf drivers. + * Note that root driver may call into xsd_leaf_call of a group driver. + */ + int (*xsd_leaf_call)(struct platform_device *pdev, u32 cmd, void *arg); +}; + +/* + * Defined and populated by subdev driver, exported as driver_data in + * struct platform_device_id. + */ +struct xrt_subdev_drvdata { + struct xrt_subdev_file_ops xsd_file_ops; + struct xrt_subdev_drv_ops xsd_dev_ops; +}; + +/* + * Partially initialized by the parent driver, then, passed in as subdev driver's + * platform data when creating subdev driver instance by calling platform + * device register API (platform_device_register_data() or the likes). + * + * Once device register API returns, platform driver framework makes a copy of + * this buffer and maintains its life cycle. The content of the buffer is + * completely owned by subdev driver. + * + * Thus, parent driver should be very careful when it touches this buffer + * again once it's handed over to subdev driver. And the data structure + * should not contain pointers pointing to buffers that is managed by + * other or parent drivers since it could have been freed before platform + * data buffer is freed by platform driver framework. + */ +struct xrt_subdev_platdata { + /* + * Per driver instance callback. The pdev points to the instance. + * Should always be defined for subdev driver to get service from root. + */ + xrt_subdev_root_cb_t xsp_root_cb; + void *xsp_root_cb_arg; + + /* Something to associate w/ root for msg printing. */ + const char *xsp_root_name; + + /* + * Char dev support for this subdev instance. + * Initialized by subdev driver. + */ + struct cdev xsp_cdev; + struct device *xsp_sysdev; + struct mutex xsp_devnode_lock; /* devnode lock */ + struct completion xsp_devnode_comp; + int xsp_devnode_ref; + bool xsp_devnode_online; + bool xsp_devnode_excl; + + /* + * Subdev driver specific init data. The buffer should be embedded + * in this data structure buffer after dtb, so that it can be freed + * together with platform data. + */ + loff_t xsp_priv_off; /* Offset into this platform data buffer. */ + size_t xsp_priv_len; + + /* + * Populated by parent driver to describe the device tree for + * the subdev driver to handle. Should always be last one since it's + * of variable length. + */ + bool xsp_dtb_valid; + char xsp_dtb[0]; +}; + +/* + * this struct define the endpoints belong to the same subdevice + */ +struct xrt_subdev_ep_names { + const char *ep_name; + const char *regmap_name; +}; + +struct xrt_subdev_endpoints { + struct xrt_subdev_ep_names *xse_names; + /* minimum number of endpoints to support the subdevice */ + u32 xse_min_ep; +}; + +struct subdev_match_arg { + enum xrt_subdev_id id; + int instance; +}; + +bool xleaf_has_endpoint(struct platform_device *pdev, const char *endpoint_name); +struct platform_device *xleaf_get_leaf(struct platform_device *pdev, + xrt_subdev_match_t cb, void *arg); + +static inline bool subdev_match(enum xrt_subdev_id id, struct platform_device *pdev, void *arg) +{ + const struct subdev_match_arg *a = (struct subdev_match_arg *)arg; + int instance = a->instance; + + if (id != a->id) + return false; + if (instance != pdev->id && instance != PLATFORM_DEVID_NONE) + return false; + return true; +} + +static inline bool xrt_subdev_match_epname(enum xrt_subdev_id id, + struct platform_device *pdev, void *arg) +{ + return xleaf_has_endpoint(pdev, arg); +} + +static inline struct platform_device * +xleaf_get_leaf_by_id(struct platform_device *pdev, + enum xrt_subdev_id id, int instance) +{ + struct subdev_match_arg arg = { id, instance }; + + return xleaf_get_leaf(pdev, subdev_match, &arg); +} + +static inline struct platform_device * +xleaf_get_leaf_by_epname(struct platform_device *pdev, const char *name) +{ + return xleaf_get_leaf(pdev, xrt_subdev_match_epname, (void *)name); +} + +static inline int xleaf_call(struct platform_device *tgt, u32 cmd, void *arg) +{ + struct xrt_subdev_drvdata *drvdata = DEV_DRVDATA(tgt); + + return (*drvdata->xsd_dev_ops.xsd_leaf_call)(tgt, cmd, arg); +} + +int xleaf_broadcast_event(struct platform_device *pdev, enum xrt_events evt, bool async); +int xleaf_create_group(struct platform_device *pdev, char *dtb); +int xleaf_destroy_group(struct platform_device *pdev, int instance); +void xleaf_get_barres(struct platform_device *pdev, struct resource **res, uint bar_idx); +void xleaf_get_root_id(struct platform_device *pdev, unsigned short *vendor, unsigned short *device, + unsigned short *subvendor, unsigned short *subdevice); +void xleaf_hot_reset(struct platform_device *pdev); +int xleaf_put_leaf(struct platform_device *pdev, struct platform_device *leaf); +struct device *xleaf_register_hwmon(struct platform_device *pdev, const char *name, void *drvdata, + const struct attribute_group **grps); +void xleaf_unregister_hwmon(struct platform_device *pdev, struct device *hwmon); +int xleaf_wait_for_group_bringup(struct platform_device *pdev); + +/* + * Character device helper APIs for use by leaf drivers + */ +static inline bool xleaf_devnode_enabled(struct xrt_subdev_drvdata *drvdata) +{ + return drvdata && drvdata->xsd_file_ops.xsf_ops.open; +} + +int xleaf_devnode_create(struct platform_device *pdev, + const char *file_name, const char *inst_name); +int xleaf_devnode_destroy(struct platform_device *pdev); + +struct platform_device *xleaf_devnode_open_excl(struct inode *inode); +struct platform_device *xleaf_devnode_open(struct inode *inode); +void xleaf_devnode_close(struct inode *inode); + +/* Helpers. */ +int xleaf_register_driver(enum xrt_subdev_id id, struct platform_driver *drv, + struct xrt_subdev_endpoints *eps); +void xleaf_unregister_driver(enum xrt_subdev_id id); + +/* Module's init/fini routines for leaf driver in xrt-lib module */ +#define XRT_LEAF_INIT_FINI_FUNC(_id, name) \ +void name##_leaf_init_fini(bool init) \ +{ \ + typeof(_id) id = _id; \ + if (init) { \ + xleaf_register_driver(id, \ + &xrt_##name##_driver, \ + xrt_##name##_endpoints); \ + } else { \ + xleaf_unregister_driver(id); \ + } \ +} + +void group_leaf_init_fini(bool init); +void vsec_leaf_init_fini(bool init); +void devctl_leaf_init_fini(bool init); +void axigate_leaf_init_fini(bool init); +void icap_leaf_init_fini(bool init); +void calib_leaf_init_fini(bool init); +void clkfreq_leaf_init_fini(bool init); +void clock_leaf_init_fini(bool init); +void ucs_leaf_init_fini(bool init); + +#endif /* _XRT_LEAF_H_ */ diff --git a/drivers/fpga/xrt/lib/lib-drv.c b/drivers/fpga/xrt/lib/lib-drv.c new file mode 100644 index 000000000000..64bb8710be66 --- /dev/null +++ b/drivers/fpga/xrt/lib/lib-drv.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include +#include "xleaf.h" +#include "xroot.h" +#include "lib-drv.h" + +#define XRT_IPLIB_MODULE_NAME "xrt-lib" +#define XRT_IPLIB_MODULE_VERSION "4.0.0" +#define XRT_MAX_DEVICE_NODES 128 +#define XRT_DRVNAME(drv) ((drv)->driver.name) + +/* + * Subdev driver is known by it's ID to others. We map the ID to it's + * struct platform_driver, which contains it's binding name and driver/file ops. + * We also map it to the endpoint name in DTB as well, if it's different + * than the driver's binding name. + */ +struct xrt_drv_map { + struct list_head list; + enum xrt_subdev_id id; + struct platform_driver *drv; + struct xrt_subdev_endpoints *eps; + struct ida ida; /* manage driver instance and char dev minor */ +}; + +static DEFINE_MUTEX(xrt_lib_lock); /* global lock protecting xrt_drv_maps list */ +static LIST_HEAD(xrt_drv_maps); +struct class *xrt_class; + +static inline struct xrt_subdev_drvdata * +xrt_drv_map2drvdata(struct xrt_drv_map *map) +{ + return (struct xrt_subdev_drvdata *)map->drv->id_table[0].driver_data; +} + +static struct xrt_drv_map * +__xrt_drv_find_map_by_id(enum xrt_subdev_id id) +{ + struct xrt_drv_map *tmap; + + list_for_each_entry(tmap, &xrt_drv_maps, list) { + if (tmap->id == id) + return tmap; + } + return NULL; +} + +static struct xrt_drv_map * +xrt_drv_find_map_by_id(enum xrt_subdev_id id) +{ + struct xrt_drv_map *map; + + mutex_lock(&xrt_lib_lock); + map = __xrt_drv_find_map_by_id(id); + mutex_unlock(&xrt_lib_lock); + /* + * map should remain valid even after the lock is dropped since a registered + * driver should only be unregistered when driver module is being unloaded, + * which means that the driver should not be used by then. + */ + return map; +} + +static int xrt_drv_register_driver(struct xrt_drv_map *map) +{ + struct xrt_subdev_drvdata *drvdata; + int rc = 0; + const char *drvname = XRT_DRVNAME(map->drv); + + rc = platform_driver_register(map->drv); + if (rc) { + pr_err("register %s platform driver failed\n", drvname); + return rc; + } + + drvdata = xrt_drv_map2drvdata(map); + if (drvdata) { + /* Initialize dev_t for char dev node. */ + if (xleaf_devnode_enabled(drvdata)) { + rc = alloc_chrdev_region(&drvdata->xsd_file_ops.xsf_dev_t, 0, + XRT_MAX_DEVICE_NODES, drvname); + if (rc) { + platform_driver_unregister(map->drv); + pr_err("failed to alloc dev minor for %s: %d\n", drvname, rc); + return rc; + } + } else { + drvdata->xsd_file_ops.xsf_dev_t = (dev_t)-1; + } + } + + ida_init(&map->ida); + + pr_info("%s registered successfully\n", drvname); + + return 0; +} + +static void xrt_drv_unregister_driver(struct xrt_drv_map *map) +{ + const char *drvname = XRT_DRVNAME(map->drv); + struct xrt_subdev_drvdata *drvdata; + + ida_destroy(&map->ida); + + drvdata = xrt_drv_map2drvdata(map); + if (drvdata && drvdata->xsd_file_ops.xsf_dev_t != (dev_t)-1) { + unregister_chrdev_region(drvdata->xsd_file_ops.xsf_dev_t, + XRT_MAX_DEVICE_NODES); + } + + platform_driver_unregister(map->drv); + + pr_info("%s unregistered successfully\n", drvname); +} + +int xleaf_register_driver(enum xrt_subdev_id id, + struct platform_driver *drv, + struct xrt_subdev_endpoints *eps) +{ + struct xrt_drv_map *map; + int rc; + + mutex_lock(&xrt_lib_lock); + + map = __xrt_drv_find_map_by_id(id); + if (map) { + mutex_unlock(&xrt_lib_lock); + pr_err("Id %d already has a registered driver, 0x%p\n", + id, map->drv); + return -EEXIST; + } + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + mutex_unlock(&xrt_lib_lock); + return -ENOMEM; + } + map->id = id; + map->drv = drv; + map->eps = eps; + + rc = xrt_drv_register_driver(map); + if (rc) { + kfree(map); + mutex_unlock(&xrt_lib_lock); + return rc; + } + + list_add(&map->list, &xrt_drv_maps); + + mutex_unlock(&xrt_lib_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(xleaf_register_driver); + +void xleaf_unregister_driver(enum xrt_subdev_id id) +{ + struct xrt_drv_map *map; + + mutex_lock(&xrt_lib_lock); + + map = __xrt_drv_find_map_by_id(id); + if (!map) { + mutex_unlock(&xrt_lib_lock); + pr_err("Id %d has no registered driver\n", id); + return; + } + + list_del(&map->list); + + mutex_unlock(&xrt_lib_lock); + + xrt_drv_unregister_driver(map); + kfree(map); +} +EXPORT_SYMBOL_GPL(xleaf_unregister_driver); + +const char *xrt_drv_name(enum xrt_subdev_id id) +{ + struct xrt_drv_map *map = xrt_drv_find_map_by_id(id); + + if (map) + return XRT_DRVNAME(map->drv); + return NULL; +} + +int xrt_drv_get_instance(enum xrt_subdev_id id) +{ + struct xrt_drv_map *map = xrt_drv_find_map_by_id(id); + + return ida_alloc_range(&map->ida, 0, XRT_MAX_DEVICE_NODES, GFP_KERNEL); +} + +void xrt_drv_put_instance(enum xrt_subdev_id id, int instance) +{ + struct xrt_drv_map *map = xrt_drv_find_map_by_id(id); + + ida_free(&map->ida, instance); +} + +struct xrt_subdev_endpoints *xrt_drv_get_endpoints(enum xrt_subdev_id id) +{ + struct xrt_drv_map *map = xrt_drv_find_map_by_id(id); + struct xrt_subdev_endpoints *eps; + + eps = map ? map->eps : NULL; + return eps; +} + +/* Leaf driver's module init/fini callbacks. */ +static void (*leaf_init_fini_cbs[])(bool) = { + group_leaf_init_fini, + vsec_leaf_init_fini, + devctl_leaf_init_fini, + axigate_leaf_init_fini, + icap_leaf_init_fini, + calib_leaf_init_fini, + clkfreq_leaf_init_fini, + clock_leaf_init_fini, + ucs_leaf_init_fini, +}; + +static __init int xrt_lib_init(void) +{ + int i; + + xrt_class = class_create(THIS_MODULE, XRT_IPLIB_MODULE_NAME); + if (IS_ERR(xrt_class)) + return PTR_ERR(xrt_class); + + for (i = 0; i < ARRAY_SIZE(leaf_init_fini_cbs); i++) + leaf_init_fini_cbs[i](true); + return 0; +} + +static __exit void xrt_lib_fini(void) +{ + struct xrt_drv_map *map; + int i; + + for (i = 0; i < ARRAY_SIZE(leaf_init_fini_cbs); i++) + leaf_init_fini_cbs[i](false); + + mutex_lock(&xrt_lib_lock); + + while (!list_empty(&xrt_drv_maps)) { + map = list_first_entry_or_null(&xrt_drv_maps, struct xrt_drv_map, list); + pr_err("Unloading module with %s still registered\n", XRT_DRVNAME(map->drv)); + list_del(&map->list); + mutex_unlock(&xrt_lib_lock); + xrt_drv_unregister_driver(map); + kfree(map); + mutex_lock(&xrt_lib_lock); + } + + mutex_unlock(&xrt_lib_lock); + + class_destroy(xrt_class); +} + +module_init(xrt_lib_init); +module_exit(xrt_lib_fini); + +MODULE_VERSION(XRT_IPLIB_MODULE_VERSION); +MODULE_AUTHOR("XRT Team "); +MODULE_DESCRIPTION("Xilinx Alveo IP Lib driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/fpga/xrt/lib/lib-drv.h b/drivers/fpga/xrt/lib/lib-drv.h new file mode 100644 index 000000000000..a94c58149cb4 --- /dev/null +++ b/drivers/fpga/xrt/lib/lib-drv.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _LIB_DRV_H_ +#define _LIB_DRV_H_ + +const char *xrt_drv_name(enum xrt_subdev_id id); +int xrt_drv_get_instance(enum xrt_subdev_id id); +void xrt_drv_put_instance(enum xrt_subdev_id id, int instance); +struct xrt_subdev_endpoints *xrt_drv_get_endpoints(enum xrt_subdev_id id); + +#endif /* _LIB_DRV_H_ */ From patchwork Wed Mar 24 05:29: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: 408377 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, URIBL_BLOCKED, 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 C643FC433DB for ; Wed, 24 Mar 2021 05:34:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 840F0619E0 for ; Wed, 24 Mar 2021 05:34:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235323AbhCXFeZ (ORCPT ); Wed, 24 Mar 2021 01:34:25 -0400 Received: from mail-bn8nam11on2054.outbound.protection.outlook.com ([40.107.236.54]:59104 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235293AbhCXFdy (ORCPT ); Wed, 24 Mar 2021 01:33:54 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=e/gdB46G7wZ8DRh9TPcMP8yDlmDc+JUMok1jg/NYEUgHtvgTPECfvqsB9LScrC+is2ChwpRdwuW7WboFGHY5If4+lNJ7EO9B+jKkpcGrRKBO4MqiQ/f6bTa7L04G7w5vCuJzrn+nQJcnqtmYDuLv8E2fHu2rcq0k9ZBre3bzpS6GzAhRtbBp0tKum5L0l/7vzLierv2D4LDGkZTzLUZahxxasH5iGFeBXidW2ACM9AhLue+ok6K3LT11GhpI9sW78tN8doedDeluqUDhg5W95zZ24+w3obxZCf5srFVtsDZjpHR8ihpZxLRqcqYK7PmiCDtX6RQF0C8nU8nLts6NWQ== 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=ZFXc46KOFg28RMmAOwlf+WAT802d6nzu43fRCR7rwcs=; b=hVrtsAqBg/CJAkgwbrryYnUHIrtW8Ga0lqYKuJ2QRkaNxrjQQcLWEwpiSvCJvq+tVvyFoBn6hGcF/XT/lXlCrAw3QhHnXi7SeX3xRFC28JEzx8bBpII/UEbLG2T2FM7Zhm9I/ZKiQdL7mUNOdEFCmB2xYuCjKqBeFaAMfQ0WjIocDXBCPZtq8hyP83YAi4hnvdTx27C5UZ1r+rQ21AXkXfuNTaVPaHGSMiKyPFhxuw+m8NMMm9y3+4Yv1K1gGKVPxzhUjtOBRNt7x7ODZSfi5f0lzJO92eT/OTETbGfjN7rRnJD4WUpxDAKbe3c6nZoYQ/x3Lq9XMgibTxx8sZP8Cg== 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=ZFXc46KOFg28RMmAOwlf+WAT802d6nzu43fRCR7rwcs=; b=QcO9VVBLFcTX1aBIMyD+x96g5k/l1wW0ai8IkPJH3jFNZWvLauAmh5P9gCdeCSzrGux5DNwD9//MPW/fjBEpxtR2/jMqSOVK3fB5/czEYYI5yklMxq6VBp0ptyjFRNO66EhS1vhf4ydVgFTKzYV2R0N8eyh6ziQB1kKpaTdBFQQ= Received: from SN6PR16CA0056.namprd16.prod.outlook.com (2603:10b6:805:ca::33) by CY4PR02MB3253.namprd02.prod.outlook.com (2603:10b6:910:80::37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:33:51 +0000 Received: from SN1NAM02FT025.eop-nam02.prod.protection.outlook.com (2603:10b6:805:ca:cafe::c) by SN6PR16CA0056.outlook.office365.com (2603:10b6:805:ca::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:33:50 +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 SN1NAM02FT025.mail.protection.outlook.com (10.152.72.87) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:33:50 +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.2106.2; Tue, 23 Mar 2021 22:33:34 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:33:34 -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=51032 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOw98-0005ts-3w; Tue, 23 Mar 2021 22:33:34 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 1391C600124; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 06/20] fpga: xrt: char dev node helper functions Date: Tue, 23 Mar 2021 22:29:33 -0700 Message-ID: <20210324052947.27889-7-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a29ab9d6-6d06-45c9-0237-08d8ee866788 X-MS-TrafficTypeDiagnostic: CY4PR02MB3253: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:67; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: n6G0E/8jGs9wGT15oRDlrDcM1dlCB3PsVVyaYypIur1QN61GSijO0vyEkQb42gOT3Edzy3yBD0YObsqXzrmiBHIxANa+fsivT+7P47DsMf/pLBTmOkNYAtann4rfZHRU7WBtmnnkvP8Mz4QNCUROnG+F7TQkD5SBs/pL469mknAQdo32zrNSrz0fyiSrnEJ7Zu9vPFot+gFOV2o8tZBeT5ZnJYBG/mk6bmebLjuM5Pqqgwr1zK1p5PKMXQJfE5Bgb6ZDEZJyLw4HzstLMR8A8dudOOEe3O6u5qlCBcFG+/Gv32kB2Z0ShGt8/Ak9+2yHa4xpG8pPJIEnNb5LkT85K6g46kQ3I8oW2qdiKstE0FWnORCgJSDOiWsWVaqwTOlDfwSfgKp9AWa6X+bDyEfM9bBx5ogpHug8LHOvp0AentZ/6fnxOshZT09m/wAC3mjv9r0xmrzs0rcG++hP9PySiogTwXb+XPmZHQcwf4GjbeDlbb+AgpVtynZKHQOxVlNF/c2qhCPi5cGFOzDZ1npmU/y8eF8jJkDQGJFC8YVclZEsQ4c5y8zyip2eFhmLzwFb9/WhXycIlPDFl5TSLQFoMq1jfCTJ3mXRSd+I9/uZ7DARER9I0Vl/kyPXUpYXTablgzSkWw6Atelu16JaDyVvv7IR0Tk+uZAg4THX6TSP4d4= 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)(396003)(136003)(346002)(376002)(39860400002)(46966006)(36840700001)(70586007)(70206006)(44832011)(478600001)(36860700001)(8676002)(6916009)(47076005)(356005)(42186006)(186003)(54906003)(336012)(4326008)(1076003)(426003)(83380400001)(36756003)(2616005)(82310400003)(6666004)(82740400003)(36906005)(26005)(8936002)(5660300002)(316002)(107886003)(6266002)(2906002)(7636003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:33:50.2120 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: a29ab9d6-6d06-45c9-0237-08d8ee866788 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: SN1NAM02FT025.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR02MB3253 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Helper functions for char device node creation / removal for platform drivers. This is part of platform driver infrastructure. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/lib/cdev.c | 232 ++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 drivers/fpga/xrt/lib/cdev.c diff --git a/drivers/fpga/xrt/lib/cdev.c b/drivers/fpga/xrt/lib/cdev.c new file mode 100644 index 000000000000..38efd24b6e10 --- /dev/null +++ b/drivers/fpga/xrt/lib/cdev.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA device node helper functions. + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include "xleaf.h" + +extern struct class *xrt_class; + +#define XRT_CDEV_DIR "xfpga" +#define INODE2PDATA(inode) \ + container_of((inode)->i_cdev, struct xrt_subdev_platdata, xsp_cdev) +#define INODE2PDEV(inode) \ + to_platform_device(kobj_to_dev((inode)->i_cdev->kobj.parent)) +#define CDEV_NAME(sysdev) (strchr((sysdev)->kobj.name, '!') + 1) + +/* Allow it to be accessed from cdev. */ +static void xleaf_devnode_allowed(struct platform_device *pdev) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(pdev); + + /* Allow new opens. */ + mutex_lock(&pdata->xsp_devnode_lock); + pdata->xsp_devnode_online = true; + mutex_unlock(&pdata->xsp_devnode_lock); +} + +/* Turn off access from cdev and wait for all existing user to go away. */ +static int xleaf_devnode_disallowed(struct platform_device *pdev) +{ + int ret = 0; + struct xrt_subdev_platdata *pdata = DEV_PDATA(pdev); + + mutex_lock(&pdata->xsp_devnode_lock); + + /* Prevent new opens. */ + pdata->xsp_devnode_online = false; + /* Wait for existing user to close. */ + while (!ret && pdata->xsp_devnode_ref) { + int rc; + + mutex_unlock(&pdata->xsp_devnode_lock); + rc = wait_for_completion_killable(&pdata->xsp_devnode_comp); + mutex_lock(&pdata->xsp_devnode_lock); + + if (rc == -ERESTARTSYS) { + /* Restore online state. */ + pdata->xsp_devnode_online = true; + xrt_err(pdev, "%s is in use, ref=%d", + CDEV_NAME(pdata->xsp_sysdev), + pdata->xsp_devnode_ref); + ret = -EBUSY; + } + } + + mutex_unlock(&pdata->xsp_devnode_lock); + + return ret; +} + +static struct platform_device * +__xleaf_devnode_open(struct inode *inode, bool excl) +{ + struct xrt_subdev_platdata *pdata = INODE2PDATA(inode); + struct platform_device *pdev = INODE2PDEV(inode); + bool opened = false; + + mutex_lock(&pdata->xsp_devnode_lock); + + if (pdata->xsp_devnode_online) { + if (excl && pdata->xsp_devnode_ref) { + xrt_err(pdev, "%s has already been opened exclusively", + CDEV_NAME(pdata->xsp_sysdev)); + } else if (!excl && pdata->xsp_devnode_excl) { + xrt_err(pdev, "%s has been opened exclusively", + CDEV_NAME(pdata->xsp_sysdev)); + } else { + pdata->xsp_devnode_ref++; + pdata->xsp_devnode_excl = excl; + opened = true; + xrt_info(pdev, "opened %s, ref=%d", + CDEV_NAME(pdata->xsp_sysdev), + pdata->xsp_devnode_ref); + } + } else { + xrt_err(pdev, "%s is offline", CDEV_NAME(pdata->xsp_sysdev)); + } + + mutex_unlock(&pdata->xsp_devnode_lock); + + pdev = opened ? pdev : NULL; + return pdev; +} + +struct platform_device * +xleaf_devnode_open_excl(struct inode *inode) +{ + return __xleaf_devnode_open(inode, true); +} + +struct platform_device * +xleaf_devnode_open(struct inode *inode) +{ + return __xleaf_devnode_open(inode, false); +} +EXPORT_SYMBOL_GPL(xleaf_devnode_open); + +void xleaf_devnode_close(struct inode *inode) +{ + struct xrt_subdev_platdata *pdata = INODE2PDATA(inode); + struct platform_device *pdev = INODE2PDEV(inode); + bool notify = false; + + mutex_lock(&pdata->xsp_devnode_lock); + + WARN_ON(pdata->xsp_devnode_ref == 0); + pdata->xsp_devnode_ref--; + if (pdata->xsp_devnode_ref == 0) { + pdata->xsp_devnode_excl = false; + notify = true; + } + if (notify) { + xrt_info(pdev, "closed %s, ref=%d", + CDEV_NAME(pdata->xsp_sysdev), pdata->xsp_devnode_ref); + } else { + xrt_info(pdev, "closed %s, notifying waiter", + CDEV_NAME(pdata->xsp_sysdev)); + } + + mutex_unlock(&pdata->xsp_devnode_lock); + + if (notify) + complete(&pdata->xsp_devnode_comp); +} +EXPORT_SYMBOL_GPL(xleaf_devnode_close); + +static inline enum xrt_subdev_file_mode +devnode_mode(struct xrt_subdev_drvdata *drvdata) +{ + return drvdata->xsd_file_ops.xsf_mode; +} + +int xleaf_devnode_create(struct platform_device *pdev, const char *file_name, + const char *inst_name) +{ + struct xrt_subdev_drvdata *drvdata = DEV_DRVDATA(pdev); + struct xrt_subdev_file_ops *fops = &drvdata->xsd_file_ops; + struct xrt_subdev_platdata *pdata = DEV_PDATA(pdev); + struct cdev *cdevp; + struct device *sysdev; + int ret = 0; + char fname[256]; + + mutex_init(&pdata->xsp_devnode_lock); + init_completion(&pdata->xsp_devnode_comp); + + cdevp = &DEV_PDATA(pdev)->xsp_cdev; + cdev_init(cdevp, &fops->xsf_ops); + cdevp->owner = fops->xsf_ops.owner; + cdevp->dev = MKDEV(MAJOR(fops->xsf_dev_t), pdev->id); + + /* + * Set pdev as parent of cdev so that when pdev (and its platform + * data) will not be freed when cdev is not freed. + */ + cdev_set_parent(cdevp, &DEV(pdev)->kobj); + + ret = cdev_add(cdevp, cdevp->dev, 1); + if (ret) { + xrt_err(pdev, "failed to add cdev: %d", ret); + goto failed; + } + if (!file_name) + file_name = pdev->name; + if (!inst_name) { + if (devnode_mode(drvdata) == XRT_SUBDEV_FILE_MULTI_INST) { + snprintf(fname, sizeof(fname), "%s/%s/%s.%u", + XRT_CDEV_DIR, DEV_PDATA(pdev)->xsp_root_name, + file_name, pdev->id); + } else { + snprintf(fname, sizeof(fname), "%s/%s/%s", + XRT_CDEV_DIR, DEV_PDATA(pdev)->xsp_root_name, + file_name); + } + } else { + snprintf(fname, sizeof(fname), "%s/%s/%s.%s", XRT_CDEV_DIR, + DEV_PDATA(pdev)->xsp_root_name, file_name, inst_name); + } + sysdev = device_create(xrt_class, NULL, cdevp->dev, NULL, "%s", fname); + if (IS_ERR(sysdev)) { + ret = PTR_ERR(sysdev); + xrt_err(pdev, "failed to create device node: %d", ret); + goto failed_cdev_add; + } + pdata->xsp_sysdev = sysdev; + + xleaf_devnode_allowed(pdev); + + xrt_info(pdev, "created (%d, %d): /dev/%s", + MAJOR(cdevp->dev), pdev->id, fname); + return 0; + +failed_cdev_add: + cdev_del(cdevp); +failed: + cdevp->owner = NULL; + return ret; +} + +int xleaf_devnode_destroy(struct platform_device *pdev) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(pdev); + struct cdev *cdevp = &pdata->xsp_cdev; + dev_t dev = cdevp->dev; + int rc; + + rc = xleaf_devnode_disallowed(pdev); + if (rc) + return rc; + + xrt_info(pdev, "removed (%d, %d): /dev/%s/%s", MAJOR(dev), MINOR(dev), + XRT_CDEV_DIR, CDEV_NAME(pdata->xsp_sysdev)); + device_destroy(xrt_class, cdevp->dev); + pdata->xsp_sysdev = NULL; + cdev_del(cdevp); + return 0; +} From patchwork Wed Mar 24 05:29: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: 408376 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, URIBL_BLOCKED, 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 259CFC433E4 for ; Wed, 24 Mar 2021 05:34:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0675A619F9 for ; Wed, 24 Mar 2021 05:34:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235293AbhCXFe1 (ORCPT ); Wed, 24 Mar 2021 01:34:27 -0400 Received: from mail-dm6nam11on2075.outbound.protection.outlook.com ([40.107.223.75]:2144 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235252AbhCXFeT (ORCPT ); Wed, 24 Mar 2021 01:34:19 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=KjF+Nq6xn1gHUb7bFoTdcs4lIcgBzBCL0dRh7BaUYT/NYBw1BM/S37xHCqBeWyOwjlr/TAuiXi7dd4PNRFPiVHH870bprkJAeikW+AhJjTm+sXXzL/6etnmuDmwF/IevPU2EvdGyMKBhDLCPSmuOP4QhsctsA8N3WN09DQ1OMYWpvzrnRwjhuuOeE5YbZKpsgpc7OObgCYg4TNG3frTu8aIJW1SF0vGT3qIQjHcWkUUvsf1rkNXURs87GUP9GmykkO0B7UDXokOxD2zYVg8XrpMuVwcrz0+UT1KxpLrKqDdXB7w4nZP5IEaHCINTDliZDrkRz7eKMPqhwlQiJqg3lA== 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=OoP8kJkrUbVP+ri0C5DHr5E1nhcG8tnxMUORKffmA+E=; b=hNqLNWxl2d0VCUxjRh9AqQCSRt1/D3fokf1aacON6Dc9887ul4epInn8tp8H3O7Uaj87kwRE3F8lgvi3x/F/4gF2LZxZF4Q2LflV/dNYc0Y6fwGWNAv+WJGMr3mXTNeCQo15MedLEvJ1pTZlLIGbgOCP5cbWH/qa+xz4pmIWOTVt5o5y0d44+D7TrGheMc0psQ0zEBXOk+MPdHfosdN/kcp0+427u36ClZDkh2ML4GwXGwKIFWfX/QEBELvqjxFCXAL88RiRKMXP8X2e/dQ7xOn978xsmaL7YOkQjy525Zu6yUt6QuwFlnyiRVuBJRVqxybFXf4DYbDumGZtlNJ8Pg== 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=OoP8kJkrUbVP+ri0C5DHr5E1nhcG8tnxMUORKffmA+E=; b=jS2dOtnziHMAooCvx1o+xlgGeXCnsZDnk8WGEvLgvDbn7OeJcegbuG7/m6v4lqlhWIz4CeI18AJ/Thk1IL47v7i0IK7muMldw+qHsP27DAtM3nQAYxH3kNJcdnoflZkse/l5rdUeLx62kpMqwlbrFU0ciHSgHBMme2btK5lWdpY= Received: from SN6PR08CA0025.namprd08.prod.outlook.com (2603:10b6:805:66::38) by MWHPR02MB2336.namprd02.prod.outlook.com (2603:10b6:300:5d::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:34:16 +0000 Received: from SN1NAM02FT030.eop-nam02.prod.protection.outlook.com (2603:10b6:805:66:cafe::b5) by SN6PR08CA0025.outlook.office365.com (2603:10b6:805:66::38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:34:16 +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 SN1NAM02FT030.mail.protection.outlook.com (10.152.72.114) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:34:16 +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.2106.2; Tue, 23 Mar 2021 22:33:58 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:33:58 -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=51036 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOw9W-0004WK-78; Tue, 23 Mar 2021 22:33:58 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 42401600127; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 08/20] fpga: xrt: platform driver infrastructure Date: Tue, 23 Mar 2021 22:29:35 -0700 Message-ID: <20210324052947.27889-9-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 056bdf9b-8927-482b-8580-08d8ee86772e X-MS-TrafficTypeDiagnostic: MWHPR02MB2336: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:525; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: T5bInnO7zX3dteObKau1Vu/RwWlHeZaqW0ZQKLOEuM/fO+sTeyRvT/NNjyQ5MQWuIxdjiJD+hojCq4iU2+7IdeYCtOOlamQ7TbXuSkRco7MNi3cettqlHq7aUingXs2xX7GtaM1mKAHN9TpQE5URmqXCd6QzSVJ1CNKgALDFm91lpT16plok5LtsCzgbVlbqWTBkTonnh9Exo5WGU5Bj/lUlrO+kiuFmTu925ZBL7Z2mLVBK49BAnzykVcSPVenebkLEA61XYLSvZ8uOBuyzYpY5kii5QOHWReNgWAVZsDJe5QktjlfKVv8WMVJMhF5R8k5ORj4aEluhsw+VjSdHEnVjTeZ1jYC8Gj48qWVVjkSKjSOTiZ64UYPbWsnFwtuflN/ujnQwHfgLpn7jijKJXWWAuWjLSuszKc2UDbQ6JBk11k3lKZLcTjIqrS5K1y2ScYY78VXg51uhbwmRyQ+Lh3pBhsTLKEGhkgYu1uUqZjEiSjT5LqOpPR7FTB6Y+w7u8mI40Ps0bNKIkK1NGepIQLAYctTEJwByYOKmxwAjYBcIMKUVePgTS//dDWgP7+G8tcBB1zniV0ubes57i//Ixvi3RqPH3XtnVEc0R2o2XaivVLBlraDj7Wk4myDjcUTbzwV2ptOmTKo1+3JIm47jBQ== 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)(39860400002)(376002)(346002)(396003)(46966006)(36840700001)(70586007)(107886003)(426003)(82310400003)(6916009)(186003)(8936002)(70206006)(4326008)(36906005)(1076003)(6666004)(6266002)(44832011)(316002)(26005)(356005)(83380400001)(30864003)(36860700001)(36756003)(478600001)(8676002)(47076005)(2616005)(82740400003)(42186006)(54906003)(2906002)(336012)(7636003)(5660300002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:34:16.4681 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 056bdf9b-8927-482b-8580-08d8ee86772e 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: SN1NAM02FT030.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MWHPR02MB2336 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Infrastructure code providing APIs for managing leaf driver instance groups, facilitating inter-leaf driver calls and root calls. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/lib/subdev.c | 865 ++++++++++++++++++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100644 drivers/fpga/xrt/lib/subdev.c diff --git a/drivers/fpga/xrt/lib/subdev.c b/drivers/fpga/xrt/lib/subdev.c new file mode 100644 index 000000000000..6428b183fee3 --- /dev/null +++ b/drivers/fpga/xrt/lib/subdev.c @@ -0,0 +1,865 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include +#include +#include "xleaf.h" +#include "subdev_pool.h" +#include "lib-drv.h" +#include "metadata.h" + +#define IS_ROOT_DEV(dev) ((dev)->bus == &pci_bus_type) +static inline struct device *find_root(struct platform_device *pdev) +{ + struct device *d = DEV(pdev); + + while (!IS_ROOT_DEV(d)) + d = d->parent; + return d; +} + +/* + * It represents a holder of a subdev. One holder can repeatedly hold a subdev + * as long as there is a unhold corresponding to a hold. + */ +struct xrt_subdev_holder { + struct list_head xsh_holder_list; + struct device *xsh_holder; + int xsh_count; + struct kref xsh_kref; +}; + +/* + * It represents a specific instance of platform driver for a subdev, which + * provides services to its clients (another subdev driver or root driver). + */ +struct xrt_subdev { + struct list_head xs_dev_list; + struct list_head xs_holder_list; + enum xrt_subdev_id xs_id; /* type of subdev */ + struct platform_device *xs_pdev; /* a particular subdev inst */ + struct completion xs_holder_comp; +}; + +static struct xrt_subdev *xrt_subdev_alloc(void) +{ + struct xrt_subdev *sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); + + if (!sdev) + return NULL; + + INIT_LIST_HEAD(&sdev->xs_dev_list); + INIT_LIST_HEAD(&sdev->xs_holder_list); + init_completion(&sdev->xs_holder_comp); + return sdev; +} + +static void xrt_subdev_free(struct xrt_subdev *sdev) +{ + kfree(sdev); +} + +int xrt_subdev_root_request(struct platform_device *self, u32 cmd, void *arg) +{ + struct device *dev = DEV(self); + struct xrt_subdev_platdata *pdata = DEV_PDATA(self); + + WARN_ON(!pdata->xsp_root_cb); + return (*pdata->xsp_root_cb)(dev->parent, pdata->xsp_root_cb_arg, cmd, arg); +} + +/* + * Subdev common sysfs nodes. + */ +static ssize_t holders_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t len; + struct platform_device *pdev = to_platform_device(dev); + struct xrt_root_get_holders holders = { pdev, buf, 1024 }; + + len = xrt_subdev_root_request(pdev, XRT_ROOT_GET_LEAF_HOLDERS, &holders); + if (len >= holders.xpigh_holder_buf_len) + return len; + buf[len] = '\n'; + return len + 1; +} +static DEVICE_ATTR_RO(holders); + +static struct attribute *xrt_subdev_attrs[] = { + &dev_attr_holders.attr, + NULL, +}; + +static ssize_t metadata_output(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct platform_device *pdev = to_platform_device(dev); + struct xrt_subdev_platdata *pdata = DEV_PDATA(pdev); + unsigned char *blob; + unsigned long size; + ssize_t ret = 0; + + blob = pdata->xsp_dtb; + size = xrt_md_size(dev, blob); + if (size == XRT_MD_INVALID_LENGTH) { + ret = -EINVAL; + goto failed; + } + + if (off >= size) + goto failed; + + if (off + count > size) + count = size - off; + memcpy(buf, blob + off, count); + + ret = count; +failed: + return ret; +} + +static struct bin_attribute meta_data_attr = { + .attr = { + .name = "metadata", + .mode = 0400 + }, + .read = metadata_output, + .size = 0 +}; + +static struct bin_attribute *xrt_subdev_bin_attrs[] = { + &meta_data_attr, + NULL, +}; + +static const struct attribute_group xrt_subdev_attrgroup = { + .attrs = xrt_subdev_attrs, + .bin_attrs = xrt_subdev_bin_attrs, +}; + +/* + * Given the device metadata, parse it to get IO ranges and construct + * resource array. + */ +static int +xrt_subdev_getres(struct device *parent, enum xrt_subdev_id id, + char *dtb, struct resource **res, int *res_num) +{ + struct xrt_subdev_platdata *pdata; + struct resource *pci_res = NULL; + const u64 *bar_range; + const u32 *bar_idx; + char *ep_name = NULL, *regmap = NULL; + uint bar; + int count1 = 0, count2 = 0, ret; + + if (!dtb) + return -EINVAL; + + pdata = DEV_PDATA(to_platform_device(parent)); + + /* go through metadata and count endpoints in it */ + for (xrt_md_get_next_endpoint(parent, dtb, NULL, NULL, &ep_name, ®map); ep_name; + xrt_md_get_next_endpoint(parent, dtb, ep_name, regmap, &ep_name, ®map)) { + ret = xrt_md_get_prop(parent, dtb, ep_name, regmap, + XRT_MD_PROP_IO_OFFSET, (const void **)&bar_range, NULL); + if (!ret) + count1++; + } + if (!count1) + return 0; + + /* allocate resource array for all endpoints been found in metadata */ + *res = vzalloc(sizeof(**res) * count1); + + /* go through all endpoints again and get IO range for each endpoint */ + for (xrt_md_get_next_endpoint(parent, dtb, NULL, NULL, &ep_name, ®map); ep_name; + xrt_md_get_next_endpoint(parent, dtb, ep_name, regmap, &ep_name, ®map)) { + ret = xrt_md_get_prop(parent, dtb, ep_name, regmap, + XRT_MD_PROP_IO_OFFSET, (const void **)&bar_range, NULL); + if (ret) + continue; + xrt_md_get_prop(parent, dtb, ep_name, regmap, + XRT_MD_PROP_BAR_IDX, (const void **)&bar_idx, NULL); + bar = bar_idx ? be32_to_cpu(*bar_idx) : 0; + xleaf_get_barres(to_platform_device(parent), &pci_res, bar); + (*res)[count2].start = pci_res->start + + be64_to_cpu(bar_range[0]); + (*res)[count2].end = pci_res->start + + be64_to_cpu(bar_range[0]) + + be64_to_cpu(bar_range[1]) - 1; + (*res)[count2].flags = IORESOURCE_MEM; + /* check if there is conflicted resource */ + ret = request_resource(pci_res, *res + count2); + if (ret) { + dev_err(parent, "Conflict resource %pR\n", *res + count2); + vfree(*res); + *res_num = 0; + *res = NULL; + return ret; + } + release_resource(*res + count2); + + (*res)[count2].parent = pci_res; + + xrt_md_find_endpoint(parent, pdata->xsp_dtb, ep_name, + regmap, &(*res)[count2].name); + + count2++; + } + + WARN_ON(count1 != count2); + *res_num = count2; + + return 0; +} + +static inline enum xrt_subdev_file_mode +xleaf_devnode_mode(struct xrt_subdev_drvdata *drvdata) +{ + return drvdata->xsd_file_ops.xsf_mode; +} + +static bool xrt_subdev_cdev_auto_creation(struct platform_device *pdev) +{ + struct xrt_subdev_drvdata *drvdata = DEV_DRVDATA(pdev); + enum xrt_subdev_file_mode mode = xleaf_devnode_mode(drvdata); + + if (!drvdata) + return false; + + if (!xleaf_devnode_enabled(drvdata)) + return false; + + return (mode == XRT_SUBDEV_FILE_DEFAULT || mode == XRT_SUBDEV_FILE_MULTI_INST); +} + +static struct xrt_subdev * +xrt_subdev_create(struct device *parent, enum xrt_subdev_id id, + xrt_subdev_root_cb_t pcb, void *pcb_arg, char *dtb) +{ + struct xrt_subdev_platdata *pdata = NULL; + struct platform_device *pdev = NULL; + int inst = PLATFORM_DEVID_NONE; + struct xrt_subdev *sdev = NULL; + struct resource *res = NULL; + unsigned long dtb_len = 0; + int res_num = 0; + size_t pdata_sz; + int ret; + + sdev = xrt_subdev_alloc(); + if (!sdev) { + dev_err(parent, "failed to alloc subdev for ID %d", id); + goto fail; + } + sdev->xs_id = id; + + if (!dtb) { + ret = xrt_md_create(parent, &dtb); + if (ret) { + dev_err(parent, "can't create empty dtb: %d", ret); + goto fail; + } + } + xrt_md_pack(parent, dtb); + dtb_len = xrt_md_size(parent, dtb); + if (dtb_len == XRT_MD_INVALID_LENGTH) { + dev_err(parent, "invalid metadata len %ld", dtb_len); + goto fail; + } + pdata_sz = sizeof(struct xrt_subdev_platdata) + dtb_len; + + /* Prepare platform data passed to subdev. */ + pdata = vzalloc(pdata_sz); + if (!pdata) + goto fail; + + pdata->xsp_root_cb = pcb; + pdata->xsp_root_cb_arg = pcb_arg; + memcpy(pdata->xsp_dtb, dtb, dtb_len); + if (id == XRT_SUBDEV_GRP) { + /* Group can only be created by root driver. */ + pdata->xsp_root_name = dev_name(parent); + } else { + struct platform_device *grp = to_platform_device(parent); + /* Leaf can only be created by group driver. */ + WARN_ON(strncmp(xrt_drv_name(XRT_SUBDEV_GRP), + platform_get_device_id(grp)->name, + strlen(xrt_drv_name(XRT_SUBDEV_GRP)) + 1)); + pdata->xsp_root_name = DEV_PDATA(grp)->xsp_root_name; + } + + /* Obtain dev instance number. */ + inst = xrt_drv_get_instance(id); + if (inst < 0) { + dev_err(parent, "failed to obtain instance: %d", inst); + goto fail; + } + + /* Create subdev. */ + if (id != XRT_SUBDEV_GRP) { + int rc = xrt_subdev_getres(parent, id, dtb, &res, &res_num); + + if (rc) { + dev_err(parent, "failed to get resource for %s.%d: %d", + xrt_drv_name(id), inst, rc); + goto fail; + } + } + pdev = platform_device_register_resndata(parent, xrt_drv_name(id), + inst, res, res_num, pdata, pdata_sz); + vfree(res); + if (IS_ERR(pdev)) { + dev_err(parent, "failed to create subdev for %s inst %d: %ld", + xrt_drv_name(id), inst, PTR_ERR(pdev)); + goto fail; + } + sdev->xs_pdev = pdev; + + if (device_attach(DEV(pdev)) != 1) { + xrt_err(pdev, "failed to attach"); + goto fail; + } + + if (sysfs_create_group(&DEV(pdev)->kobj, &xrt_subdev_attrgroup)) + xrt_err(pdev, "failed to create sysfs group"); + + /* + * Create sysfs sym link under root for leaves + * under random groups for easy access to them. + */ + if (id != XRT_SUBDEV_GRP) { + if (sysfs_create_link(&find_root(pdev)->kobj, + &DEV(pdev)->kobj, dev_name(DEV(pdev)))) { + xrt_err(pdev, "failed to create sysfs link"); + } + } + + /* All done, ready to handle req thru cdev. */ + if (xrt_subdev_cdev_auto_creation(pdev)) + xleaf_devnode_create(pdev, DEV_DRVDATA(pdev)->xsd_file_ops.xsf_dev_name, NULL); + + vfree(pdata); + return sdev; + +fail: + vfree(pdata); + if (sdev && !IS_ERR_OR_NULL(sdev->xs_pdev)) + platform_device_unregister(sdev->xs_pdev); + if (inst >= 0) + xrt_drv_put_instance(id, inst); + xrt_subdev_free(sdev); + return NULL; +} + +static void xrt_subdev_destroy(struct xrt_subdev *sdev) +{ + struct platform_device *pdev = sdev->xs_pdev; + struct device *dev = DEV(pdev); + int inst = pdev->id; + int ret; + + /* Take down the device node */ + if (xrt_subdev_cdev_auto_creation(pdev)) { + ret = xleaf_devnode_destroy(pdev); + WARN_ON(ret); + } + if (sdev->xs_id != XRT_SUBDEV_GRP) + sysfs_remove_link(&find_root(pdev)->kobj, dev_name(dev)); + sysfs_remove_group(&dev->kobj, &xrt_subdev_attrgroup); + platform_device_unregister(pdev); + xrt_drv_put_instance(sdev->xs_id, inst); + xrt_subdev_free(sdev); +} + +struct platform_device * +xleaf_get_leaf(struct platform_device *pdev, xrt_subdev_match_t match_cb, void *match_arg) +{ + int rc; + struct xrt_root_get_leaf get_leaf = { + pdev, match_cb, match_arg, }; + + rc = xrt_subdev_root_request(pdev, XRT_ROOT_GET_LEAF, &get_leaf); + if (rc) + return NULL; + return get_leaf.xpigl_tgt_pdev; +} +EXPORT_SYMBOL_GPL(xleaf_get_leaf); + +bool xleaf_has_endpoint(struct platform_device *pdev, const char *endpoint_name) +{ + struct resource *res; + int i = 0; + + do { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res && !strncmp(res->name, endpoint_name, strlen(res->name) + 1)) + return true; + ++i; + } while (res); + + return false; +} +EXPORT_SYMBOL_GPL(xleaf_has_endpoint); + +int xleaf_put_leaf(struct platform_device *pdev, struct platform_device *leaf) +{ + struct xrt_root_put_leaf put_leaf = { pdev, leaf }; + + return xrt_subdev_root_request(pdev, XRT_ROOT_PUT_LEAF, &put_leaf); +} +EXPORT_SYMBOL_GPL(xleaf_put_leaf); + +int xleaf_create_group(struct platform_device *pdev, char *dtb) +{ + return xrt_subdev_root_request(pdev, XRT_ROOT_CREATE_GROUP, dtb); +} +EXPORT_SYMBOL_GPL(xleaf_create_group); + +int xleaf_destroy_group(struct platform_device *pdev, int instance) +{ + return xrt_subdev_root_request(pdev, XRT_ROOT_REMOVE_GROUP, (void *)(uintptr_t)instance); +} +EXPORT_SYMBOL_GPL(xleaf_destroy_group); + +int xleaf_wait_for_group_bringup(struct platform_device *pdev) +{ + return xrt_subdev_root_request(pdev, XRT_ROOT_WAIT_GROUP_BRINGUP, NULL); +} +EXPORT_SYMBOL_GPL(xleaf_wait_for_group_bringup); + +static ssize_t +xrt_subdev_get_holders(struct xrt_subdev *sdev, char *buf, size_t len) +{ + const struct list_head *ptr; + struct xrt_subdev_holder *h; + ssize_t n = 0; + + list_for_each(ptr, &sdev->xs_holder_list) { + h = list_entry(ptr, struct xrt_subdev_holder, xsh_holder_list); + n += snprintf(buf + n, len - n, "%s:%d ", + dev_name(h->xsh_holder), kref_read(&h->xsh_kref)); + if (n >= (len - 1)) + break; + } + return n; +} + +void xrt_subdev_pool_init(struct device *dev, struct xrt_subdev_pool *spool) +{ + INIT_LIST_HEAD(&spool->xsp_dev_list); + spool->xsp_owner = dev; + mutex_init(&spool->xsp_lock); + spool->xsp_closing = false; +} + +static void xrt_subdev_free_holder(struct xrt_subdev_holder *holder) +{ + list_del(&holder->xsh_holder_list); + vfree(holder); +} + +static void xrt_subdev_pool_wait_for_holders(struct xrt_subdev_pool *spool, struct xrt_subdev *sdev) +{ + const struct list_head *ptr, *next; + char holders[128]; + struct xrt_subdev_holder *holder; + struct mutex *lk = &spool->xsp_lock; + + while (!list_empty(&sdev->xs_holder_list)) { + int rc; + + /* It's most likely a bug if we ever enters this loop. */ + xrt_subdev_get_holders(sdev, holders, sizeof(holders)); + xrt_err(sdev->xs_pdev, "awaits holders: %s", holders); + mutex_unlock(lk); + rc = wait_for_completion_killable(&sdev->xs_holder_comp); + mutex_lock(lk); + if (rc == -ERESTARTSYS) { + xrt_err(sdev->xs_pdev, "give up on waiting for holders, clean up now"); + list_for_each_safe(ptr, next, &sdev->xs_holder_list) { + holder = list_entry(ptr, struct xrt_subdev_holder, xsh_holder_list); + xrt_subdev_free_holder(holder); + } + } + } +} + +void xrt_subdev_pool_fini(struct xrt_subdev_pool *spool) +{ + struct list_head *dl = &spool->xsp_dev_list; + struct mutex *lk = &spool->xsp_lock; + + mutex_lock(lk); + if (spool->xsp_closing) { + mutex_unlock(lk); + return; + } + spool->xsp_closing = true; + mutex_unlock(lk); + + /* Remove subdev in the reverse order of added. */ + while (!list_empty(dl)) { + struct xrt_subdev *sdev = list_first_entry(dl, struct xrt_subdev, xs_dev_list); + + xrt_subdev_pool_wait_for_holders(spool, sdev); + list_del(&sdev->xs_dev_list); + xrt_subdev_destroy(sdev); + } +} + +static struct xrt_subdev_holder *xrt_subdev_find_holder(struct xrt_subdev *sdev, + struct device *holder_dev) +{ + struct list_head *hl = &sdev->xs_holder_list; + struct xrt_subdev_holder *holder; + const struct list_head *ptr; + + list_for_each(ptr, hl) { + holder = list_entry(ptr, struct xrt_subdev_holder, xsh_holder_list); + if (holder->xsh_holder == holder_dev) + return holder; + } + return NULL; +} + +static int xrt_subdev_hold(struct xrt_subdev *sdev, struct device *holder_dev) +{ + struct xrt_subdev_holder *holder = xrt_subdev_find_holder(sdev, holder_dev); + struct list_head *hl = &sdev->xs_holder_list; + + if (!holder) { + holder = vzalloc(sizeof(*holder)); + if (!holder) + return -ENOMEM; + holder->xsh_holder = holder_dev; + kref_init(&holder->xsh_kref); + list_add_tail(&holder->xsh_holder_list, hl); + } else { + kref_get(&holder->xsh_kref); + } + + return 0; +} + +static void xrt_subdev_free_holder_kref(struct kref *kref) +{ + struct xrt_subdev_holder *holder = container_of(kref, struct xrt_subdev_holder, xsh_kref); + + xrt_subdev_free_holder(holder); +} + +static int +xrt_subdev_release(struct xrt_subdev *sdev, struct device *holder_dev) +{ + struct xrt_subdev_holder *holder = xrt_subdev_find_holder(sdev, holder_dev); + struct list_head *hl = &sdev->xs_holder_list; + + if (!holder) { + dev_err(holder_dev, "can't release, %s did not hold %s", + dev_name(holder_dev), dev_name(DEV(sdev->xs_pdev))); + return -EINVAL; + } + kref_put(&holder->xsh_kref, xrt_subdev_free_holder_kref); + + /* kref_put above may remove holder from list. */ + if (list_empty(hl)) + complete(&sdev->xs_holder_comp); + return 0; +} + +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) +{ + struct mutex *lk = &spool->xsp_lock; + struct list_head *dl = &spool->xsp_dev_list; + struct xrt_subdev *sdev; + int ret = 0; + + sdev = xrt_subdev_create(spool->xsp_owner, id, pcb, pcb_arg, dtb); + if (sdev) { + mutex_lock(lk); + if (spool->xsp_closing) { + /* No new subdev when pool is going away. */ + xrt_err(sdev->xs_pdev, "pool is closing"); + ret = -ENODEV; + } else { + list_add(&sdev->xs_dev_list, dl); + } + mutex_unlock(lk); + if (ret) + xrt_subdev_destroy(sdev); + } else { + ret = -EINVAL; + } + + ret = ret ? ret : sdev->xs_pdev->id; + return ret; +} + +int xrt_subdev_pool_del(struct xrt_subdev_pool *spool, enum xrt_subdev_id id, int instance) +{ + const struct list_head *ptr; + struct mutex *lk = &spool->xsp_lock; + struct list_head *dl = &spool->xsp_dev_list; + struct xrt_subdev *sdev; + int ret = -ENOENT; + + mutex_lock(lk); + if (spool->xsp_closing) { + /* Pool is going away, all subdevs will be gone. */ + mutex_unlock(lk); + return 0; + } + list_for_each(ptr, dl) { + sdev = list_entry(ptr, struct xrt_subdev, xs_dev_list); + if (sdev->xs_id != id || sdev->xs_pdev->id != instance) + continue; + xrt_subdev_pool_wait_for_holders(spool, sdev); + list_del(&sdev->xs_dev_list); + ret = 0; + break; + } + mutex_unlock(lk); + if (ret) + return ret; + + xrt_subdev_destroy(sdev); + return 0; +} + +static int xrt_subdev_pool_get_impl(struct xrt_subdev_pool *spool, xrt_subdev_match_t match, + void *arg, struct device *holder_dev, struct xrt_subdev **sdevp) +{ + struct platform_device *pdev = (struct platform_device *)arg; + struct list_head *dl = &spool->xsp_dev_list; + struct mutex *lk = &spool->xsp_lock; + struct xrt_subdev *sdev = NULL; + const struct list_head *ptr; + struct xrt_subdev *d = NULL; + int ret = -ENOENT; + + mutex_lock(lk); + + if (!pdev) { + if (match == XRT_SUBDEV_MATCH_PREV) { + sdev = list_empty(dl) ? NULL : + list_last_entry(dl, struct xrt_subdev, xs_dev_list); + } else if (match == XRT_SUBDEV_MATCH_NEXT) { + sdev = list_first_entry_or_null(dl, struct xrt_subdev, xs_dev_list); + } + } + + list_for_each(ptr, dl) { + d = list_entry(ptr, struct xrt_subdev, xs_dev_list); + if (match == XRT_SUBDEV_MATCH_PREV || match == XRT_SUBDEV_MATCH_NEXT) { + if (d->xs_pdev != pdev) + continue; + } else { + if (!match(d->xs_id, d->xs_pdev, arg)) + continue; + } + + if (match == XRT_SUBDEV_MATCH_PREV) + sdev = !list_is_first(ptr, dl) ? list_prev_entry(d, xs_dev_list) : NULL; + else if (match == XRT_SUBDEV_MATCH_NEXT) + sdev = !list_is_last(ptr, dl) ? list_next_entry(d, xs_dev_list) : NULL; + else + sdev = d; + } + + if (sdev) + ret = xrt_subdev_hold(sdev, holder_dev); + + mutex_unlock(lk); + + if (!ret) + *sdevp = sdev; + return ret; +} + +int xrt_subdev_pool_get(struct xrt_subdev_pool *spool, xrt_subdev_match_t match, void *arg, + struct device *holder_dev, struct platform_device **pdevp) +{ + int rc; + struct xrt_subdev *sdev; + + rc = xrt_subdev_pool_get_impl(spool, match, arg, holder_dev, &sdev); + if (rc) { + if (rc != -ENOENT) + dev_err(holder_dev, "failed to hold device: %d", rc); + return rc; + } + + if (!IS_ROOT_DEV(holder_dev)) { + xrt_dbg(to_platform_device(holder_dev), "%s <<==== %s", + dev_name(holder_dev), dev_name(DEV(sdev->xs_pdev))); + } + + *pdevp = sdev->xs_pdev; + return 0; +} + +static int xrt_subdev_pool_put_impl(struct xrt_subdev_pool *spool, struct platform_device *pdev, + struct device *holder_dev) +{ + const struct list_head *ptr; + struct mutex *lk = &spool->xsp_lock; + struct list_head *dl = &spool->xsp_dev_list; + struct xrt_subdev *sdev; + int ret = -ENOENT; + + mutex_lock(lk); + list_for_each(ptr, dl) { + sdev = list_entry(ptr, struct xrt_subdev, xs_dev_list); + if (sdev->xs_pdev != pdev) + continue; + ret = xrt_subdev_release(sdev, holder_dev); + break; + } + mutex_unlock(lk); + + return ret; +} + +int xrt_subdev_pool_put(struct xrt_subdev_pool *spool, struct platform_device *pdev, + struct device *holder_dev) +{ + int ret = xrt_subdev_pool_put_impl(spool, pdev, holder_dev); + + if (ret) + return ret; + + if (!IS_ROOT_DEV(holder_dev)) { + xrt_dbg(to_platform_device(holder_dev), "%s <<==X== %s", + dev_name(holder_dev), dev_name(DEV(pdev))); + } + return 0; +} + +void xrt_subdev_pool_trigger_event(struct xrt_subdev_pool *spool, enum xrt_events e) +{ + struct platform_device *tgt = NULL; + struct xrt_subdev *sdev = NULL; + struct xrt_event evt; + + while (!xrt_subdev_pool_get_impl(spool, XRT_SUBDEV_MATCH_NEXT, + tgt, spool->xsp_owner, &sdev)) { + tgt = sdev->xs_pdev; + evt.xe_evt = e; + evt.xe_subdev.xevt_subdev_id = sdev->xs_id; + evt.xe_subdev.xevt_subdev_instance = tgt->id; + xrt_subdev_root_request(tgt, XRT_ROOT_EVENT_SYNC, &evt); + xrt_subdev_pool_put_impl(spool, tgt, spool->xsp_owner); + } +} + +void xrt_subdev_pool_handle_event(struct xrt_subdev_pool *spool, struct xrt_event *evt) +{ + struct platform_device *tgt = NULL; + struct xrt_subdev *sdev = NULL; + + while (!xrt_subdev_pool_get_impl(spool, XRT_SUBDEV_MATCH_NEXT, + tgt, spool->xsp_owner, &sdev)) { + tgt = sdev->xs_pdev; + xleaf_call(tgt, XRT_XLEAF_EVENT, evt); + xrt_subdev_pool_put_impl(spool, tgt, spool->xsp_owner); + } +} + +ssize_t xrt_subdev_pool_get_holders(struct xrt_subdev_pool *spool, + struct platform_device *pdev, char *buf, size_t len) +{ + const struct list_head *ptr; + struct mutex *lk = &spool->xsp_lock; + struct list_head *dl = &spool->xsp_dev_list; + struct xrt_subdev *sdev; + ssize_t ret = 0; + + mutex_lock(lk); + list_for_each(ptr, dl) { + sdev = list_entry(ptr, struct xrt_subdev, xs_dev_list); + if (sdev->xs_pdev != pdev) + continue; + ret = xrt_subdev_get_holders(sdev, buf, len); + break; + } + mutex_unlock(lk); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_subdev_pool_get_holders); + +int xleaf_broadcast_event(struct platform_device *pdev, enum xrt_events evt, bool async) +{ + struct xrt_event e = { evt, }; + enum xrt_root_cmd cmd = async ? XRT_ROOT_EVENT_ASYNC : XRT_ROOT_EVENT_SYNC; + + WARN_ON(evt == XRT_EVENT_POST_CREATION || evt == XRT_EVENT_PRE_REMOVAL); + return xrt_subdev_root_request(pdev, cmd, &e); +} +EXPORT_SYMBOL_GPL(xleaf_broadcast_event); + +void xleaf_hot_reset(struct platform_device *pdev) +{ + xrt_subdev_root_request(pdev, XRT_ROOT_HOT_RESET, NULL); +} +EXPORT_SYMBOL_GPL(xleaf_hot_reset); + +void xleaf_get_barres(struct platform_device *pdev, struct resource **res, uint bar_idx) +{ + struct xrt_root_get_res arg = { 0 }; + + if (bar_idx > PCI_STD_RESOURCE_END) { + xrt_err(pdev, "Invalid bar idx %d", bar_idx); + *res = NULL; + return; + } + + xrt_subdev_root_request(pdev, XRT_ROOT_GET_RESOURCE, &arg); + + *res = &arg.xpigr_res[bar_idx]; +} + +void xleaf_get_root_id(struct platform_device *pdev, unsigned short *vendor, unsigned short *device, + unsigned short *subvendor, unsigned short *subdevice) +{ + struct xrt_root_get_id id = { 0 }; + + WARN_ON(!vendor && !device && !subvendor && !subdevice); + + xrt_subdev_root_request(pdev, XRT_ROOT_GET_ID, (void *)&id); + if (vendor) + *vendor = id.xpigi_vendor_id; + if (device) + *device = id.xpigi_device_id; + if (subvendor) + *subvendor = id.xpigi_sub_vendor_id; + if (subdevice) + *subdevice = id.xpigi_sub_device_id; +} + +struct device *xleaf_register_hwmon(struct platform_device *pdev, const char *name, void *drvdata, + const struct attribute_group **grps) +{ + struct xrt_root_hwmon hm = { true, name, drvdata, grps, }; + + xrt_subdev_root_request(pdev, XRT_ROOT_HWMON, (void *)&hm); + return hm.xpih_hwmon_dev; +} + +void xleaf_unregister_hwmon(struct platform_device *pdev, struct device *hwmon) +{ + struct xrt_root_hwmon hm = { false, }; + + hm.xpih_hwmon_dev = hwmon; + xrt_subdev_root_request(pdev, XRT_ROOT_HWMON, (void *)&hm); +} From patchwork Wed Mar 24 05:29:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408375 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, URIBL_BLOCKED, 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 26F76C433E1 for ; Wed, 24 Mar 2021 05:35:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D9F7A619E9 for ; Wed, 24 Mar 2021 05:35:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235316AbhCXFe6 (ORCPT ); Wed, 24 Mar 2021 01:34:58 -0400 Received: from mail-co1nam11on2075.outbound.protection.outlook.com ([40.107.220.75]:63232 "EHLO NAM11-CO1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235344AbhCXFel (ORCPT ); Wed, 24 Mar 2021 01:34:41 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=bvPo1qFfJUWtWDXpH7tPNFdIyJ6eAkVAUwwsvoJqL1wEC7y2P4ilUjVNyR0pInSZlDDihkyXVi1Sj2+zb472Ru5dIHiNS64ukFVRWcEtjtAiGVboiaFvgoQTHww9WTz6HJJ8tO+5Si7kgglakcwUV2rvnLf4ak6buW8oGmpi4zKOHOhSDkbx2r3bHfB5gk0B3PE5BmXQQGe8O9SE1RJPYPMqNqenyrNVh1D9V5bZJ+R5ltnBboxEcjfmPYfEKhDpKe7yX99HxoNBE1kZsIMnt6XEmaVwTVn1/Z1pZ2MqbhOyKADfe5MeQLDgCIDACv6mIgtInFCV04JeOOvWfH6qug== 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=YVvxrhC+mGAMXK7kio8dF9YKg6yZ+yzqQO9YpuTFMhc=; b=hsOgamRY6nKC9do/vDcZQn+GgCOKR82HO7W10ErssxawuO81OHAPvdOIHXiV+Ew+tmC8m6iF9yadwXYNnNjRylYBMxBhV9Fh+1qSIpYAgtZS6v1CwrKTm92DRVGr3nPK9a35FHB9e+OfaFmqSgE/7p417EuH2i5Ek2mXfDM3ys4IfPxYR5aABcDKi1sxNj0E+zbTzvEVBjF8MAEWQOeotWWFIRA94smUPdEKV7kKTLxCcCTVO4UCD01IbgbE6u+9o9S5f53+ywMMrUkv961198k97nqvHDir1CrBaFW3o79xIIfK+Nh47M5Z5X2vnnrOKyrV3neflUT9wjVBneRD+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=YVvxrhC+mGAMXK7kio8dF9YKg6yZ+yzqQO9YpuTFMhc=; b=aGBCTL6Kp/Gg91Otld/yX/P02gGG0TkD37j75K/Sw+ak4cOAdebIMxOVx3AkNHVxSP02upKWSCJ8SwJkEuPpbCanKKrh7Ss/75nQaXm0xWzaIBa/FGyl5XBqS+ZCDKON6Z6BZl7Mqk6Afb1t04FXWFa31Bp3zPnGEZuWj0jzkfk= Received: from DM5PR11CA0007.namprd11.prod.outlook.com (2603:10b6:3:115::17) by CY4PR02MB3381.namprd02.prod.outlook.com (2603:10b6:910:7d::35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:34:39 +0000 Received: from DM3NAM02FT007.eop-nam02.prod.protection.outlook.com (2603:10b6:3:115:cafe::3) by DM5PR11CA0007.outlook.office365.com (2603:10b6:3:115::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:34:39 +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 DM3NAM02FT007.mail.protection.outlook.com (10.13.4.88) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3955.24 via Frontend Transport; Wed, 24 Mar 2021 05:34:39 +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.2106.2; Tue, 23 Mar 2021 22:34:10 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:34:10 -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=51038 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOw9i-0004YG-8d; Tue, 23 Mar 2021 22:34:10 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 56AE3600128; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 09/20] fpga: xrt: management physical function driver (root) Date: Tue, 23 Mar 2021 22:29:36 -0700 Message-ID: <20210324052947.27889-10-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 95b26703-d6aa-407f-b341-08d8ee8684a1 X-MS-TrafficTypeDiagnostic: CY4PR02MB3381: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:279; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 9mfXA4/BLgTxa/a9l2ktZ8u2w0NGR0aJ4OB591V/+I8y6CZwyPO0IJ5rQUNbxN5KpBK/QR40A6VwhkA82L9nh6RLY48n5dwJntO2TMw+TsaWIyg/lSgXpXWwogVzeKGWtLjC5fJGJEQuQPD51Oc6UMyADf1eOhrclniZN9hKfooQvgBAhQ65dmUeWnvcK+K211d2cghmIBa/QXhyVJ89aG36cQg4KOlLcgnQXmDOAuEtTm0cuXpcmwXmj2bTFQb5T/OFhzinM17r4rwZbUDI8RNUjr2Zc04S4WrSSDE9lRs717/pEdQCgghOCtYJIpBZghPnD213Esrvzzp5pPBfNn+9zZgi3B+Qb441zz+5BidkPiXB5NKozzFuD7btesf4dcjdbOQWQ8IWZG50u6ILU9e/UvlrWVh4cXJygnCutQY0Qdg9qZATQZrf+apNGA/MuNl0d+vD6JUTOf0HQBkOnxY3UfzeFvD893r38I56hTTxiF92N+2EjYCNGaWWi1/jEFY9SoHTBZsZmpKBzlxrweHZSUx6xM+hSe8cSmZKIjpsN3uq2TMUCx01xHLznbK/BZj7F+9jhUO842ZnKQIExlnpGkFslYWHOt70XFWIefCJOHAsB0PqD821pUlTbW+D1HIivJyz7H6n4XyLLwfM9OShlvfVVOQXW+ThoL/L8LA= 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)(39850400004)(396003)(376002)(346002)(136003)(36840700001)(46966006)(6666004)(2906002)(8936002)(26005)(42186006)(83380400001)(6266002)(82310400003)(44832011)(70206006)(5660300002)(82740400003)(2616005)(426003)(8676002)(6916009)(107886003)(7636003)(316002)(54906003)(36906005)(336012)(4326008)(478600001)(36756003)(186003)(47076005)(70586007)(356005)(1076003)(36860700001); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:34:39.0243 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 95b26703-d6aa-407f-b341-08d8ee8684a1 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: DM3NAM02FT007.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR02MB3381 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 platform drivers. The instantiation of group and platform drivers is completely dtb driven. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/mgmt/root.c | 333 +++++++++++++++++++++++++++++++++++ 1 file changed, 333 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..f97f92807c01 --- /dev/null +++ b/drivers/fpga/xrt/mgmt/root.c @@ -0,0 +1,333 @@ +// 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 "xmgnt.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)); }) + +static struct class *xmgmt_class; + +/* PCI Device IDs */ +#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 > 512) + pcie_set_readrq(pdev, 512); + 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 pci_dev *pdev) +{ + struct xmgmt *xm = pci_get_drvdata(pdev); + struct pci_bus *bus; + u8 pci_bctl; + u16 pci_cmd, devctl; + int i, ret; + + 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, "time'd 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_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 = xroot_add_vsec_node(xm->root, 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 struct xroot_physical_function_callback xmgmt_xroot_pf_cb = { + .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, &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 Mar 24 05:29:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408374 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=-13.9 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, URIBL_BLOCKED, 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 05C9DC433E0 for ; Wed, 24 Mar 2021 05:36:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D3B20619F5 for ; Wed, 24 Mar 2021 05:36:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235368AbhCXFfd (ORCPT ); Wed, 24 Mar 2021 01:35:33 -0400 Received: from mail-mw2nam12on2046.outbound.protection.outlook.com ([40.107.244.46]:42962 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S233036AbhCXFfX (ORCPT ); Wed, 24 Mar 2021 01:35:23 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=XLUG3Ta3d1l4CKoftgDq1LuQCJO2YguIuI+EiQl9hrdm4MmnFNHuq1uSKmzmF6XgyMh1vkUccXsqqdUX42iqK0iUbKmMLlktXK5zrdjVjBl3vRGHSeuVKsYkEFSwoQNQIMhP4uNvoUBTSlPDcy2zKrChDSXEI3HrW/Jwi5EFupHPkASisy0WXW4C8F2U4ci1xAML3z37V4yfigFOJtHQY+wN4J53cyXJg6G4Px9EYAW9804GpDCtRO9kcraD6XG/kyAsyPhNBCWxUKuqpJsZqD/3yfObWKG7gWDRKsfH8cd3dDVlgDEVS83p+PkvtkK/aGsfd8e5IY51IstQWMtK9Q== 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=x5n5rbp52QygWuNPykEhc5q6TGQKwnMy2vr7WcEyRsk=; b=OnM7JHEGHRiSSnBv0yTAYHNL/H+18JxYTzj+m9t6qV3/hPqdm1dhDCVwbsW1F9k4eBWzhYsgr/E8d0JRqA2bKR0a+dHlvDhE76rt++YCe7AAlCHd0jz5dt5/5ko8E4mP1h/tl+pmoh7qUClADAOKgdm/iMB3ZPio4aDXCYR82whdcjNPg2R0DaDsNEo0LJxAy1FmUaRBB68BlheTog0M8ySiN/zqrpnRi5a3A3qW+60/CZSa+EFekWleYST6T+H+C/COEXGHAVTfa6Wpnl0cu0uBqnxu4tmfEQcxOoVqiXk++XAeBJxxQqwT3W1u6DJMHyVNXe9kLFoKk944AUOr8w== 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=x5n5rbp52QygWuNPykEhc5q6TGQKwnMy2vr7WcEyRsk=; b=oqgk+UDLYuDu+FhWnGleN7OATChQ2wY6tfpsdRSKc4PUT7zrvUBYGuCZ7rPJP1e0ExoZ+YcRqMc7Z0SzWNW1d0aedqUEFHpNKbGV0iLgvv6p863N3+ME5QW0VoMxD7fxDkroRM3SasWlvZ+k0EmSSpH1NqAf8/JaBbNheMw+5SA= Received: from DM6PR06CA0022.namprd06.prod.outlook.com (2603:10b6:5:120::35) by MN2PR02MB6832.namprd02.prod.outlook.com (2603:10b6:208:1d8::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18; Wed, 24 Mar 2021 05:35:20 +0000 Received: from DM3NAM02FT025.eop-nam02.prod.protection.outlook.com (2603:10b6:5:120:cafe::18) by DM6PR06CA0022.outlook.office365.com (2603:10b6:5:120::35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.18 via Frontend Transport; Wed, 24 Mar 2021 05:35: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-pvapexch01.xlnx.xilinx.com; Received: from xsj-pvapexch01.xlnx.xilinx.com (149.199.62.198) by DM3NAM02FT025.mail.protection.outlook.com (10.13.4.112) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:35:20 +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.2106.2; Tue, 23 Mar 2021 22:34:46 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:34:46 -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=51044 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOwAI-00061W-L3; Tue, 23 Mar 2021 22:34:46 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 94D0260012A; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 12/20] fpga: xrt: VSEC platform driver Date: Tue, 23 Mar 2021 22:29:39 -0700 Message-ID: <20210324052947.27889-13-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 3435a9ef-7ac6-4430-69a2-08d8ee869d59 X-MS-TrafficTypeDiagnostic: MN2PR02MB6832: 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: be9SF4LaFtXF68EmpUWBoHf7wRMTEN4+sPDuUpMYEdSZtAD1wKB1k30UWk135ToiBplLDhoGSqdgScW4m9AV3GNpicI6C/kB03jscXj8RE2ry4aT/XG7oHUKYK+VcmvS4vJsA0AE7Jac/S0OokbMxpNkJMTtl+lkeZgqTvJgthW8a5iN4m4G/TWxI3WyXQK/01IhuJSboh5Ic6CGFez1GCrP4UfHHB/72em2/UiKCgyKO7F98RDlpleLfO4qC8kbgNi8q2UUka6hOLeb9Rk7CCpwkoFrSjJdV5f2wx9lU1I4LUUQ76gnlWA13Ry3GPgXc5F2QTcR7GS/fOIENAkFEZKNU3TLGGDhoTg7+MF+08rNlZVSIgYe3pmsuufmwlrVzeTeh/N8dgE7lq7KSuG8zRpvrIgxBOjdaUQ4j6Mtzt1EaRnfxo+mmrxLsm38nGhvnJzoCqaK3ktXVf+iymUL4jvcJuDud+F42g+hLUhRMqp6amAd1mBwhxU97Z1gNeo1gkMBZ20rpDp+2VGPtp/vDJzs1ysx4ncu8U4ZPPr/4GY2tj9cUKU0tt0aoFnv89dmWbacYwiuZsllKH2HOYA6EfYvpOcp/KFMB/WjHGVSjFre+gICtinH8nCKgqkkdzioosTcU8h9MXiy+CG+T42xTKcWytrZlabf/bE5omiDKvs= 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)(4326008)(2906002)(8676002)(36860700001)(6266002)(356005)(47076005)(82310400003)(478600001)(42186006)(54906003)(36906005)(316002)(83380400001)(186003)(1076003)(336012)(5660300002)(44832011)(36756003)(426003)(70586007)(2616005)(82740400003)(6916009)(8936002)(26005)(70206006)(107886003)(6666004)(7636003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:35:20.4946 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3435a9ef-7ac6-4430-69a2-08d8ee869d59 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: DM3NAM02FT025.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR02MB6832 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 platform 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 --- drivers/fpga/xrt/lib/xleaf/vsec.c | 388 ++++++++++++++++++++++++++++++ 1 file changed, 388 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..8595d23f5710 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/vsec.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA VSEC Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#include +#include +#include "metadata.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 *regmap; +}; + +static struct vsec_device vsec_devs[] = { + { + .type = VSEC_TYPE_UUID, + .ep_name = XRT_MD_NODE_BLP_ROM, + .size = VSEC_UUID_LEN, + .regmap = "vsec-uuid", + }, + { + .type = VSEC_TYPE_FLASH, + .ep_name = XRT_MD_NODE_FLASH_VSEC, + .size = 4096, + .regmap = "vsec-flash", + }, + { + .type = VSEC_TYPE_PLATINFO, + .ep_name = XRT_MD_NODE_PLAT_INFO, + .size = 4, + .regmap = "vsec-platinfo", + }, + { + .type = VSEC_TYPE_MAILBOX, + .ep_name = XRT_MD_NODE_MAILBOX_VSEC, + .size = 48, + .regmap = "vsec-mbx", + }, +}; + +static const struct regmap_config vsec_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x1000, +}; + +struct xrt_vsec { + struct platform_device *pdev; + 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 *type2regmap(u32 type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vsec_devs); i++) { + if (vsec_devs[i].type == type) + return (vsec_devs[i].regmap); + } + + 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 regmap_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(regmap_ver, sizeof(regmap_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 = vsec_get_bar(p_entry); + ep.bar_off = vsec_get_bar_off(p_entry); + ep.size = type2size(p_entry->type); + ep.regmap = type2regmap(p_entry->type); + ep.regmap_ver = regmap_ver; + ret = xrt_md_add_endpoint(DEV(vsec->pdev), vsec->metadata, &ep); + if (ret) + xrt_err(vsec->pdev, "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->pdev->dev, &vsec->metadata); + if (ret) { + xrt_err(vsec->pdev, "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->pdev, "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 platform_device *pdev, u32 cmd, void *arg) +{ + int ret = 0; + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + default: + ret = -EINVAL; + xrt_err(pdev, "should never been called"); + break; + } + + return ret; +} + +static int xrt_vsec_mapio(struct xrt_vsec *vsec) +{ + struct xrt_subdev_platdata *pdata = DEV_PDATA(vsec->pdev); + struct resource *res = NULL; + void __iomem *base = NULL; + const u64 *bar_off; + const u32 *bar; + u64 addr; + int ret; + + if (!pdata || xrt_md_size(DEV(vsec->pdev), pdata->xsp_dtb) == XRT_MD_INVALID_LENGTH) { + xrt_err(vsec->pdev, "empty metadata"); + return -EINVAL; + } + + ret = xrt_md_get_prop(DEV(vsec->pdev), pdata->xsp_dtb, XRT_MD_NODE_VSEC, + NULL, XRT_MD_PROP_BAR_IDX, (const void **)&bar, NULL); + if (ret) { + xrt_err(vsec->pdev, "failed to get bar idx, ret %d", ret); + return -EINVAL; + } + + ret = xrt_md_get_prop(DEV(vsec->pdev), pdata->xsp_dtb, XRT_MD_NODE_VSEC, + NULL, XRT_MD_PROP_OFFSET, (const void **)&bar_off, NULL); + if (ret) { + xrt_err(vsec->pdev, "failed to get bar off, ret %d", ret); + return -EINVAL; + } + + xrt_info(vsec->pdev, "Map vsec at bar %d, offset 0x%llx", + be32_to_cpu(*bar), be64_to_cpu(*bar_off)); + + xleaf_get_barres(vsec->pdev, &res, be32_to_cpu(*bar)); + if (!res) { + xrt_err(vsec->pdev, "failed to get bar addr"); + return -EINVAL; + } + + addr = res->start + be64_to_cpu(*bar_off); + + base = devm_ioremap(&vsec->pdev->dev, addr, vsec_regmap_config.max_register); + if (!base) { + xrt_err(vsec->pdev, "Map failed"); + return -EIO; + } + + vsec->regmap = devm_regmap_init_mmio(&vsec->pdev->dev, base, &vsec_regmap_config); + if (IS_ERR(vsec->regmap)) { + xrt_err(vsec->pdev, "regmap %pR failed", res); + return PTR_ERR(vsec->regmap); + } + + ret = regmap_read(vsec->regmap, VSEC_REG_LENGTH, &vsec->length); + if (ret) { + xrt_err(vsec->pdev, "failed to read length %d", ret); + return ret; + } + + return 0; +} + +static int xrt_vsec_remove(struct platform_device *pdev) +{ + struct xrt_vsec *vsec; + + vsec = platform_get_drvdata(pdev); + + if (vsec->group >= 0) + xleaf_destroy_group(pdev, vsec->group); + vfree(vsec->metadata); + + return 0; +} + +static int xrt_vsec_probe(struct platform_device *pdev) +{ + struct xrt_vsec *vsec; + int ret = 0; + + vsec = devm_kzalloc(&pdev->dev, sizeof(*vsec), GFP_KERNEL); + if (!vsec) + return -ENOMEM; + + vsec->pdev = pdev; + vsec->group = -1; + platform_set_drvdata(pdev, vsec); + + ret = xrt_vsec_mapio(vsec); + if (ret) + goto failed; + + ret = xrt_vsec_create_metadata(vsec); + if (ret) { + xrt_err(pdev, "create metadata failed, ret %d", ret); + goto failed; + } + vsec->group = xleaf_create_group(pdev, vsec->metadata); + if (ret < 0) { + xrt_err(pdev, "create group failed, ret %d", vsec->group); + ret = vsec->group; + goto failed; + } + + return 0; + +failed: + xrt_vsec_remove(pdev); + + return ret; +} + +static struct xrt_subdev_endpoints xrt_vsec_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names []){ + { .ep_name = XRT_MD_NODE_VSEC }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_subdev_drvdata xrt_vsec_data = { + .xsd_dev_ops = { + .xsd_leaf_call = xrt_vsec_leaf_call, + }, +}; + +static const struct platform_device_id xrt_vsec_table[] = { + { XRT_VSEC, (kernel_ulong_t)&xrt_vsec_data }, + { }, +}; + +static struct platform_driver xrt_vsec_driver = { + .driver = { + .name = XRT_VSEC, + }, + .probe = xrt_vsec_probe, + .remove = xrt_vsec_remove, + .id_table = xrt_vsec_table, +}; + +XRT_LEAF_INIT_FINI_FUNC(XRT_SUBDEV_VSEC, vsec); From patchwork Wed Mar 24 05:29:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408373 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, URIBL_BLOCKED, 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 27295C433E3 for ; Wed, 24 Mar 2021 05:36:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0F59E619FF for ; Wed, 24 Mar 2021 05:36:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235390AbhCXFgD (ORCPT ); Wed, 24 Mar 2021 01:36:03 -0400 Received: from mail-dm6nam12on2050.outbound.protection.outlook.com ([40.107.243.50]:8160 "EHLO NAM12-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235379AbhCXFfk (ORCPT ); Wed, 24 Mar 2021 01:35:40 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=L6zFI6oxmNBmgBj8T47TAj2zcGxkwLeiX7qiRUpeeUCtHb02uJqYJNENT/E3BJlDC4146JCMhPXYKGwMCGBqaVCEbmEnM/Wb90a1gdKhiIl+UUZiVdMo+64iZFT412OddhavPOtJXMpw0ljBFy3k7BBlbW1ySWNGnSF3w5GPRurV8vvunlLCzl40p1TB37GEaG6ILv0RWjHO7G+tSnMYDy4fUo/arkdc2VeQmDUpqI6Xi8E9pij5MtPcvZwt3sJ0j1Z9rItw9mRVv7oCcJZlEVQh1riPila82yXivZpKqpWUzpJNNreGMTs3h5nWv1mPLOuMzvyGI7fZVqsIlPXLrw== 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=b5Ba4iu7iZfkE5iNCC+snAUjNesqB3Fql7ghLqiBIi8=; b=XKp4r+HDnZhQmRDpj70KXf3oGjuAiEk3udlKFeLlBrCXYqySyU4ro4UVVVnnDm9ogGHhbf6HKtLN7psignU/ch4qOn7XwGNpIl/3erDwLZx6KPtTpLZU2/TKP/egEQLu2ux8JxAcH0QASNg193DeAMIqpYiI3E4dNSo7djf1wkwTQXW1CLRmH1CEewpDirzLR4UH+RUB/d3YQuyKgGpTTyEz4EQx9pb6SP4+HtxAyYGmd17THvsG7cX+F60LQwSSEyFOZ85jcGlAtSi8plSra9Rkszm68v7afuDxxLoX41pORmIBDUlKZm/1zpkTboPwxEbjfnCYGWa9m083sSzeag== 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=b5Ba4iu7iZfkE5iNCC+snAUjNesqB3Fql7ghLqiBIi8=; b=BcDEbM/B1bzSDbo1QjIkI0+hA33GYV/FSLU+qu3CKVTBAep00Pyt/hV0mDsXVzCP4kMVc3mZ15NMx2Jlv65QQoQzR28FqcLizSMruiIlY26Dmas/pFoQmxGRUBmit88/1+kUSRtF0083+slw2NGxnL7VdZNxGMvMYnkOhc4mTOE= Received: from SA0PR11CA0191.namprd11.prod.outlook.com (2603:10b6:806:1bc::16) by SN6PR02MB4639.namprd02.prod.outlook.com (2603:10b6:805:ab::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24; Wed, 24 Mar 2021 05:35:38 +0000 Received: from SN1NAM02FT032.eop-nam02.prod.protection.outlook.com (2603:10b6:806:1bc:cafe::5e) by SA0PR11CA0191.outlook.office365.com (2603:10b6:806:1bc::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:35:38 +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 SN1NAM02FT032.mail.protection.outlook.com (10.152.72.126) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:35:38 +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.2106.2; Tue, 23 Mar 2021 22:35:22 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:35:22 -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=51050 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOwAs-0004eh-PN; Tue, 23 Mar 2021 22:35:22 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id D189860012E; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 15/20] fpga: xrt: devctl platform driver Date: Tue, 23 Mar 2021 22:29:42 -0700 Message-ID: <20210324052947.27889-16-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 8f853db6-89fc-4abe-3c9b-08d8ee86a815 X-MS-TrafficTypeDiagnostic: SN6PR02MB4639: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:765; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: vOYsH9qASyRfvUnsNPAyOZuMBw26EBWXh0gr5FslLFSrIKo8IIuYJartdhr91zFBku8eY6Nd0lPwY3qSLlI1xI5HkSj+D11UMWdk1UUvGHxjCTLGyxXnATZ9/Ef2/jnb4OF2Hsk7xWYdC4+LzELJbW90mLeIR0XDLmEQi9S/L9Ic22B67SeL0z81Zp13v37i76tKqebOCX1xpHOrYjsSBRHUWBEUj6B1k6KKB1OkhdSUweqdyia4qlBacZY1KhPttzgj6Wg7txEs/S8dlVRRK+8EBEA0pJNK8eAQ12ScEdFwIo3Nbi6eACiQNC8LOOYZDAo3am+1IRkJiDLuLgIrJrqwX+B3X9hG3/v8jkXxxfetur37+in4BByvXt9h/Lnfx53q+1hT1yBp2NPN1AH9CdjjbZcCY71bbP8jZ5hLlhgcIitX5Ve8bNHVnoCYnkQsfFvFdC4RsJfXLUBda5TFO7Aa4mtI+arQJ9uvaBurFDzZqLOGqT/+Au+tWuKwsmc8IWbxXlFKL+gd/2SqpSe2jW9EHobcTR6yMWKq4+yBiNITlOAExMeHU+PX+wsEtMbs7E4nAedf8tgweEiH+3/lmrmxAOUshO9km8RMs3feSY/DYrLuBbQPczhYaj/ms4n0OdpfjpNzHzDfPXs+dmJAXOn7LKQ/wVWm9Ts4ShcPyhA= 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)(39860400002)(346002)(136003)(396003)(376002)(36840700001)(46966006)(36860700001)(1076003)(8676002)(4326008)(8936002)(6666004)(426003)(2616005)(7636003)(107886003)(336012)(6916009)(6266002)(36906005)(82310400003)(36756003)(42186006)(186003)(5660300002)(478600001)(316002)(70586007)(356005)(2906002)(44832011)(47076005)(26005)(70206006)(54906003)(82740400003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:35:38.5114 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 8f853db6-89fc-4abe-3c9b-08d8ee86a815 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: SN1NAM02FT032.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR02MB4639 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add devctl driver. devctl is a type of hardware function which only has few registers to read or write. They are discovered by walking firmware metadata. A platform device node will be created for them. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou Reviewed-by: Tom Rix --- drivers/fpga/xrt/include/xleaf/devctl.h | 40 ++++++ drivers/fpga/xrt/lib/xleaf/devctl.c | 183 ++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/devctl.h create mode 100644 drivers/fpga/xrt/lib/xleaf/devctl.c diff --git a/drivers/fpga/xrt/include/xleaf/devctl.h b/drivers/fpga/xrt/include/xleaf/devctl.h new file mode 100644 index 000000000000..b97f3b6d9326 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/devctl.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_DEVCTL_H_ +#define _XRT_DEVCTL_H_ + +#include "xleaf.h" + +/* + * DEVCTL driver leaf calls. + */ +enum xrt_devctl_leaf_cmd { + XRT_DEVCTL_READ = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ +}; + +enum xrt_devctl_id { + XRT_DEVCTL_ROM_UUID = 0, + XRT_DEVCTL_DDR_CALIB, + XRT_DEVCTL_GOLDEN_VER, + XRT_DEVCTL_MAX +}; + +struct xrt_devctl_rw { + u32 xdr_id; + void *xdr_buf; + u32 xdr_len; + u32 xdr_offset; +}; + +struct xrt_devctl_intf_uuid { + u32 uuid_num; + uuid_t *uuids; +}; + +#endif /* _XRT_DEVCTL_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/devctl.c b/drivers/fpga/xrt/lib/xleaf/devctl.c new file mode 100644 index 000000000000..ae086d7c431d --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/devctl.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA devctl Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#include +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/devctl.h" + +#define XRT_DEVCTL "xrt_devctl" + +struct xrt_name_id { + char *ep_name; + int id; +}; + +static struct xrt_name_id name_id[XRT_DEVCTL_MAX] = { + { XRT_MD_NODE_BLP_ROM, XRT_DEVCTL_ROM_UUID }, + { XRT_MD_NODE_GOLDEN_VER, XRT_DEVCTL_GOLDEN_VER }, +}; + +static const struct regmap_config devctl_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +struct xrt_devctl { + struct platform_device *pdev; + struct regmap *regmap[XRT_DEVCTL_MAX]; + ulong sizes[XRT_DEVCTL_MAX]; +}; + +static int xrt_devctl_name2id(struct xrt_devctl *devctl, const char *name) +{ + int i; + + for (i = 0; i < XRT_DEVCTL_MAX && name_id[i].ep_name; i++) { + if (!strncmp(name_id[i].ep_name, name, strlen(name_id[i].ep_name) + 1)) + return name_id[i].id; + } + + return -EINVAL; +} + +static int +xrt_devctl_leaf_call(struct platform_device *pdev, u32 cmd, void *arg) +{ + struct xrt_devctl *devctl; + int ret = 0; + + devctl = platform_get_drvdata(pdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + case XRT_DEVCTL_READ: { + struct xrt_devctl_rw *rw_arg = arg; + + if (rw_arg->xdr_len & 0x3) { + xrt_err(pdev, "invalid len %d", rw_arg->xdr_len); + return -EINVAL; + } + + if (rw_arg->xdr_id >= XRT_DEVCTL_MAX) { + xrt_err(pdev, "invalid id %d", rw_arg->xdr_id); + return -EINVAL; + } + + if (!devctl->regmap[rw_arg->xdr_id]) { + xrt_err(pdev, "io not found, id %d", + rw_arg->xdr_id); + return -EINVAL; + } + + ret = regmap_bulk_read(devctl->regmap[rw_arg->xdr_id], rw_arg->xdr_offset, + rw_arg->xdr_buf, + rw_arg->xdr_len / devctl_regmap_config.reg_stride); + break; + } + default: + xrt_err(pdev, "unsupported cmd %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int xrt_devctl_probe(struct platform_device *pdev) +{ + struct xrt_devctl *devctl = NULL; + void __iomem *base = NULL; + struct resource *res; + int i, id, ret = 0; + + devctl = devm_kzalloc(&pdev->dev, sizeof(*devctl), GFP_KERNEL); + if (!devctl) + return -ENOMEM; + + devctl->pdev = pdev; + platform_set_drvdata(pdev, devctl); + + xrt_info(pdev, "probing..."); + for (i = 0, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res; + res = platform_get_resource(pdev, IORESOURCE_MEM, ++i)) { + struct regmap_config config = devctl_regmap_config; + + id = xrt_devctl_name2id(devctl, res->name); + if (id < 0) { + xrt_err(pdev, "ep %s not found", res->name); + continue; + } + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + break; + } + config.max_register = res->end - res->start + 1; + devctl->regmap[id] = devm_regmap_init_mmio(&pdev->dev, base, &config); + if (IS_ERR(devctl->regmap[id])) { + xrt_err(pdev, "map base failed %pR", res); + ret = PTR_ERR(devctl->regmap[id]); + break; + } + devctl->sizes[id] = res->end - res->start + 1; + } + + return ret; +} + +static struct xrt_subdev_endpoints xrt_devctl_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names[]) { + /* add name if ep is in same partition */ + { .ep_name = XRT_MD_NODE_BLP_ROM }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { + .xse_names = (struct xrt_subdev_ep_names[]) { + { .ep_name = XRT_MD_NODE_GOLDEN_VER }, + { NULL }, + }, + .xse_min_ep = 1, + }, + /* adding ep bundle generates devctl device instance */ + { 0 }, +}; + +static struct xrt_subdev_drvdata xrt_devctl_data = { + .xsd_dev_ops = { + .xsd_leaf_call = xrt_devctl_leaf_call, + }, +}; + +static const struct platform_device_id xrt_devctl_table[] = { + { XRT_DEVCTL, (kernel_ulong_t)&xrt_devctl_data }, + { }, +}; + +static struct platform_driver xrt_devctl_driver = { + .driver = { + .name = XRT_DEVCTL, + }, + .probe = xrt_devctl_probe, + .id_table = xrt_devctl_table, +}; + +XRT_LEAF_INIT_FINI_FUNC(XRT_SUBDEV_DEVCTL, devctl); From patchwork Wed Mar 24 05:29:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408372 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, URIBL_BLOCKED, 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 567E6C433E8 for ; Wed, 24 Mar 2021 05:36:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 37DBF619FF for ; Wed, 24 Mar 2021 05:36:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235391AbhCXFgE (ORCPT ); Wed, 24 Mar 2021 01:36:04 -0400 Received: from mail-mw2nam10on2067.outbound.protection.outlook.com ([40.107.94.67]:62945 "EHLO NAM10-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235384AbhCXFfs (ORCPT ); Wed, 24 Mar 2021 01:35:48 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GKuB+E9dVNRzewhm4W9AUKOl7q6GVXp6dV/PI5rAw9rjXmX8rjL3qKzTQBjWdqjdAtzmtGgUz1n4SQZf4WS4jUOlL/xBvOz80ThvetS/Eb7FRWVQDfZFUoritgiXAJ5E2rQ4pvapeG/yylgr8CdwHQ8UNE6YjRj+AS+GftRoKTwqpr/+qX9KEShOFjz8oPkzkUEYigtjL2FRrnMi9GHKRxOTUDP2AL6AIAiMNNRzMLukbMenbU1TfBEYuXiDnDWmxQDFqgo6k8HcwiJVuiKXwlgWCRB3FHyTr7K4IMlvWVWA9kvsVHlO1fknZM22G139n5M9iiJFnyOEggrKnjPHeA== 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=oYi8b3/1dyQ2xmsfv6IEN2O3BXcNBovu/jEK8G3VIcI=; b=USDCu9zg5M7HMVpl/u1kyolD4nfKr52gvboFFabTzIZd3rzZNBw573sSPHO7rTDGwc4PaOAREd+AKLGbLtKSGIvC9rEoRincDCYPGJ62euJpqRwhQoFucMaK4oA2TGWL96+UqItXLJ/Uvw7Jkh2xmeKWxwBRMM86i5No2/QhRXLlwOa7T08BTlDhxiREy0oejrBNJMSULMZ7O8ey3QnR2hjHht7JTf5/sQoA/xxC3yM2dIYfMHI7aosx2CJM+35fCURZNogWkOGa3Mhf8rPiVjPxAKZCdq2eeAm0L1vb7EK9eZHEUZS8mCJ5SftvhxJoj/wtLy0ZfT8GirQUs1QDbQ== 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=oYi8b3/1dyQ2xmsfv6IEN2O3BXcNBovu/jEK8G3VIcI=; b=id990VqI4Q3+JtB+UEZsT9+H0lrE4WfV4iSrRk0jR0DY0sJwDu3ZEFC34PDC8aLgNsWlpgW8DATldaH+A88CGSnnTHl1u810duV6dYVjHRNWAXbEh7MqjLXy7mh2S1sscsa4NjL/R9YQa1kzZM2/mwQ2gblwplr+60/YIVHsDs8= Received: from DS7PR03CA0040.namprd03.prod.outlook.com (2603:10b6:5:3b5::15) by SN6PR02MB4608.namprd02.prod.outlook.com (2603:10b6:805:a6::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24; Wed, 24 Mar 2021 05:35:46 +0000 Received: from DM3NAM02FT059.eop-nam02.prod.protection.outlook.com (2603:10b6:5:3b5:cafe::d9) by DS7PR03CA0040.outlook.office365.com (2603:10b6:5:3b5::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:35:45 +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 DM3NAM02FT059.mail.protection.outlook.com (10.13.4.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:35:45 +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.2106.2; Tue, 23 Mar 2021 22:35:34 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:35:34 -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=51052 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOwB4-0006DN-Qz; Tue, 23 Mar 2021 22:35:34 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id EDC5460012F; Tue, 23 Mar 2021 22:29:56 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 16/20] fpga: xrt: clock platform driver Date: Tue, 23 Mar 2021 22:29:43 -0700 Message-ID: <20210324052947.27889-17-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 11af8496-c0b8-47a3-03a5-08d8ee86ac5c X-MS-TrafficTypeDiagnostic: SN6PR02MB4608: 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: 2dwLOpBVHzSehsRGnq4SySpxK9Yn0rh5/GgECntxAGvP6X8CGuio68njcv9A93bdL6mQpz68oq5pzkFqVjeOCkHrSnZbhbDsAGZUwho/EUuYgc2kG3Dr6808pyr1n9QEFVcVXP5cVDg34iPLU0sztzJFkEqFkJsVsB/VgM+5P7IetWxuCksD/7WXnUayWxORvb8TKYoXQ4aT/8fBZisCK+51pj/CPwUGAGIVCKP9FGpOZh8ymq+VL0k6DSalDukVccqQiT0VorDk1c7l0UFqQ1tjGzMM28jTrJRuG38TRZelCFACEQAGrSsT3zvaeX7U3x32/Ggu+ouHWh3CRHxU5Tg/Uod4ZF6QxbQJMT7iDmk3HeLYFIHj7XqwD1wXYYT9jfC4jwKhO5c5aytvQv847JK01Yg+cYm17dhg+1vbQU8F0Xzx3DzbeCXcya9srf1SXNnWLocRdpGUH8fBgJT4kEBZpXI4pZoHq4wUocL/a1H5P2HXTLgsRpl2Ykg8GfgNHFr3L5DAsQJyLjsK664Srp/xuOyfRIIcQYlZLpuJ6+RSvsvqEPRfmlPMP59t7KpVFwGZhQCuSpgtKcfZQ9vOW7QczIBrOCAxx3SC0AMqT5oiqbterqa5CNpf98RJEdgj5cpotzk2IjJFk+2Yyvkfpm0QplSshG2OwQ+75x2Cx3k= 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)(39860400002)(396003)(136003)(376002)(346002)(46966006)(36840700001)(1076003)(426003)(316002)(36906005)(6916009)(6666004)(54906003)(336012)(356005)(47076005)(186003)(4326008)(44832011)(42186006)(26005)(36860700001)(2906002)(8676002)(107886003)(82740400003)(82310400003)(5660300002)(478600001)(30864003)(2616005)(83380400001)(7636003)(36756003)(70206006)(6266002)(8936002)(70586007); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:35:45.6765 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 11af8496-c0b8-47a3-03a5-08d8ee86ac5c 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: DM3NAM02FT059.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR02MB4608 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 platform 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 | 669 +++++++++++++++++++++++++ 2 files changed, 698 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..071485e4bf65 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/clock.c @@ -0,0 +1,669 @@ +// 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 +#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)->pdev, fmt "\n", ##arg) +#define CLOCK_WARN(clock, fmt, arg...) \ + xrt_warn((clock)->pdev, fmt "\n", ##arg) +#define CLOCK_INFO(clock, fmt, arg...) \ + xrt_info((clock)->pdev, fmt "\n", ##arg) +#define CLOCK_DBG(clock, fmt, arg...) \ + xrt_dbg((clock)->pdev, fmt "\n", ##arg) + +#define XRT_CLOCK "xrt_clock" + +static const struct regmap_config clock_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x1000, +}; + +struct clock { + struct platform_device *pdev; + 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->pdev); + struct platform_device *pdev = clock->pdev; + struct platform_device *counter_leaf; + const void *counter; + int err; + + WARN_ON(!mutex_is_locked(&clock->clock_lock)); + + err = xrt_md_get_prop(DEV(pdev), pdata->xsp_dtb, clock->clock_ep_name, + NULL, XRT_MD_PROP_CLK_CNT, &counter, NULL); + if (err) { + xrt_err(pdev, "no counter specified"); + return err; + } + + counter_leaf = xleaf_get_leaf_by_epname(pdev, counter); + if (!counter_leaf) { + xrt_err(pdev, "can't find counter"); + return -ENOENT; + } + + err = xleaf_call(counter_leaf, XRT_CLKFREQ_READ, freq); + if (err) + xrt_err(pdev, "can't read counter"); + xleaf_put_leaf(clock->pdev, 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->pdev, "get freq failed, %d", err); + goto end; + } + + err = get_freq_counter(clock, &clock_freq_counter); + if (err) { + xrt_err(clock->pdev, "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->pdev); + const u16 *freq; + int err = 0; + + err = xrt_md_get_prop(DEV(clock->pdev), pdata->xsp_dtb, + clock->clock_ep_name, NULL, XRT_MD_PROP_CLK_FREQ, + (const void **)&freq, NULL); + if (err) { + xrt_info(clock->pdev, "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 = platform_get_drvdata(to_platform_device(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 platform_device *pdev, u32 cmd, void *arg) +{ + struct clock *clock; + int ret = 0; + + clock = platform_get_drvdata(pdev); + + 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(pdev, "unsupported cmd %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int clock_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &clock_attr_group); + + return 0; +} + +static int clock_probe(struct platform_device *pdev) +{ + struct clock *clock = NULL; + void __iomem *base = NULL; + struct resource *res; + int ret; + + clock = devm_kzalloc(&pdev->dev, sizeof(*clock), GFP_KERNEL); + if (!clock) + return -ENOMEM; + + platform_set_drvdata(pdev, clock); + clock->pdev = pdev; + mutex_init(&clock->clock_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -EINVAL; + goto failed; + } + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto failed; + } + + clock->regmap = devm_regmap_init_mmio(&pdev->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(&pdev->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_subdev_endpoints xrt_clock_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names[]) { + { .regmap_name = "clkwiz" }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_subdev_drvdata xrt_clock_data = { + .xsd_dev_ops = { + .xsd_leaf_call = xrt_clock_leaf_call, + }, +}; + +static const struct platform_device_id xrt_clock_table[] = { + { XRT_CLOCK, (kernel_ulong_t)&xrt_clock_data }, + { }, +}; + +static struct platform_driver xrt_clock_driver = { + .driver = { + .name = XRT_CLOCK, + }, + .probe = clock_probe, + .remove = clock_remove, + .id_table = xrt_clock_table, +}; + +XRT_LEAF_INIT_FINI_FUNC(XRT_SUBDEV_CLOCK, clock); From patchwork Wed Mar 24 05:29:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408371 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, URIBL_BLOCKED, 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 6D598C433DB for ; Wed, 24 Mar 2021 05:37:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3A982619F2 for ; Wed, 24 Mar 2021 05:37:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235401AbhCXFgf (ORCPT ); Wed, 24 Mar 2021 01:36:35 -0400 Received: from mail-bn7nam10on2067.outbound.protection.outlook.com ([40.107.92.67]:54048 "EHLO NAM10-BN7-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235384AbhCXFgP (ORCPT ); Wed, 24 Mar 2021 01:36:15 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=e7leXaE6dDEvoz35dhYNf8gyhltBnB0U8/XeDcZYvsEVK5Top6u3AvhDFEyrk4NDCD+CyTCP7pdvEd0cmLJSsKyqMxg5lcuui8pHwmu/GBIPKLTBKEjX94M72KJwOgHGlpk3+oFtgNPdpl23otXcNvuxupyyziFFHvPnRdDMEGsWcreAj2SRcwStu0+dRNrDoOZsran11XnnTsHG6iwv+Nht1k3cYLM14n8PR68HqR5+ZSOF4dxbjcN48Za81DXJioYd2rsJnr/DM/GwZIu5JRacNlF1GQm+rmt+TOXoLj2Q4quqR3/fdkDZt5gPnkDyeEblzqLVFh88/VQKUQFNlg== 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=LFs1DgjJ1rWAX5buzhQU/q+oc9wU60jE4oTon4ZSEZs=; b=C3eh83ZLeGRr75yjECPe2KS5SfRED/QLUSsVokVaK76kUiLWGqT1x/5qxJA+UFkL2GIkymU5LfKU9iCTPXKomogGyXaM95Oj7B7tjK3HXrIL2yC0P8kr/K1/Q1IW+KzigWclMVWhnKSxQxOTPfEnJdDo0RRQWUtrvuyO37OTpcTJnCVOuD3mOZj4uACxzRX9bO2TknVkOLJZZtcGKxVqhQigVn0Z3MZK358kniTTYdibKoBSmn32Msol0yg51jfZWfRvhKSj2PAm5mo+eC/1mP5kimn27HsdDdsFO1eibRVEmr8zOXcBzEa8qrsx9ZJH9O9EP8OL4EN0kkKWbHNhOA== 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=LFs1DgjJ1rWAX5buzhQU/q+oc9wU60jE4oTon4ZSEZs=; b=KvKa+YJ3GpLnP6A+kLnXegjieJNN3g4qFgZWqPtYc5gGrkl3Ql7if3kmdxRjpqoB6fYPziX+ofWdJppWLvGF0LAWkVq3IbJhpsRaJF43IN9UE+eW78PclVvdR0CwtiJMAap7bpHYaPBhQjuQV5NE009j85Cqgi638+AATT/YkTc= Received: from SN4PR0401CA0031.namprd04.prod.outlook.com (2603:10b6:803:2a::17) by BL0PR02MB6546.namprd02.prod.outlook.com (2603:10b6:208:1cc::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.23; Wed, 24 Mar 2021 05:36:13 +0000 Received: from SN1NAM02FT064.eop-nam02.prod.protection.outlook.com (2603:10b6:803:2a:cafe::4c) by SN4PR0401CA0031.outlook.office365.com (2603:10b6:803:2a::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:36:13 +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 SN1NAM02FT064.mail.protection.outlook.com (10.152.72.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3955.24 via Frontend Transport; Wed, 24 Mar 2021 05:36:13 +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.2106.2; Tue, 23 Mar 2021 22:35:59 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:35:59 -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=51056 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOwBS-0006Er-UF; Tue, 23 Mar 2021 22:35:58 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 2C67E600132; Tue, 23 Mar 2021 22:29:57 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 18/20] fpga: xrt: DDR calibration platform driver Date: Tue, 23 Mar 2021 22:29:45 -0700 Message-ID: <20210324052947.27889-19-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: db1a0881-a47a-43d5-2754-08d8ee86bccb X-MS-TrafficTypeDiagnostic: BL0PR02MB6546: 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: E0anDwwQCxrU9dJ9Qufv+ILADasuJnuw2UfxMgTeWe4VE3ixcMadNRjXyMGl0Mhj7rA3hMliPS3tBOp3Jfzhh2eP4gZFjnE0Ze7Nh/y6935l/NdF5BWKCHNn1ZXOL6jJtkNYW9VAF5EMZV2J9CO4hLZ3yasPMjbeGo9l4SdQz3vC9KtanCBWuYPrK/t9R8Pcnicp5nFbjawEQMuX6S/KDgY0AKT1gYwrPss/JObE7xG5OQxMQbsEIsypNdEmCz8NSQf2xFNhp6HdiZ2rMBhAcbGpIZmzv11ynZaU2T29CSjhhMFteVB+m4Xb3P/fgzc9ffxs2+Sr0My/kWUNTWGuHiYE0bzawImZ16AjIXsSwHrFDSV8bGLIULLq+HqNY9l67VAiXXC4ZsazRfTC+HFUGuqKsw45zJcx/Susy4i5wKcfYx3OIsOehUobc/GeyC5lP5dKtx0GuAu6duLFT0j35lmL7Yvh+8ew6dZLYiJZjkX5+dEFpUow8Bmpohs8VfJZRHUosd2fcKuYe7PHh+NFo+W9KP+Vh0DlNtSfDk7riqI+m9dq1+iUxnAfCuIOvo0yGKNNNnYG5LeHoWJBcAVgF3yl4cS3Lqukha6uv1YJcLOLn6ATb2RdFpuig++TJS1a22hzdjD1v07+/CPmPc9Bin//nLVeqkAoDUoweMzVQnM= 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)(396003)(346002)(376002)(39860400002)(136003)(46966006)(36840700001)(5660300002)(1076003)(426003)(82740400003)(7636003)(4326008)(336012)(36756003)(2616005)(6266002)(44832011)(107886003)(47076005)(83380400001)(6916009)(70206006)(54906003)(42186006)(36860700001)(478600001)(316002)(2906002)(26005)(82310400003)(356005)(36906005)(186003)(70586007)(8936002)(8676002)(6666004); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:36:13.2584 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: db1a0881-a47a-43d5-2754-08d8ee86bccb 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: SN1NAM02FT064.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR02MB6546 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 platform 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 | 226 ++++++++++++++++++ 2 files changed, 254 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..5a9fa82946cb --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/ddr_calibration.c @@ -0,0 +1,226 @@ +// 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 */ + +static const struct regmap_config calib_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x1000, +}; + +struct calib_cache { + struct list_head link; + const char *ep_name; + char *data; + u32 data_size; +}; + +struct calib { + struct platform_device *pdev; + 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->pdev, "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->pdev, + "MIG calibration timeout after bitstream download"); + return -ETIMEDOUT; + } + + xrt_info(calib->pdev, "took %dms", (XRT_CALIB_READ_RETRIES - times) * + XRT_CALIB_READ_INTERVAL); + return 0; +} + +static void xrt_calib_event_cb(struct platform_device *pdev, void *arg) +{ + struct calib *calib = platform_get_drvdata(pdev); + 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(pdev, "ignored event %d", e); + break; + } +} + +static int xrt_calib_remove(struct platform_device *pdev) +{ + struct calib *calib = platform_get_drvdata(pdev); + + calib_cache_clean(calib); + + return 0; +} + +static int xrt_calib_probe(struct platform_device *pdev) +{ + void __iomem *base = NULL; + struct resource *res; + struct calib *calib; + int err = 0; + + calib = devm_kzalloc(&pdev->dev, sizeof(*calib), GFP_KERNEL); + if (!calib) + return -ENOMEM; + + calib->pdev = pdev; + platform_set_drvdata(pdev, calib); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -EINVAL; + goto failed; + } + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + err = PTR_ERR(base); + goto failed; + } + + calib->regmap = devm_regmap_init_mmio(&pdev->dev, base, &calib_regmap_config); + if (IS_ERR(calib->regmap)) { + xrt_err(pdev, "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 platform_device *pdev, u32 cmd, void *arg) +{ + struct calib *calib = platform_get_drvdata(pdev); + int ret = 0; + + switch (cmd) { + case XRT_XLEAF_EVENT: + xrt_calib_event_cb(pdev, arg); + break; + case XRT_CALIB_RESULT: { + enum xrt_calib_results *r = (enum xrt_calib_results *)arg; + *r = calib->result; + break; + } + default: + xrt_err(pdev, "unsupported cmd %d", cmd); + ret = -EINVAL; + } + return ret; +} + +static struct xrt_subdev_endpoints xrt_calib_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names[]) { + { .ep_name = XRT_MD_NODE_DDR_CALIB }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_subdev_drvdata xrt_calib_data = { + .xsd_dev_ops = { + .xsd_leaf_call = xrt_calib_leaf_call, + }, +}; + +static const struct platform_device_id xrt_calib_table[] = { + { XRT_CALIB, (kernel_ulong_t)&xrt_calib_data }, + { }, +}; + +static struct platform_driver xrt_calib_driver = { + .driver = { + .name = XRT_CALIB, + }, + .probe = xrt_calib_probe, + .remove = xrt_calib_remove, + .id_table = xrt_calib_table, +}; + +XRT_LEAF_INIT_FINI_FUNC(XRT_SUBDEV_CALIB, calib); From patchwork Wed Mar 24 05:29:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 408370 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=-21.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, 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 37070C433DB for ; Wed, 24 Mar 2021 05:37:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 02FC2619E0 for ; Wed, 24 Mar 2021 05:37:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233007AbhCXFhG (ORCPT ); Wed, 24 Mar 2021 01:37:06 -0400 Received: from mail-mw2nam12on2077.outbound.protection.outlook.com ([40.107.244.77]:58373 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235333AbhCXFgq (ORCPT ); Wed, 24 Mar 2021 01:36:46 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=eQ9OEast/OLLwY26+oK0ahtnoL8reQx+FQwQNFpDuX27hiRu9CFEBw7RJg6W+ZmRgMdomWSY/6A0RGUPJKa3F9+DMpUPHcVIVGdJetAw1GGzwWn2bF9yY0pUDaUVtohZ+zjHzV7krOR0TSVFmgwLq/bpixSDAvW1eL1nf63R31XxdDWC2pQZex34APVPrUfsP17g0+omHrua76YyyYE3oAHhhIyErzdOxkCzcvXQOlgQq79ZKo232f2AOXNC6+mHpP0OopMOmprp+bu/WhQeLLy/9rna/roqezyMb5gYjmwg1aGbyZbodPwMS0WRTjnkj04GeshXVNj1X3wla8glbQ== 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=FgnY9B0r73HcZ2CrK9u/ksYWo0wPjWRHZMjnJ/YvmCc=; b=feDGU9DGKynv5uC5mR1rdc3K6mmxiWzEKvVrh8CjAyugUA6JpKUCuRzBABqoBd+RZezzodgI/EZpjSxst5naYCSdQR395vPTzyusAS903inL13H+tslQT+b3ERfKYCe2ZSCQs3k7JnhumQpPRpJgj/xkagHZdfpmD+TrO+ySrHeUG50ukFUaWyl3Y34tag17FgcbkLL6fhUjeOGN6R3E8TMOV6s+ZBDeqWpwNLGBhz8W8Z3SkO/bmMetDy1KzAZMQWoDlLddq8duGSUIao2R2u9xLk408eeZLwOgNcIXrYBImhIW5wvGcpF+ByeB/In2XWC/kHnpAd/iR4u4jo/ghA== 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=FgnY9B0r73HcZ2CrK9u/ksYWo0wPjWRHZMjnJ/YvmCc=; b=aYVOUzQ4lhZL91StFAtD8Axdt5eOaKATaqA0Se9DxIfuoDoj+jhdLp0as475ZH2+DlBaAf/nuY/aEe+D784CWmd6024vMBOZIBYuC81QNN9R+YOM9lZ/0FA7ezga2wAEkD8Sw48sPtETr2tYHus5GsELHTUrZCKEja91DB3BmxY= Received: from SN7PR04CA0212.namprd04.prod.outlook.com (2603:10b6:806:127::7) by DM6PR02MB5801.namprd02.prod.outlook.com (2603:10b6:5:17c::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3955.23; Wed, 24 Mar 2021 05:36:43 +0000 Received: from SN1NAM02FT046.eop-nam02.prod.protection.outlook.com (2603:10b6:806:127:cafe::1a) by SN7PR04CA0212.outlook.office365.com (2603:10b6:806:127::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3977.24 via Frontend Transport; Wed, 24 Mar 2021 05:36:43 +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 SN1NAM02FT046.mail.protection.outlook.com (10.152.72.191) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3977.25 via Frontend Transport; Wed, 24 Mar 2021 05:36:43 +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.2106.2; Tue, 23 Mar 2021 22:36:23 -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.2106.2 via Frontend Transport; Tue, 23 Mar 2021 22:36:23 -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=51060 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lOwBr-0006HP-1B; Tue, 23 Mar 2021 22:36:23 -0700 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 4D9C0600133; Tue, 23 Mar 2021 22:29:57 -0700 (PDT) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , , Max Zhen Subject: [PATCH V4 XRT Alveo 20/20] fpga: xrt: Kconfig and Makefile updates for XRT drivers Date: Tue, 23 Mar 2021 22:29:47 -0700 Message-ID: <20210324052947.27889-21-lizhi.hou@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210324052947.27889-1-lizhi.hou@xilinx.com> References: <20210324052947.27889-1-lizhi.hou@xilinx.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: a3a26724-e1a7-4ea6-f583-08d8ee86ce8b X-MS-TrafficTypeDiagnostic: DM6PR02MB5801: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:4941; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: V4uvT96kKhiUQQR6QYV/PcqhnfX2xRSTSLRGkOp/0DZ2CP13FrmEc6IGghc9FzpU+x3B+xpO+2dik3ECAjhz9cdS/CrHnFy8RzB7Xi94Aq264El914N3P8RNdSuj/6YlZpygLXcPhkncDtCx00cH/NUaDBAirbG6OqyZajKyfW7+D68VtMGuhwZXAo4Rmoxk64cU+tasBaPXfJ1oQTqU0s7Wj++C+jZ0q9AMbqyEn8EzaO50rgqQr/By3YUm86/Qy24hvJDHMC+Bhj4HXC8+PWlItTVb6cPnJpfkWYDEjretYp/rnH5xouxPUupvV50SnU0GRYKRdJj1LE7c13g3G47Hpvjscr4vgyMs8W1L6cR7XMNA2UweeqISw1hiknVh1M5O+bj6duCtHvV2enET4YfFD2NkfyZ8AJFJ+/nwXOTQpi6yVQdnpgXvHmaMd03pIxvHOYtu77YJxQdiOXZDiFzXKH4l0DWaiWEy6KCPIWR0aFw8rfh5FMcqjEgHMmvSDgBntiEgKmulNqsYKRNacYupMOPMijhEV798sdNot9AYB2+BS5wHaZq42n7f5AG4ostPUcosKKqIYrQyztOtvAGlTZ/y/kf5Ya7sFgTNizqzXz2Mcfr5EWBmjpf45aJpBxhWYFc4blX6ilUvtkEBIda5U7GvLfuy3pYWaCZjKzTG3LNUvKoaVOD8ub18xI818iQwcc0viFYJJ1rr3ZrPzKQNPB776tU7WtAMH5YMaRU= 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)(39860400002)(396003)(346002)(376002)(46966006)(36840700001)(426003)(6916009)(36860700001)(7636003)(6266002)(356005)(5660300002)(47076005)(2906002)(8676002)(2616005)(966005)(15650500001)(82310400003)(1076003)(186003)(6666004)(82740400003)(26005)(70586007)(36756003)(42186006)(478600001)(8936002)(36906005)(336012)(70206006)(54906003)(83380400001)(4326008)(316002)(44832011)(107886003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Mar 2021 05:36:43.0432 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: a3a26724-e1a7-4ea6-f583-08d8ee86ce8b 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: SN1NAM02FT046.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR02MB5801 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Update fpga Kconfig/Makefile and add Kconfig/Makefile for new drivers. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- MAINTAINERS | 11 +++++++++++ drivers/Makefile | 1 + drivers/fpga/Kconfig | 2 ++ drivers/fpga/Makefile | 5 +++++ drivers/fpga/xrt/Kconfig | 8 ++++++++ drivers/fpga/xrt/lib/Kconfig | 17 +++++++++++++++++ drivers/fpga/xrt/lib/Makefile | 30 ++++++++++++++++++++++++++++++ drivers/fpga/xrt/metadata/Kconfig | 12 ++++++++++++ drivers/fpga/xrt/metadata/Makefile | 16 ++++++++++++++++ drivers/fpga/xrt/mgmt/Kconfig | 15 +++++++++++++++ drivers/fpga/xrt/mgmt/Makefile | 19 +++++++++++++++++++ 11 files changed, 136 insertions(+) create mode 100644 drivers/fpga/xrt/Kconfig create mode 100644 drivers/fpga/xrt/lib/Kconfig create mode 100644 drivers/fpga/xrt/lib/Makefile create mode 100644 drivers/fpga/xrt/metadata/Kconfig create mode 100644 drivers/fpga/xrt/metadata/Makefile create mode 100644 drivers/fpga/xrt/mgmt/Kconfig create mode 100644 drivers/fpga/xrt/mgmt/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index aa84121c5611..44ccc52987ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7009,6 +7009,17 @@ F: Documentation/fpga/ F: drivers/fpga/ F: include/linux/fpga/ +FPGA XRT DRIVERS +M: Lizhi Hou +R: Max Zhen +R: Sonal Santan +L: linux-fpga@vger.kernel.org +S: Maintained +W: https://github.com/Xilinx/XRT +F: Documentation/fpga/xrt.rst +F: drivers/fpga/xrt/ +F: include/uapi/linux/xrt/ + FPU EMULATOR M: Bill Metzenthen S: Maintained diff --git a/drivers/Makefile b/drivers/Makefile index 6fba7daba591..dbb3b727fc7a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -179,6 +179,7 @@ obj-$(CONFIG_STM) += hwtracing/stm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ +obj-$(CONFIG_FPGA_XRT_METADATA) += fpga/ obj-$(CONFIG_FSI) += fsi/ obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_MULTIPLEXER) += mux/ diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 5ff9438b7b46..01410ff000b9 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -227,4 +227,6 @@ config FPGA_MGR_ZYNQMP_FPGA to configure the programmable logic(PL) through PS on ZynqMP SoC. +source "drivers/fpga/xrt/Kconfig" + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 18dc9885883a..4b887bf95cb3 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -48,3 +48,8 @@ obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o + +# XRT drivers for Alveo +obj-$(CONFIG_FPGA_XRT_METADATA) += xrt/metadata/ +obj-$(CONFIG_FPGA_XRT_LIB) += xrt/lib/ +obj-$(CONFIG_FPGA_XRT_XMGMT) += xrt/mgmt/ diff --git a/drivers/fpga/xrt/Kconfig b/drivers/fpga/xrt/Kconfig new file mode 100644 index 000000000000..0e2c59589ddd --- /dev/null +++ b/drivers/fpga/xrt/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Xilinx Alveo FPGA device configuration +# + +source "drivers/fpga/xrt/metadata/Kconfig" +source "drivers/fpga/xrt/lib/Kconfig" +source "drivers/fpga/xrt/mgmt/Kconfig" diff --git a/drivers/fpga/xrt/lib/Kconfig b/drivers/fpga/xrt/lib/Kconfig new file mode 100644 index 000000000000..935369fad570 --- /dev/null +++ b/drivers/fpga/xrt/lib/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# XRT Alveo FPGA device configuration +# + +config FPGA_XRT_LIB + tristate "XRT Alveo Driver Library" + depends on HWMON && PCI && HAS_IOMEM + select FPGA_XRT_METADATA + select REGMAP_MMIO + help + Select this option to enable Xilinx XRT Alveo driver library. This + library is core infrastructure of XRT Alveo FPGA drivers which + provides functions for working with device nodes, iteration and + lookup of platform devices, common interfaces for platform devices, + plumbing of function call and ioctls between platform devices and + parent partitions. diff --git a/drivers/fpga/xrt/lib/Makefile b/drivers/fpga/xrt/lib/Makefile new file mode 100644 index 000000000000..58563416efbf --- /dev/null +++ b/drivers/fpga/xrt/lib/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020-2021 Xilinx, Inc. All rights reserved. +# +# Authors: Sonal.Santan@xilinx.com +# + +FULL_XRT_PATH=$(srctree)/$(src)/.. +FULL_DTC_PATH=$(srctree)/scripts/dtc/libfdt + +obj-$(CONFIG_FPGA_XRT_LIB) += xrt-lib.o + +xrt-lib-objs := \ + lib-drv.o \ + xroot.o \ + xclbin.o \ + subdev.o \ + cdev.o \ + group.o \ + xleaf/vsec.o \ + xleaf/axigate.o \ + xleaf/devctl.o \ + xleaf/icap.o \ + xleaf/clock.o \ + xleaf/clkfreq.o \ + xleaf/ucs.o \ + xleaf/ddr_calibration.o + +ccflags-y := -I$(FULL_XRT_PATH)/include \ + -I$(FULL_DTC_PATH) diff --git a/drivers/fpga/xrt/metadata/Kconfig b/drivers/fpga/xrt/metadata/Kconfig new file mode 100644 index 000000000000..129adda47e94 --- /dev/null +++ b/drivers/fpga/xrt/metadata/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# XRT Alveo FPGA device configuration +# + +config FPGA_XRT_METADATA + bool "XRT Alveo Driver Metadata Parser" + select LIBFDT + help + This option provides helper functions to parse Xilinx Alveo FPGA + firmware metadata. The metadata is in device tree format and the + XRT driver uses it to discover the HW subsystems behind PCIe BAR. diff --git a/drivers/fpga/xrt/metadata/Makefile b/drivers/fpga/xrt/metadata/Makefile new file mode 100644 index 000000000000..14f65ef1595c --- /dev/null +++ b/drivers/fpga/xrt/metadata/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020-2021 Xilinx, Inc. All rights reserved. +# +# Authors: Sonal.Santan@xilinx.com +# + +FULL_XRT_PATH=$(srctree)/$(src)/.. +FULL_DTC_PATH=$(srctree)/scripts/dtc/libfdt + +obj-$(CONFIG_FPGA_XRT_METADATA) += xrt-md.o + +xrt-md-objs := metadata.o + +ccflags-y := -I$(FULL_XRT_PATH)/include \ + -I$(FULL_DTC_PATH) diff --git a/drivers/fpga/xrt/mgmt/Kconfig b/drivers/fpga/xrt/mgmt/Kconfig new file mode 100644 index 000000000000..31e9e19fffb8 --- /dev/null +++ b/drivers/fpga/xrt/mgmt/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Xilinx XRT FPGA device configuration +# + +config FPGA_XRT_XMGMT + tristate "Xilinx Alveo Management Driver" + depends on FPGA_XRT_LIB + select FPGA_XRT_METADATA + select FPGA_BRIDGE + select FPGA_REGION + help + Select this option to enable XRT PCIe driver for Xilinx Alveo FPGA. + This driver provides interfaces for userspace application to access + Alveo FPGA device. diff --git a/drivers/fpga/xrt/mgmt/Makefile b/drivers/fpga/xrt/mgmt/Makefile new file mode 100644 index 000000000000..acabd811f3fd --- /dev/null +++ b/drivers/fpga/xrt/mgmt/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020-2021 Xilinx, Inc. All rights reserved. +# +# Authors: Sonal.Santan@xilinx.com +# + +FULL_XRT_PATH=$(srctree)/$(src)/.. +FULL_DTC_PATH=$(srctree)/scripts/dtc/libfdt + +obj-$(CONFIG_FPGA_XRT_XMGMT) += xrt-mgmt.o + +xrt-mgmt-objs := root.o \ + main.o \ + fmgr-drv.o \ + main-region.o + +ccflags-y := -I$(FULL_XRT_PATH)/include \ + -I$(FULL_DTC_PATH)