From patchwork Thu Feb 18 06:40:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384530 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 3F234C433E9 for ; Thu, 18 Feb 2021 06:47:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E900560295 for ; Thu, 18 Feb 2021 06:47:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229471AbhBRGqy (ORCPT ); Thu, 18 Feb 2021 01:46:54 -0500 Received: from mail-dm6nam12on2064.outbound.protection.outlook.com ([40.107.243.64]:63297 "EHLO NAM12-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230254AbhBRGoN (ORCPT ); Thu, 18 Feb 2021 01:44:13 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Xid+yeBJzdwhZ3OoAampqcCLNnsIfeT4/BN6nT1Zv6WkAyIa+CsAdQA0RCnyGy9ODotLoNRp+v2HYSd3It6/IiVxwDi2ba6EqR3CNJiYKCvm5igQeRl6/rKgIaOV8FDexZfID0YK2WStjUysb6OVmQYENkNyr+iqWGL0I2aTM15ojJ1npCqcWo6+XbsntXW6bQz5AQ0v0wWPITtXc7m11pj15w9cqZadWVJkflsilswGR+P/w5cRZdENpRHNavzkEmhKCYZ5KScEp/dqPCwqj1tP1LZFeQ2y9HTOYN/Jw0aXJq0OaOaudeO0snD6Y4ZMrxLWXCmjkWULGGTz96gP1A== 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=FFbv8Te/OzW74xlQOxOgorgLWhekM/UnynTgE9067EU=; b=hjN7cYHsdfqBMv37CgsZ/oVlJrJP+C4byUxL8vcYc4ov1RJtySs/lfqoMREUiziaXFhqmhpfSM1h7rUy5Z7doAOU8GvdoJkDula1Yi05izxl02v6YYzUVrrvftjES03zFr7mcIG+kFfNIqdTnXilgUA4WEL/z+YrU2cd2HEulUO5CQEvxltKiRLDGwCFfB7uGxRE7ogLMS5O66UR2rYw861RCWEzdYD0zjMFG9wWdgApR2zuR+YR5RryqmIfO21+uHU5oPXzc68kdpmP0Q2j03A/O+Hf3eG5+lYM47cRWbH3TN8fOW6Yor+Ob2JlTEXmaKVz+gp/yJ19GtV5uAcTTQ== 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=bestguesspass 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=FFbv8Te/OzW74xlQOxOgorgLWhekM/UnynTgE9067EU=; b=OQYnfdUJLuWK+/mQTQgahAOPuly0yPtVO1NE7cd7Hq1nxR1Ej/CPlxJ6B4p0jK7ttArlYr6F5F0BkC306PGvZtA+zPzWyFwiZ40/eq+2v3Jhv50b2n2x/jcZGLXDCCYXrs0KB1f5VUpZkNy5+1AdMS6+/0d3opjgpW+J3d8tmfk= Received: from CY4PR2201CA0022.namprd22.prod.outlook.com (2603:10b6:910:5f::32) by CH2PR02MB6805.namprd02.prod.outlook.com (2603:10b6:610:7c::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.31; Thu, 18 Feb 2021 06:43:17 +0000 Received: from CY1NAM02FT024.eop-nam02.prod.protection.outlook.com (2603:10b6:910:5f:cafe::b6) by CY4PR2201CA0022.outlook.office365.com (2603:10b6:910:5f::32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:43:17 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 149.199.62.198) smtp.mailfrom=xilinx.com; kernel.org; dkim=none (message not signed) header.d=none;kernel.org; dmarc=bestguesspass 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 CY1NAM02FT024.mail.protection.outlook.com (10.152.74.210) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:43:17 +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.1913.5; Wed, 17 Feb 2021 22:43:15 -0800 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.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:43:15 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40162 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd1v-0001lA-Hv; Wed, 17 Feb 2021 22:43:15 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 9FCD660011B; Wed, 17 Feb 2021 22:41:05 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 02/18] fpga: xrt: driver metadata helper functions Date: Wed, 17 Feb 2021 22:40:03 -0800 Message-ID: <20210218064019.29189-3-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 640d8604-5bc9-45c2-c052-08d8d3d87924 X-MS-TrafficTypeDiagnostic: CH2PR02MB6805: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:873; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RIMSvbnGQJwz2wyOY8IsI9+uco+vQevNilQ6zQMP7X6ifd1/hlMJXLGoBGVB140W7LmxEohEGL+vI+yiTcBAdnhxkNrEzkSIZ2H8tIqpwE8/9cZBlRAeodAHHRHKYsvBgVgZqg2eaVVER6xI9TJ8jVc6J6h9vZXhTYMdM1qvqyN0+eCWnBYry/ErnYwgxesqGzaPM38ibQpeHgIGDIZCydZILJJjUwTYtuI5pdrpq8atqbF5CEj12qq+0QtO9YQWumZW2h0kCe9ufBqkyKFuNSrw+6EDehncE/ywgSv8oWk8WxztCXamVR9COXvjeZOjV9aPwgFq51OP3TbCGsuh7HuhldVwO3rpRjzlCIdOowODcWBF8Rm+2eHyzRaOvtZ+2d0JeAnxT3PS0y5ffwwHIeTzhx4dmBpEfs1C1MQGpPbgJXfhu64kofmYSFIWF7q1B9ySDQiO+iGBRJUGz7CuNrKMo+rO6Rnb1YYS668H2CWv/BzWHWN3F76Ysypy/5K8RHbQ0b500QnCKRRzMcx8yeN6xS8vM3pGyIfG8vQMwEexwjQVqw6RPo5iamlgnkFruOvuSqtikjPX7FenU/EpVsWBREYDlbl5Wp9LeTejlilaNmm8P7vxsyuD/1nO8AuaEdJQcV1OiAX5jYghWswBosmCkgquPw7plQETmJRY5qU= 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)(376002)(136003)(396003)(36840700001)(46966006)(26005)(83380400001)(356005)(2616005)(6916009)(44832011)(8936002)(8676002)(70206006)(82310400003)(54906003)(42186006)(70586007)(36756003)(478600001)(36860700001)(36906005)(47076005)(1076003)(426003)(7636003)(186003)(2906002)(5660300002)(107886003)(82740400003)(336012)(4326008)(6266002)(30864003)(316002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:43:17.1143 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 640d8604-5bc9-45c2-c052-08d8d3d87924 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: CY1NAM02FT024.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR02MB6805 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 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 | 229 ++++++++++++ drivers/fpga/xrt/metadata/metadata.c | 524 +++++++++++++++++++++++++++ 2 files changed, 753 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..b929bc469b73 --- /dev/null +++ b/drivers/fpga/xrt/include/metadata.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for Xilinx Runtime (XRT) driver + * + * 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) + +#define XRT_MD_PROP_COMPATIBLE "compatible" +#define XRT_MD_PROP_PF_NUM "pcie_physical_function" +#define XRT_MD_PROP_BAR_IDX "pcie_bar_mapping" +#define XRT_MD_PROP_IO_OFFSET "reg" +#define XRT_MD_PROP_INTERRUPTS "interrupts" +#define XRT_MD_PROP_INTERFACE_UUID "interface_uuid" +#define XRT_MD_PROP_LOGIC_UUID "logic_uuid" +#define XRT_MD_PROP_VERSION_MAJOR "firmware_version_major" + +#define XRT_MD_PROP_HWICAP "axi_hwicap" +#define XRT_MD_PROP_PDI_CONFIG "pdi_config_mem" + +#define XRT_MD_NODE_ENDPOINTS "addressable_endpoints" +#define XRT_MD_INTERFACES_PATH "/interfaces" + +#define XRT_MD_NODE_FIRMWARE "firmware" +#define XRT_MD_NODE_INTERFACES "interfaces" +#define XRT_MD_NODE_PARTITION_INFO "partition_info" + +#define XRT_MD_NODE_FLASH "ep_card_flash_program_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_SYSMON "ep_cmp_sysmon_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_MGMT "ep_firewall_ctrl_mgmt_00" +#define XRT_MD_NODE_AF_CTRL_USER "ep_firewall_ctrl_user_00" +#define XRT_MD_NODE_AF_CTRL_DEBUG "ep_firewall_ctrl_debug_00" +#define XRT_MD_NODE_AF_DATA_H2C "ep_firewall_data_h2c_00" +#define XRT_MD_NODE_AF_DATA_C2H "ep_firewall_data_c2h_00" +#define XRT_MD_NODE_AF_DATA_P2P "ep_firewall_data_p2p_00" +#define XRT_MD_NODE_AF_DATA_M2M "ep_firewall_data_m2m_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_CMC_MUTEX "ep_cmc_mutex_00" +#define XRT_MD_NODE_CMC_FW_MEM "ep_cmc_firmware_mem_00" +#define XRT_MD_NODE_ERT_FW_MEM "ep_ert_firmware_mem_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_MAILBOX_MGMT "ep_mailbox_mgmt_00" +#define XRT_MD_NODE_MAILBOX_USER "ep_mailbox_user_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_PCIE_MON "ep_pcie_link_mon_00" +#define XRT_MD_NODE_DDR_CALIB "ep_ddr_mem_calib_00" +#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_KDMA_CTRL "ep_kdma_ctrl_00" +#define XRT_MD_NODE_FPGA_CONFIG "ep_fpga_configuration_00" +#define XRT_MD_NODE_ERT_SCHED "ep_ert_sched_00" +#define XRT_MD_NODE_XDMA "ep_xdma_00" +#define XRT_MD_NODE_MSIX "ep_msix_00" +#define XRT_MD_NODE_QDMA "ep_qdma_00" +#define XRT_MD_XRT_MD_NODE_QDMA4 "ep_qdma4_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_CLK_SHUTDOWN "ep_aclk_shutdown_00" +#define XRT_MD_NODE_ERT_BASE "ep_ert_base_address_00" +#define XRT_MD_NODE_ERT_RESET "ep_ert_reset_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_CLKFREQ_HBM "ep_freq_cnt_aclk_hbm_00" +#define XRT_MD_NODE_GAPPING "ep_gapping_demand_00" +#define XRT_MD_NODE_UCS_CONTROL_STATUS "ep_ucs_control_status_00" +#define XRT_MD_NODE_P2P "ep_p2p_00" +#define XRT_MD_NODE_REMAP_P2P "ep_remap_p2p_00" +#define XRT_MD_NODE_DDR4_RESET_GATE "ep_ddr_mem_srsr_gate_00" +#define XRT_MD_NODE_ADDR_TRANSLATOR "ep_remap_data_c2h_00" +#define XRT_MD_NODE_MAILBOX_XRT "ep_mailbox_user_to_ert_00" +#define XRT_MD_NODE_PMC_INTR "ep_pmc_intr_00" +#define XRT_MD_NODE_PMC_MUX "ep_pmc_mux_00" + +/* driver defined endpoints */ +#define XRT_MD_NODE_VSEC "drv_ep_vsec_00" +#define XRT_MD_NODE_VSEC_GOLDEN "drv_ep_vsec_golden_00" +#define XRT_MD_NODE_BLP_ROM "drv_ep_blp_rom_00" +#define XRT_MD_NODE_MAILBOX_VSEC "ep_mailbox_vsec_00" +#define XRT_MD_NODE_PLAT_INFO "drv_ep_platform_info_mgmt_00" +#define XRT_MD_NODE_TEST "drv_ep_test_00" +#define XRT_MD_NODE_MGMT_MAIN "drv_ep_mgmt_main_00" +#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_XRT_MD_NODE_PARTITION_INFO_BLP "partition_info_0" +#define XRT_MD_XRT_MD_NODE_PARTITION_INFO_PLP "partition_info_1" + +#define XRT_MD_NODE_DDR_SRSR "drv_ep_ddr_srsr" +#define XRT_MD_REGMAP_DDR_SRSR "drv_ddr_srsr" + +#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; + long 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 (!strcmp(res_name, res_map->res_name)) + 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); +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, + 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); +void xrt_md_pack(struct device *dev, char *blob); +char *xrt_md_dup(struct device *dev, const char *blob); +int xrt_md_get_intf_uuids(struct device *dev, const char *blob, + u32 *num_uuids, uuid_t *intf_uuids); +static inline int xrt_md_copy_all_endpoints(struct device *dev, char *blob, const char *src_blob) +{ + return xrt_md_copy_endpoint(dev, blob, src_blob, XRT_MD_NODE_ENDPOINTS, + NULL, NULL); +} + +/* + * Firmware provides 128 bit hash string as unque id of partition/interface. + * This string will be canonical textual representation in the future. + * Before that, introducing these two functions below to translate + * hash string to uuid_t for released hardware. + */ +static inline void xrt_md_trans_uuid2str(const uuid_t *uuid, char *uuidstr) +{ + int i, p; + u8 *u = (u8 *)uuid; + + for (p = 0, i = sizeof(uuid_t) - 1; i >= 0; p++, i--) + (void)snprintf(&uuidstr[p * 2], 3, "%02x", u[i]); +} + +static inline int xrt_md_trans_str2uuid(struct device *dev, const char *uuidstr, uuid_t *p_uuid) +{ + char *p; + const char *str; + char tmp[3] = { 0 }; + int i, ret; + + memset(p_uuid, 0, sizeof(*p_uuid)); + p = (char *)p_uuid; + 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); + if (ret) + return -EINVAL; + p++; + str -= 2; + } + + 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..5d106396f438 --- /dev/null +++ b/drivers/fpga/xrt/metadata/metadata.c @@ -0,0 +1,524 @@ +// 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) + +static int xrt_md_setprop(struct device *dev, char *blob, int offset, + const char *prop, const void *val, int size); +static int xrt_md_overlay(struct device *dev, char *blob, int target, + const char *overlay_blob, int overlay_offset); +static int xrt_md_get_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + int *ep_offset); + +unsigned long xrt_md_size(struct device *dev, const char *blob) +{ + unsigned long len = (long)fdt_totalsize(blob); + + len = (len > MAX_BLOB_SIZE) ? XRT_MD_INVALID_LENGTH : len; + return len; +} +EXPORT_SYMBOL_GPL(xrt_md_size); + +int xrt_md_create(struct device *dev, char **blob) +{ + int ret = 0; + + WARN_ON(!blob); + + *blob = vmalloc(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, ret, 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); + +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; +} + +int xrt_md_del_endpoint(struct device *dev, char *blob, const char *ep_name, + char *regmap_name) +{ + int ret; + int ep_offset; + + 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, bool root) +{ + int ret = 0; + int ep_offset = 0; + u32 val, count = 0; + u64 io_range[2]; + char comp[128]; + + if (!ep->ep_name) { + dev_err(dev, "empty name"); + return -EINVAL; + } + + if (!root) { + ret = xrt_md_get_endpoint(dev, blob, XRT_MD_NODE_ENDPOINTS, NULL, + &ep_offset); + if (ret) { + dev_err(dev, "invalid blob, ret = %d", ret); + return -EINVAL; + } + } + + ep_offset = xrt_md_add_node(dev, blob, ep_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), + "%s-%s", ep->regmap, ep->regmap_ver); + count++; + } + + count += snprintf(comp + count, sizeof(comp) - count, + "%s", ep->regmap); + count++; + + 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, false); +} +EXPORT_SYMBOL_GPL(xrt_md_add_endpoint); + +static int xrt_md_get_endpoint(struct device *dev, const char *blob, + const char *ep_name, const char *regmap_name, + int *ep_offset) +{ + int offset; + const char *name; + + 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; +} + +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 && offset >= 0) + *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) + *val = NULL; + if (ep_name) { + ret = xrt_md_get_endpoint(dev, blob, ep_name, regmap_name, + &offset); + if (ret) { + dev_err(dev, "cannot get ep %s, regmap %s, ret = %d", + ep_name, regmap_name, ret); + return -EINVAL; + } + } else { + offset = fdt_next_node(blob, -1, NULL); + if (offset < 0) { + dev_err(dev, "internal error, ret = %d", offset); + return -EINVAL; + } + } + + if (val) { + *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); + +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; +} + +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; + + if (ep_name) { + ret = xrt_md_get_endpoint(dev, blob, ep_name, + regmap_name, &offset); + if (ret) { + dev_err(dev, "cannot get node %s, ret = %d", + ep_name, ret); + return -EINVAL; + } + } else { + offset = fdt_next_node(blob, -1, NULL); + if (offset < 0) { + dev_err(dev, "internal error, ret = %d", offset); + return -EINVAL; + } + } + + 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) +{ + int offset, target; + int ret; + struct xrt_md_endpoint ep = {0}; + const char *newepnm = new_ep_name ? new_ep_name : ep_name; + + 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; + ret = __xrt_md_add_endpoint(dev, blob, &ep, &target, + fdt_parent_offset(src_blob, offset) == 0); + if (ret) + return -EINVAL; + } + + ret = xrt_md_overlay(dev, blob, target, src_blob, offset); + if (ret) + dev_err(dev, "overlay failed, ret = %d", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xrt_md_copy_endpoint); + +char *xrt_md_dup(struct device *dev, const char *blob) +{ + int ret; + char *dup_blob; + + ret = xrt_md_create(dev, &dup_blob); + if (ret) + return NULL; + ret = xrt_md_overlay(dev, dup_blob, -1, blob, -1); + if (ret) { + vfree(dup_blob); + return NULL; + } + + return dup_blob; +} +EXPORT_SYMBOL_GPL(xrt_md_dup); + +static int xrt_md_overlay(struct device *dev, char *blob, int target, + const char *overlay_blob, int overlay_offset) +{ + int property, subnode; + int ret; + + WARN_ON(!blob || !overlay_blob); + + if (!blob) { + dev_err(dev, "blob is NULL"); + 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) { + 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); + if (ret) + return ret; + } + + return 0; +} + +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; + + 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) { + *next_ep = NULL; + *next_regmap = NULL; + return -EINVAL; + } + + offset = ep_name ? fdt_next_subnode(blob, offset) : + fdt_first_subnode(blob, offset); + if (offset < 0) { + *next_ep = NULL; + *next_regmap = NULL; + 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 = (char *)fdt_get_name(blob, ep_offset, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_md_get_compatible_endpoint); + +void xrt_md_pack(struct device *dev, char *blob) +{ + int ret; + + ret = fdt_pack(blob); + if (ret) + dev_err(dev, "pack failed %d", ret); +} +EXPORT_SYMBOL_GPL(xrt_md_pack); + +int xrt_md_get_intf_uuids(struct device *dev, const char *blob, + u32 *num_uuids, uuid_t *intf_uuids) +{ + int offset, count = 0; + int ret; + const char *uuid_str; + + 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)) { + uuid_str = fdt_getprop(blob, offset, XRT_MD_PROP_INTERFACE_UUID, + NULL); + if (!uuid_str) { + dev_err(dev, "empty intf uuid node"); + return -EINVAL; + } + + if (intf_uuids && count < *num_uuids) { + ret = xrt_md_trans_str2uuid(dev, uuid_str, + &intf_uuids[count]); + if (ret) + return -EINVAL; + } + count++; + } + + *num_uuids = count; + + return 0; +} +EXPORT_SYMBOL_GPL(xrt_md_get_intf_uuids); From patchwork Thu Feb 18 06:40:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384529 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 15710C433E6 for ; Thu, 18 Feb 2021 06:49:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C31B464EAE for ; Thu, 18 Feb 2021 06:49:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230211AbhBRGr2 (ORCPT ); Thu, 18 Feb 2021 01:47:28 -0500 Received: from mail-bn8nam11on2067.outbound.protection.outlook.com ([40.107.236.67]:1633 "EHLO NAM11-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230414AbhBRGoe (ORCPT ); Thu, 18 Feb 2021 01:44:34 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lVEdj5+Rf1Y+sqKJt/KPMD/B9EgHhVGPK8KwXMpj1VKAD3ev+297+JzYU1b8bazZie8i+gt0cC37zAU/iqDoy2JODn3Chm1n7yrMaPyL5GJo4+o30hcuFgyiXQy6vb4643fUI0TvDXXFocIf4/bO84WvawS5YFpffnM3T3siXzAlucj8aSnbGpGU8OzJZoyvJJfPFcyk9lao80kwSm5XXfdCEcBfEfQvSv7FTmdFwciN0iVdHJUTlCw6ifCVb1IamZw2utzR3mUBwip7R7AMgGHDaCtJPorf/gYK/0RUGWej6AuYxQBYr+FrM+zzSga+CVMqgepF4RFMu3ucNvtfpQ== 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=OvbnYh7wtw4wrcPKjmAjuyLX1itMsUsN/7g5nSLFyKU=; b=N7+i/TKov4eMw33S9YEzzsq8otcJbm10BhTQe8nvFVGF52URvkts75EdTg5A41eWqk4Yian8sr1TO4rO4KZJtfY7qNDjTRqfOpvsMu+YD1dtFuYhaiPUqvC0JCuraJflg2wkCXWzWhX/ltFT5rC6zkLhiubESp4g27bY0yRcvxI0aTEA6NMDzxvEaDW3NJK/UH7RsHDrHJZRg23FtCj7LVrL/ySmsm9PRLj6PnLjozI3BNA5weQ+qql2etTWjNv2zC1C20ucOilXjXk8H011GL9QbKE8THh7dRpjwOI0Of/1Dv88Oc9dU27rem3l/GS/pvRnoPAvxOGlXutcdBh1vA== 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=bestguesspass 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=OvbnYh7wtw4wrcPKjmAjuyLX1itMsUsN/7g5nSLFyKU=; b=hfp5bDETBywyw1YGNx+YwNVBrXlR5+F6urHmOP98LcQ+xwIzLbqAcYzFBt4c+93DvCj+47+KR6GjyxSZfXCKK+l54Ymafix3f7dVHtrjsZk/NZIFvJbVIqXQ+bkdZk5tWdRmxCkC45tPQVjIyavGmkhgLWpQGTDDQEkp/oZiP3E= Received: from CY4PR01CA0010.prod.exchangelabs.com (2603:10b6:903:1f::20) by DM6PR02MB4827.namprd02.prod.outlook.com (2603:10b6:5:fa::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.36; Thu, 18 Feb 2021 06:43:41 +0000 Received: from CY1NAM02FT050.eop-nam02.prod.protection.outlook.com (2603:10b6:903:1f:cafe::77) by CY4PR01CA0010.outlook.office365.com (2603:10b6:903:1f::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:43:41 +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=bestguesspass 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 CY1NAM02FT050.mail.protection.outlook.com (10.152.75.65) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:43:41 +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.1913.5; Wed, 17 Feb 2021 22:43:39 -0800 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.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:43:39 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40166 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd2J-0001li-Ku; Wed, 17 Feb 2021 22:43:39 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id C364F60011D; Wed, 17 Feb 2021 22:41:05 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 04/18] fpga: xrt: xrt-lib platform driver manager Date: Wed, 17 Feb 2021 22:40:05 -0800 Message-ID: <20210218064019.29189-5-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 8f7f9018-ebb5-4956-046c-08d8d3d8876f X-MS-TrafficTypeDiagnostic: DM6PR02MB4827: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:119; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: wnJBKVifC3DgR3wh6C6nDpCyUEKc/01/GIyF+flBwWbqX8hpD8UA9Xnq34v+2Uive3KhvUtc7IQ/vHio4mTwUoeVrH7XePJCa5Q+ktRwkJmxqUmAUEALhvWIT44nNusK9RLiEBymE02JnXCBOFLmZCbJ0jve3YTx1OVcPi/3j8+BtMZoPN4pKVRegKTkGxrpkPvYbIZGbFVxVzBz0pGXG3peTGsX0H+aZcjUdZxo7yBdivbohxc9ZULu03zwdR8BU0WpS40GK2XgtKoRazreQl3+5zuSNfJwaH1NzAmbJC4sdyl7v5Q8neh2dq2Lu18ddWd/MbcmP2kvwO/r0py9G+WugQExjJ6AlZODjotdPIEeQA5JLihJFMEmDJFIgYWw9VlHW4Z6O/CKwSkPGD8LhG9fdc9OEhjgB438V5whYhMKWHYTop5sl7hdsKHCoq7irrwdumq0o0SqNWv3PW0zwbW8VZxF/Onn/gv8afUdnt9Fa/PWJWQxvM3MDX2U16r1bBvH/PECsaECqc51j6rjGIIWkGSILnGi9LKXsdq5hUqIvVB78JQyqiLaGrOBMO3KmB+A8jdDPnGAoc42fFAYP+H8IvAzZ6L4wqrQeQzlJiLhViCQ8i0OJxAMqcQ4lNKyyPFNs74NOFBYT/dEaXlVRw== 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)(396003)(346002)(39860400002)(376002)(46966006)(36840700001)(1076003)(107886003)(356005)(44832011)(82740400003)(4326008)(82310400003)(26005)(7636003)(70586007)(2616005)(5660300002)(8676002)(336012)(6266002)(316002)(36906005)(186003)(426003)(2906002)(8936002)(83380400001)(36756003)(42186006)(478600001)(47076005)(70206006)(36860700001)(6916009)(54906003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:43:41.0882 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 8f7f9018-ebb5-4956-046c-08d8d3d8876f 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: CY1NAM02FT050.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR02MB4827 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/lib/main.c | 274 ++++++++++++++++++++++++++++++++++++ drivers/fpga/xrt/lib/main.h | 17 +++ 2 files changed, 291 insertions(+) create mode 100644 drivers/fpga/xrt/lib/main.c create mode 100644 drivers/fpga/xrt/lib/main.h diff --git a/drivers/fpga/xrt/lib/main.c b/drivers/fpga/xrt/lib/main.c new file mode 100644 index 000000000000..36fb62710843 --- /dev/null +++ b/drivers/fpga/xrt/lib/main.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Xilinx Alveo FPGA Support + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#include +#include "xleaf.h" +#include "xroot.h" +#include "main.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 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_nolock(enum xrt_subdev_id id) +{ + const struct list_head *ptr; + + list_for_each(ptr, &xrt_drv_maps) { + struct xrt_drv_map *tmap = list_entry(ptr, struct xrt_drv_map, 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_nolock(id); + mutex_unlock(&xrt_lib_lock); + /* + * map should remain valid even after 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; + + mutex_lock(&xrt_lib_lock); + + map = xrt_drv_find_map_by_id_nolock(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 = vzalloc(sizeof(*map)); + if (!map) { + mutex_unlock(&xrt_lib_lock); + return -ENOMEM; + } + map->id = id; + map->drv = drv; + map->eps = eps; + + xrt_drv_register_driver(map); + + 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_nolock(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); + vfree(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); + vfree(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/main.h b/drivers/fpga/xrt/lib/main.h new file mode 100644 index 000000000000..f3bfc87ee614 --- /dev/null +++ b/drivers/fpga/xrt/lib/main.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_MAIN_H_ +#define _XRT_MAIN_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 /* _XRT_MAIN_H_ */ From patchwork Thu Feb 18 06:40:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384527 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 ECE7AC433E0 for ; Thu, 18 Feb 2021 06:50:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 970B864DFF for ; Thu, 18 Feb 2021 06:50:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230492AbhBRGtu (ORCPT ); Thu, 18 Feb 2021 01:49:50 -0500 Received: from mail-mw2nam12on2089.outbound.protection.outlook.com ([40.107.244.89]:18701 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S230499AbhBRGpY (ORCPT ); Thu, 18 Feb 2021 01:45:24 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GBLptQhQRiXXPoCwuTC0LGNwAup+K6YqkR0HfmVN4jD/dTxHiwgWpOAXMmF4WX25LxRljVjDGz50rwJBLXHijg3HYGrOu4Unto46vL+8Ji5lxvp73Nrx9U4KzWYDSvbPMsRb5V5IDXHLexhj4ULmy+tihCEPMQIdO60TMQTTihYDPtCox7grvN5OeLjvWjXzwlAwNFMFb/dkYfnln/G7WjC9gswfd7mxzhb4bl5/ihTA3MbRQcJ3s6CPUXUpGLyMCKKBW2nC851n/bQ8g83EPwyHS66UTQZ4rQG5BfFPncFoIybX6RhV01OfHniqP08IgqCsRw8/LyAvc19E1kPlmA== 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=33iDveisfT4f79uuD+ddvuclmU/h4cKMP7UkUfVye9g=; b=At9hc6KD9txz3T9E4AHefX+C6KLE7sjxKLMdqWuPtFMOAARwzqIeYH5Yt8LxcJXvPniProN23sbxr17SpbDZdoWCcC/q/dL3DcOZlyW2dUV+JLWPAxEOA/IHto1Wc2KafZP+bV/GoWov3oKGRlXT5et8qAtHrmIwWm6Zex7ANSf+9y5iIYCS+54hld82+ax5jvotdxwoKWC2qSKrg+84IzL5S28OJKLefPVsPMhyMz0Ie694ejNWMiB+wAZhu1zfsqKDZAYeDHedVZKl0giS8BBRQP1hh/5o3VPXkL4RKuoi3zktMmapgohVabAuFFzKbFvKocU18AoPIMicJNS88Q== 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=bestguesspass 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=33iDveisfT4f79uuD+ddvuclmU/h4cKMP7UkUfVye9g=; b=VkFzMWTiapdtOWr4N+MFJfCe+XXdqiIoJV29UfgrmcxL+X0suvsSQjbX+fE/VHTHUEkPtXSgquODgJduwuC2fwSGKSrA6RHn1VEkzPZBTfuFizsD01gqcCL5mDoEqNNRvDOsO0wIyNorUOFi4w27D3B5nFmjwkm3Sa5yrh0dJSs= Received: from DM6PR13CA0041.namprd13.prod.outlook.com (2603:10b6:5:134::18) by MN2PR02MB6352.namprd02.prod.outlook.com (2603:10b6:208:1b8::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.34; Thu, 18 Feb 2021 06:44:25 +0000 Received: from CY1NAM02FT027.eop-nam02.prod.protection.outlook.com (2603:10b6:5:134:cafe::3) by DM6PR13CA0041.outlook.office365.com (2603:10b6:5:134::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.15 via Frontend Transport; Thu, 18 Feb 2021 06:44:25 +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=bestguesspass 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 CY1NAM02FT027.mail.protection.outlook.com (10.152.75.159) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:44:24 +0000 Received: from xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) 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.1913.5; Wed, 17 Feb 2021 22:44:15 -0800 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server id 15.1.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:44:15 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40172 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd2t-0000a7-P3; Wed, 17 Feb 2021 22:44:15 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 01D13600120; Wed, 17 Feb 2021 22:41:05 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 07/18] fpga: xrt: management physical function driver (root) Date: Wed, 17 Feb 2021 22:40:08 -0800 Message-ID: <20210218064019.29189-8-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 71761757-4617-44c5-d460-08d8d3d8a19a X-MS-TrafficTypeDiagnostic: MN2PR02MB6352: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:366; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: CnFRmFg04oeu0xm23yjbWrteVT74xaE/ZL9G8kgueHyOhXFx18GvqV7SYjBOZC+flyfQZFY3gWWO87M8uoOIO2uB2W/KX6ycq4G0JM7w1vz4yjAphUOENCoz8DFliTXFCpFbYNTp6WSuIrusl8mobvH0pUIAd/x/tn6n5g/Bngb1r2N6mO/oLZ5vIM1OlyPUs/9wX8D7gtilUgAjJJ2/nBMc+rn8mkVvPe4zsrgBqtMKtSjkXjnmDd9uBZWXEDiO1el/fAhq2394XQtavehidBrO7es3fXlBM6egPbambAEbQNdOnOqp6fWEMKB0W1AvnMSHy862eOjDMCB4Ltz20vyjFilvFMIUt9rYJMfkHDokGlACcuEC90sPrDO3frybvyF11xqhtucjdIHjXtIcI/6Y4PUh9pk6jfv95cUZQBugnxn5aTmy2m5J84pZIxpHN8EC59+uCH+xnHDpn0TYFdNrC4yudAFOTqNko7QySwNKinLzLHqNhVncBhEp9B9ZQJ4IPFmDJKQSMdMJmGEtWoAISDDq4vpl5XDg8l96N+8heCVSkVBuxa4VLj+31tircY9xGcr0fcR/SA4NciEgclXiTiuRes34YR70h0NiGgKcxts8hj4pXtyxuZQ4TkgnEXrTPdL5XHkkvvdZloTjEy6v5oopT5LC0Ecx7LxRQqI= 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)(36840700001)(46966006)(316002)(83380400001)(42186006)(2906002)(107886003)(26005)(186003)(7636003)(2616005)(478600001)(8676002)(36860700001)(70206006)(356005)(4326008)(336012)(44832011)(82740400003)(8936002)(6266002)(5660300002)(36906005)(70586007)(47076005)(36756003)(6916009)(1076003)(54906003)(82310400003)(426003)(30864003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:44:24.9970 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 71761757-4617-44c5-d460-08d8d3d8a19a 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: CY1NAM02FT027.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR02MB6352 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 partition drivers which in turn instantiate platform drivers. The instantiation of partition and platform drivers is completely data driven. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/include/xroot.h | 114 +++++++++++ drivers/fpga/xrt/mgmt/root.c | 342 +++++++++++++++++++++++++++++++ 2 files changed, 456 insertions(+) create mode 100644 drivers/fpga/xrt/include/xroot.h create mode 100644 drivers/fpga/xrt/mgmt/root.c diff --git a/drivers/fpga/xrt/include/xroot.h b/drivers/fpga/xrt/include/xroot.h new file mode 100644 index 000000000000..752e10daa85e --- /dev/null +++ b/drivers/fpga/xrt/include/xroot.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for Xilinx Runtime (XRT) driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_ROOT_H_ +#define _XRT_ROOT_H_ + +#include +#include "subdev_id.h" +#include "events.h" + +typedef bool (*xrt_subdev_match_t)(enum xrt_subdev_id, + struct platform_device *, void *); +#define XRT_SUBDEV_MATCH_PREV ((xrt_subdev_match_t)-1) +#define XRT_SUBDEV_MATCH_NEXT ((xrt_subdev_match_t)-2) + +/* + * Root IOCTL calls. + */ +enum xrt_root_ioctl_cmd { + /* Leaf actions. */ + XRT_ROOT_GET_LEAF = 0, + XRT_ROOT_PUT_LEAF, + XRT_ROOT_GET_LEAF_HOLDERS, + + /* Group actions. */ + XRT_ROOT_CREATE_GROUP, + XRT_ROOT_REMOVE_GROUP, + XRT_ROOT_LOOKUP_GROUP, + XRT_ROOT_WAIT_GROUP_BRINGUP, + + /* Event actions. */ + XRT_ROOT_EVENT, + XRT_ROOT_EVENT_ASYNC, + + /* Device info. */ + XRT_ROOT_GET_RESOURCE, + XRT_ROOT_GET_ID, + + /* Misc. */ + XRT_ROOT_HOT_RESET, + XRT_ROOT_HWMON, +}; + +struct xrt_root_ioctl_get_leaf { + struct platform_device *xpigl_pdev; /* caller's pdev */ + xrt_subdev_match_t xpigl_match_cb; + void *xpigl_match_arg; + struct platform_device *xpigl_leaf; /* target leaf pdev */ +}; + +struct xrt_root_ioctl_put_leaf { + struct platform_device *xpipl_pdev; /* caller's pdev */ + struct platform_device *xpipl_leaf; /* target's pdev */ +}; + +struct xrt_root_ioctl_lookup_group { + struct platform_device *xpilp_pdev; /* caller's pdev */ + xrt_subdev_match_t xpilp_match_cb; + void *xpilp_match_arg; + int xpilp_grp_inst; +}; + +struct xrt_root_ioctl_get_holders { + struct platform_device *xpigh_pdev; /* caller's pdev */ + char *xpigh_holder_buf; + size_t xpigh_holder_buf_len; +}; + +struct xrt_root_ioctl_get_res { + struct resource *xpigr_res; +}; + +struct xrt_root_ioctl_get_id { + unsigned short xpigi_vendor_id; + unsigned short xpigi_device_id; + unsigned short xpigi_sub_vendor_id; + unsigned short xpigi_sub_device_id; +}; + +struct xrt_root_ioctl_hwmon { + bool xpih_register; + const char *xpih_name; + void *xpih_drvdata; + const struct attribute_group **xpih_groups; + struct device *xpih_hwmon_dev; +}; + +typedef int (*xrt_subdev_root_cb_t)(struct device *, void *, u32, void *); +int xrt_subdev_root_request(struct platform_device *self, u32 cmd, void *arg); + +/* + * Defines physical function (MPF / UPF) specific operations + * needed in common root driver. + */ +struct xroot_pf_cb { + void (*xpc_hot_reset)(struct pci_dev *pdev); +}; + +int xroot_probe(struct pci_dev *pdev, struct xroot_pf_cb *cb, void **root); +void xroot_remove(void *root); +bool xroot_wait_for_bringup(void *root); +int xroot_add_vsec_node(void *root, char *dtb); +int xroot_create_group(void *xr, char *dtb); +int xroot_add_simple_node(void *root, char *dtb, const char *endpoint); +void xroot_broadcast(void *root, enum xrt_events evt); + +#endif /* _XRT_ROOT_H_ */ diff --git a/drivers/fpga/xrt/mgmt/root.c b/drivers/fpga/xrt/mgmt/root.c new file mode 100644 index 000000000000..583a37c9d30c --- /dev/null +++ b/drivers/fpga/xrt/mgmt/root.c @@ -0,0 +1,342 @@ +// 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 "main-impl.h" +#include "metadata.h" + +#define XMGMT_MODULE_NAME "xmgmt" +#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; +static const struct pci_device_id xmgmt_pci_ids[] = { + { PCI_DEVICE(0x10EE, 0xd020), }, /* Alveo U50 (golden image) */ + { PCI_DEVICE(0x10EE, 0x5020), }, /* 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 < 0) { + xmgmt_err(xm, "failed to read mrrs %d", rc); + return rc; + } + if (rc > 512) { + rc = pcie_set_readrq(pdev, 512); + if (rc) { + xmgmt_err(xm, "failed to force mrrs %d", rc); + return rc; + } + } + + 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_bctl |= PCI_BRIDGE_CTL_BUS_RESET; + pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); + + msleep(100); + pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; + 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); + } + + 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_pf_cb 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: + (void)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); + (void)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_main_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_main_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 Thu Feb 18 06:40:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384528 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 96748C4332E for ; Thu, 18 Feb 2021 06:49:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 694AD64E6F for ; Thu, 18 Feb 2021 06:49:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231236AbhBRGsJ (ORCPT ); Thu, 18 Feb 2021 01:48:09 -0500 Received: from mail-eopbgr680072.outbound.protection.outlook.com ([40.107.68.72]:57504 "EHLO NAM04-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S231145AbhBRGpZ (ORCPT ); Thu, 18 Feb 2021 01:45:25 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=AGIZkhO7+ZCuHidgZwf3AyB+XSpxQcs9nLKf0MQTj9VRoBrrxxobuhW3I6829hE4PWVonOO0+2+QEIGAE71LO47iTDjfHtKKYQRNHvakqcv2nq6LAqHacqaATjkiIwcMX8sq/sZkZw/FrSV8jFAMT7QJh20FvnmA6spMALIu8IiMe3dN9Mv7u5uhycZVNnl9czWvAnjFRjwWywXTi5gEz28H/2PETK08g21a+si2Ar44kBfUw0IPfZ7QManX9zEgAUhiyxrmx6Yc7Iy1mupQYzdLtSpQ8xRB7nAf0kfCbz3EuCbXXT5Qb3hac3rG3sarrow0GmscjVO0znIHVSe/aw== 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=6m9vp5LFQQU+w252y2PtqNDeFzDYx0RbfvVV9WDvpP4=; b=FfWWLMbbB54MtCVQcbE4YEKzIJZrhz82Wxtzh9VgRb4j1mbqmxCOjnZ2yF7nL0L7SxtB8Kjk9a6isWzlEP/mI6fQm+aIuJwUggHuK9UM2n2ITeKhw+HCvW0uxlHSNUxCJk6CprSevSwBMWfBCdTUgZrFJO4uRTYsw/ise3wG1c0naGMKHk7+KjwwCVmphBOWGVXNFaih6m5eRwL+5ZqDorPtnUIXa8zeuk7yyPgW41dGsEPx4ki5YxuqYIMUKZlQ15+m24118+JEHbYGbX2ZTfpcg2C94F7B+e0QEm3dvKiY5oEvA7RuW7AmPmfNqI6AdmjKBvoF/DzMgyd+wRxP6w== 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=bestguesspass 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=6m9vp5LFQQU+w252y2PtqNDeFzDYx0RbfvVV9WDvpP4=; b=MELzGMWJmzX1Y3Ev27IGiX1N+UQ3muAJvYam9qd4Izl/5J22vCscAUnxcUMTx3Aa+oFzjmvCo/4J3jQK3Eczg+PKUZ+Wl6woRJMR+5UzWKyyePPCbsdDHc6cf9c81coREufzNRMZTTAAPfTorUe/P13VhoZ2sizd/tHFSJMnrRE= Received: from CY4PR07CA0016.namprd07.prod.outlook.com (2603:10b6:903:165::26) by BYAPR02MB5957.namprd02.prod.outlook.com (2603:10b6:a03:122::27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.39; Thu, 18 Feb 2021 06:44:33 +0000 Received: from CY1NAM02FT057.eop-nam02.prod.protection.outlook.com (2603:10b6:903:165:cafe::5a) by CY4PR07CA0016.outlook.office365.com (2603:10b6:903:165::26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.28 via Frontend Transport; Thu, 18 Feb 2021 06:44:33 +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=bestguesspass 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 CY1NAM02FT057.mail.protection.outlook.com (10.152.75.110) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:44:33 +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.1913.5; Wed, 17 Feb 2021 22:44:27 -0800 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.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:44:27 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40174 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd35-0001nt-Qa; Wed, 17 Feb 2021 22:44:27 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 1091C600125; Wed, 17 Feb 2021 22:41:06 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 08/18] fpga: xrt: main platform driver for management function device Date: Wed, 17 Feb 2021 22:40:09 -0800 Message-ID: <20210218064019.29189-9-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: d0d03d80-3243-4d07-862f-08d8d3d8a691 X-MS-TrafficTypeDiagnostic: BYAPR02MB5957: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:538; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: fil7NtRrTegd7lE2t54dQ9DyMG3JolYR23HhapypT1BgASZp8p4uyNvv0r3Piy/QgY+gnSH4yiL7LLcPNJz2ejmqCENZem4DXweUsSpqrmN2HyNlT0bZXUvJiu/r/1Ne3APkM7rGxuLdanvn10TsFbyGt8p+6tIiqv5BTTFEXKOKEEnCYx/UlIMHvkLPc60vtAK94+yh6K1wrH1pjf/xBUuodJOJAtOM0XxwjE5UUKT7LTph8lvHgu4pacK+r7YWoJ3Bmk3+CSBfBOnvYVoj6Xi3NMFZrfUGTilpBSV7GRwmlLhBzArQ8bjiGsRNEFL4+MX057kuqfsjGe0KPpNX7vXh/dQGnBscnOUwEJTlI0NN4MAF/YG591ytEM1e5SReDEvUz5d+V46C3qeMcdznk3HCm1o4swFxnGSgOjWvW33xUSsxkcjRyb5nhEWYW9QIfZGcVVXrPv94rGH59XZJArhUEWj8ojUtHRaJ7WQxE0/+UIgPjUnTsXlSoRy9Ra8kWcoFU1mxHbhaympT+iHLrwwTCZ+IkEI5aOyksHY+bjWQBbSkccrHW6dHRXbWUTfIBSPgSMjh8qw+jZY1Yh6y9w0dusumD3k0V1iWP78k9jU3K+W+3fbifCnGQhI0rKotH8+ohSQb6kbJ2AHmdZFS3fKbCAesLq1Tq9O2RiHZPUo= 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)(376002)(396003)(136003)(36840700001)(46966006)(356005)(8936002)(36860700001)(2906002)(30864003)(6916009)(36756003)(7636003)(44832011)(5660300002)(478600001)(8676002)(36906005)(82310400003)(2616005)(47076005)(4326008)(316002)(54906003)(42186006)(1076003)(107886003)(336012)(426003)(6266002)(70206006)(186003)(82740400003)(70586007)(26005)(83380400001); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:44:33.3247 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d0d03d80-3243-4d07-862f-08d8d3d8a691 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: CY1NAM02FT057.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB5957 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org platform driver that handles IOCTLs, such as hot reset and xclbin download. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/include/xmgmt-main.h | 37 ++ drivers/fpga/xrt/mgmt/main-impl.h | 37 ++ drivers/fpga/xrt/mgmt/main.c | 693 ++++++++++++++++++++++++++ include/uapi/linux/xrt/xmgmt-ioctl.h | 46 ++ 4 files changed, 813 insertions(+) create mode 100644 drivers/fpga/xrt/include/xmgmt-main.h create mode 100644 drivers/fpga/xrt/mgmt/main-impl.h create mode 100644 drivers/fpga/xrt/mgmt/main.c create mode 100644 include/uapi/linux/xrt/xmgmt-ioctl.h diff --git a/drivers/fpga/xrt/include/xmgmt-main.h b/drivers/fpga/xrt/include/xmgmt-main.h new file mode 100644 index 000000000000..1216d1881f8e --- /dev/null +++ b/drivers/fpga/xrt/include/xmgmt-main.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for Xilinx Runtime (XRT) driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XMGMT_MAIN_H_ +#define _XMGMT_MAIN_H_ + +#include +#include "xleaf.h" + +enum xrt_mgmt_main_ioctl_cmd { + /* section needs to be vfree'd by caller */ + XRT_MGMT_MAIN_GET_AXLF_SECTION = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + /* vbnv needs to be kfree'd by caller */ + XRT_MGMT_MAIN_GET_VBNV, +}; + +enum provider_kind { + XMGMT_BLP, + XMGMT_PLP, + XMGMT_ULP, +}; + +struct xrt_mgmt_main_ioctl_get_axlf_section { + enum provider_kind xmmigas_axlf_kind; + enum axlf_section_kind xmmigas_section_kind; + void *xmmigas_section; + u64 xmmigas_section_size; +}; + +#endif /* _XMGMT_MAIN_H_ */ diff --git a/drivers/fpga/xrt/mgmt/main-impl.h b/drivers/fpga/xrt/mgmt/main-impl.h new file mode 100644 index 000000000000..dd1b3e3773cc --- /dev/null +++ b/drivers/fpga/xrt/mgmt/main-impl.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for Xilinx Alveo Management Function Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + * Cheng Zhen + */ + +#ifndef _XMGMT_MAIN_IMPL_H_ +#define _XMGMT_MAIN_IMPL_H_ + +#include +#include "xmgmt-main.h" + +struct fpga_manager; +int xmgmt_process_xclbin(struct platform_device *pdev, + struct fpga_manager *fmgr, + const struct axlf *xclbin, + enum provider_kind kind); +void xmgmt_region_cleanup_all(struct platform_device *pdev); + +int bitstream_axlf_mailbox(struct platform_device *pdev, const void *xclbin); +int xmgmt_hot_reset(struct platform_device *pdev); + +/* Getting dtb for specified group. Caller should vfree returned dtb .*/ +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind); +char *xmgmt_get_vbnv(struct platform_device *pdev); +int xmgmt_get_provider_uuid(struct platform_device *pdev, + enum provider_kind kind, uuid_t *uuid); + +int xmgmt_main_register_leaf(void); +void xmgmt_main_unregister_leaf(void); + +#endif /* _XMGMT_MAIN_IMPL_H_ */ diff --git a/drivers/fpga/xrt/mgmt/main.c b/drivers/fpga/xrt/mgmt/main.c new file mode 100644 index 000000000000..66ffb4e7029d --- /dev/null +++ b/drivers/fpga/xrt/mgmt/main.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA MGMT PF entry point driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Sonal Santan + */ + +#include +#include +#include "xclbin-helper.h" +#include "metadata.h" +#include "xleaf.h" +#include +#include "xleaf/devctl.h" +#include "xmgmt-main.h" +#include "fmgr.h" +#include "xleaf/icap.h" +#include "xleaf/axigate.h" +#include "main-impl.h" + +#define XMGMT_MAIN "xmgmt_main" + +struct xmgmt_main { + struct platform_device *pdev; + struct axlf *firmware_blp; + struct axlf *firmware_plp; + struct axlf *firmware_ulp; + bool flash_ready; + bool devctl_ready; + struct fpga_manager *fmgr; + struct mutex busy_mutex; /* busy lock */ + + uuid_t *blp_intf_uuids; + u32 blp_intf_uuid_num; +}; + +/* Caller should be responsible for freeing the returned string. */ +char *xmgmt_get_vbnv(struct platform_device *pdev) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + const char *vbnv; + char *ret; + int i; + + if (xmm->firmware_plp) + vbnv = xmm->firmware_plp->m_header.m_platformVBNV; + else if (xmm->firmware_blp) + vbnv = xmm->firmware_blp->m_header.m_platformVBNV; + else + return NULL; + + ret = kstrdup(vbnv, GFP_KERNEL); + if (!ret) + return NULL; + + for (i = 0; i < strlen(ret); i++) { + if (ret[i] == ':' || ret[i] == '.') + ret[i] = '_'; + } + return ret; +} + +static int get_dev_uuid(struct platform_device *pdev, char *uuidstr, size_t len) +{ + char uuid[16]; + struct platform_device *devctl_leaf; + struct xrt_devctl_ioctl_rw devctl_arg = { 0 }; + int err, i, count; + + devctl_leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM); + if (!devctl_leaf) { + xrt_err(pdev, "can not get %s", XRT_MD_NODE_BLP_ROM); + return -EINVAL; + } + + devctl_arg.xgir_id = XRT_DEVCTL_ROM_UUID; + devctl_arg.xgir_buf = uuid; + devctl_arg.xgir_len = sizeof(uuid); + devctl_arg.xgir_offset = 0; + err = xleaf_ioctl(devctl_leaf, XRT_DEVCTL_READ, &devctl_arg); + xleaf_put_leaf(pdev, devctl_leaf); + if (err) { + xrt_err(pdev, "can not get uuid: %d", err); + return err; + } + + for (count = 0, i = sizeof(uuid) - sizeof(u32); + i >= 0 && len > count; i -= sizeof(u32)) { + count += snprintf(uuidstr + count, len - count, "%08x", *(u32 *)&uuid[i]); + } + return 0; +} + +int xmgmt_hot_reset(struct platform_device *pdev) +{ + int ret = xleaf_broadcast_event(pdev, XRT_EVENT_PRE_HOT_RESET, false); + + if (ret) { + xrt_err(pdev, "offline failed, hot reset is canceled"); + return ret; + } + + xleaf_hot_reset(pdev); + xleaf_broadcast_event(pdev, XRT_EVENT_POST_HOT_RESET, false); + return 0; +} + +static ssize_t reset_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + + xmgmt_hot_reset(pdev); + return count; +} +static DEVICE_ATTR_WO(reset); + +static ssize_t VBNV_show(struct device *dev, struct device_attribute *da, char *buf) +{ + ssize_t ret; + char *vbnv; + struct platform_device *pdev = to_platform_device(dev); + + vbnv = xmgmt_get_vbnv(pdev); + ret = sprintf(buf, "%s\n", vbnv); + kfree(vbnv); + return ret; +} +static DEVICE_ATTR_RO(VBNV); + +static ssize_t logic_uuids_show(struct device *dev, struct device_attribute *da, char *buf) +{ + ssize_t ret; + char uuid[80]; + struct platform_device *pdev = to_platform_device(dev); + + /* Getting UUID pointed to by VSEC, should be the same as logic UUID of BLP. */ + ret = get_dev_uuid(pdev, uuid, sizeof(uuid)); + if (ret) + return ret; + ret = sprintf(buf, "%s\n", uuid); + return ret; +} +static DEVICE_ATTR_RO(logic_uuids); + +static ssize_t interface_uuids_show(struct device *dev, struct device_attribute *da, char *buf) +{ + ssize_t ret = 0; + struct platform_device *pdev = to_platform_device(dev); + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + u32 i; + + for (i = 0; i < xmm->blp_intf_uuid_num; i++) { + char uuidstr[80]; + + xrt_md_trans_uuid2str(&xmm->blp_intf_uuids[i], uuidstr); + ret += sprintf(buf + ret, "%s\n", uuidstr); + } + return ret; +} +static DEVICE_ATTR_RO(interface_uuids); + +static struct attribute *xmgmt_main_attrs[] = { + &dev_attr_reset.attr, + &dev_attr_VBNV.attr, + &dev_attr_logic_uuids.attr, + &dev_attr_interface_uuids.attr, + NULL, +}; + +/* + * sysfs hook to load xclbin primarily used for driver debug + */ +static ssize_t ulp_image_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buffer, loff_t off, size_t count) +{ + struct xmgmt_main *xmm = dev_get_drvdata(container_of(kobj, struct device, kobj)); + struct axlf *xclbin; + ulong len; + + if (off == 0) { + if (count < sizeof(*xclbin)) { + xrt_err(xmm->pdev, "count is too small %zu", count); + return -EINVAL; + } + + if (xmm->firmware_ulp) { + vfree(xmm->firmware_ulp); + xmm->firmware_ulp = NULL; + } + xclbin = (struct axlf *)buffer; + xmm->firmware_ulp = vmalloc(xclbin->m_header.m_length); + if (!xmm->firmware_ulp) + return -ENOMEM; + } else { + xclbin = xmm->firmware_ulp; + } + + len = xclbin->m_header.m_length; + if (off + count >= len && off < len) { + memcpy(xmm->firmware_ulp + off, buffer, len - off); + xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, xmm->firmware_ulp, XMGMT_ULP); + } else if (off + count < len) { + memcpy(xmm->firmware_ulp + off, buffer, count); + } + + return count; +} + +static struct bin_attribute ulp_image_attr = { + .attr = { + .name = "ulp_image", + .mode = 0200 + }, + .write = ulp_image_write, + .size = 0 +}; + +static struct bin_attribute *xmgmt_main_bin_attrs[] = { + &ulp_image_attr, + NULL, +}; + +static const struct attribute_group xmgmt_main_attrgroup = { + .attrs = xmgmt_main_attrs, + .bin_attrs = xmgmt_main_bin_attrs, +}; + +static int load_firmware_from_flash(struct platform_device *pdev, struct axlf **fw_buf, size_t *len) +{ + return -EOPNOTSUPP; +} + +static int load_firmware_from_disk(struct platform_device *pdev, struct axlf **fw_buf, size_t *len) +{ + char uuid[80]; + int err = 0; + char fw_name[256]; + const struct firmware *fw; + + err = get_dev_uuid(pdev, uuid, sizeof(uuid)); + if (err) + return err; + + (void)snprintf(fw_name, sizeof(fw_name), "xilinx/%s/partition.xsabin", uuid); + xrt_info(pdev, "try loading fw: %s", fw_name); + + err = request_firmware(&fw, fw_name, DEV(pdev)); + if (err) + return err; + + *fw_buf = vmalloc(fw->size); + *len = fw->size; + if (*fw_buf) + memcpy(*fw_buf, fw->data, fw->size); + else + err = -ENOMEM; + + release_firmware(fw); + return 0; +} + +static const struct axlf *xmgmt_get_axlf_firmware(struct xmgmt_main *xmm, enum provider_kind kind) +{ + switch (kind) { + case XMGMT_BLP: + return xmm->firmware_blp; + case XMGMT_PLP: + return xmm->firmware_plp; + case XMGMT_ULP: + return xmm->firmware_ulp; + default: + xrt_err(xmm->pdev, "unknown axlf kind: %d", kind); + return NULL; + } +} + +char *xmgmt_get_dtb(struct platform_device *pdev, enum provider_kind kind) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + char *dtb = NULL; + const struct axlf *provider = xmgmt_get_axlf_firmware(xmm, kind); + int rc; + + if (!provider) + return dtb; + + rc = xrt_xclbin_get_metadata(DEV(pdev), provider, &dtb); + if (rc) + xrt_err(pdev, "failed to find dtb: %d", rc); + return dtb; +} + +static const char *get_uuid_from_firmware(struct platform_device *pdev, const struct axlf *xclbin) +{ + const void *uuid = NULL; + const void *uuiddup = NULL; + void *dtb = NULL; + int rc; + + rc = xrt_xclbin_get_section(xclbin, PARTITION_METADATA, &dtb, NULL); + if (rc) + return NULL; + + rc = xrt_md_get_prop(DEV(pdev), dtb, NULL, NULL, XRT_MD_PROP_LOGIC_UUID, &uuid, NULL); + if (!rc) + uuiddup = kstrdup(uuid, GFP_KERNEL); + vfree(dtb); + return uuiddup; +} + +static bool is_valid_firmware(struct platform_device *pdev, + const struct axlf *xclbin, size_t fw_len) +{ + const char *fw_buf = (const char *)xclbin; + size_t axlflen = xclbin->m_header.m_length; + const char *fw_uuid; + char dev_uuid[80]; + int err; + + err = get_dev_uuid(pdev, dev_uuid, sizeof(dev_uuid)); + if (err) + return false; + + if (memcmp(fw_buf, ICAP_XCLBIN_V2, sizeof(ICAP_XCLBIN_V2)) != 0) { + xrt_err(pdev, "unknown fw format"); + return false; + } + + if (axlflen > fw_len) { + xrt_err(pdev, "truncated fw, length: %zu, expect: %zu", fw_len, axlflen); + return false; + } + + fw_uuid = get_uuid_from_firmware(pdev, xclbin); + if (!fw_uuid || strcmp(fw_uuid, dev_uuid) != 0) { + xrt_err(pdev, "bad fw UUID: %s, expect: %s", + fw_uuid ? fw_uuid : "", dev_uuid); + kfree(fw_uuid); + return false; + } + + kfree(fw_uuid); + return true; +} + +int xmgmt_get_provider_uuid(struct platform_device *pdev, enum provider_kind kind, uuid_t *uuid) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + const struct axlf *fwbuf; + const char *fw_uuid; + int rc = -ENOENT; + + mutex_lock(&xmm->busy_mutex); + + fwbuf = xmgmt_get_axlf_firmware(xmm, kind); + if (!fwbuf) + goto done; + + fw_uuid = get_uuid_from_firmware(pdev, fwbuf); + if (!fw_uuid) + goto done; + + rc = xrt_md_trans_str2uuid(DEV(pdev), fw_uuid, uuid); + kfree(fw_uuid); + +done: + mutex_unlock(&xmm->busy_mutex); + return rc; +} + +static int xmgmt_create_blp(struct xmgmt_main *xmm) +{ + struct platform_device *pdev = xmm->pdev; + int rc = 0; + char *dtb = NULL; + const struct axlf *provider = xmgmt_get_axlf_firmware(xmm, XMGMT_BLP); + + dtb = xmgmt_get_dtb(pdev, XMGMT_BLP); + if (dtb) { + rc = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, provider, XMGMT_BLP); + if (rc) { + xrt_err(pdev, "failed to process BLP: %d", rc); + goto failed; + } + + rc = xleaf_create_group(pdev, dtb); + if (rc < 0) + xrt_err(pdev, "failed to create BLP group: %d", rc); + else + rc = 0; + + WARN_ON(xmm->blp_intf_uuids); + xrt_md_get_intf_uuids(&pdev->dev, dtb, &xmm->blp_intf_uuid_num, NULL); + if (xmm->blp_intf_uuid_num > 0) { + xmm->blp_intf_uuids = vzalloc(sizeof(uuid_t) * xmm->blp_intf_uuid_num); + xrt_md_get_intf_uuids(&pdev->dev, dtb, &xmm->blp_intf_uuid_num, + xmm->blp_intf_uuids); + } + } + +failed: + vfree(dtb); + return rc; +} + +static int xmgmt_load_firmware(struct xmgmt_main *xmm) +{ + struct platform_device *pdev = xmm->pdev; + int rc; + size_t fwlen; + + rc = load_firmware_from_disk(pdev, &xmm->firmware_blp, &fwlen); + if (rc != 0) + rc = load_firmware_from_flash(pdev, &xmm->firmware_blp, &fwlen); + if (rc == 0 && is_valid_firmware(pdev, xmm->firmware_blp, fwlen)) + (void)xmgmt_create_blp(xmm); + else + xrt_err(pdev, "failed to find firmware, giving up: %d", rc); + return rc; +} + +static void xmgmt_main_event_cb(struct platform_device *pdev, void *arg) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + struct xrt_event *evt = (struct xrt_event *)arg; + enum xrt_events e = evt->xe_evt; + enum xrt_subdev_id id = evt->xe_subdev.xevt_subdev_id; + struct platform_device *leaf; + + switch (e) { + case XRT_EVENT_POST_CREATION: { + if (id == XRT_SUBDEV_DEVCTL && !xmm->devctl_ready) { + leaf = xleaf_get_leaf_by_epname(pdev, XRT_MD_NODE_BLP_ROM); + if (leaf) { + xmm->devctl_ready = true; + xleaf_put_leaf(pdev, leaf); + } + } else if (id == XRT_SUBDEV_QSPI && !xmm->flash_ready) { + xmm->flash_ready = true; + } else { + break; + } + + if (xmm->devctl_ready) + (void)xmgmt_load_firmware(xmm); + break; + } + case XRT_EVENT_PRE_REMOVAL: + break; + default: + xrt_dbg(pdev, "ignored event %d", e); + break; + } +} + +static int xmgmt_main_probe(struct platform_device *pdev) +{ + struct xmgmt_main *xmm; + + xrt_info(pdev, "probing..."); + + xmm = devm_kzalloc(DEV(pdev), sizeof(*xmm), GFP_KERNEL); + if (!xmm) + return -ENOMEM; + + xmm->pdev = pdev; + xmm->fmgr = xmgmt_fmgr_probe(pdev); + if (IS_ERR(xmm->fmgr)) + return PTR_ERR(xmm->fmgr); + + platform_set_drvdata(pdev, xmm); + mutex_init(&xmm->busy_mutex); + + /* Ready to handle req thru sysfs nodes. */ + if (sysfs_create_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup)) + xrt_err(pdev, "failed to create sysfs group"); + return 0; +} + +static int xmgmt_main_remove(struct platform_device *pdev) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + + /* By now, group driver should prevent any inter-leaf call. */ + + xrt_info(pdev, "leaving..."); + + vfree(xmm->blp_intf_uuids); + vfree(xmm->firmware_blp); + vfree(xmm->firmware_plp); + vfree(xmm->firmware_ulp); + xmgmt_region_cleanup_all(pdev); + (void)xmgmt_fmgr_remove(xmm->fmgr); + (void)sysfs_remove_group(&DEV(pdev)->kobj, &xmgmt_main_attrgroup); + return 0; +} + +static int +xmgmt_main_leaf_ioctl(struct platform_device *pdev, u32 cmd, void *arg) +{ + struct xmgmt_main *xmm = platform_get_drvdata(pdev); + int ret = 0; + + switch (cmd) { + case XRT_XLEAF_EVENT: + xmgmt_main_event_cb(pdev, arg); + break; + case XRT_MGMT_MAIN_GET_AXLF_SECTION: { + struct xrt_mgmt_main_ioctl_get_axlf_section *get = + (struct xrt_mgmt_main_ioctl_get_axlf_section *)arg; + const struct axlf *firmware = xmgmt_get_axlf_firmware(xmm, get->xmmigas_axlf_kind); + + if (!firmware) { + ret = -ENOENT; + } else { + ret = xrt_xclbin_get_section(firmware, get->xmmigas_section_kind, + &get->xmmigas_section, + &get->xmmigas_section_size); + } + break; + } + case XRT_MGMT_MAIN_GET_VBNV: { + char **vbnv_p = (char **)arg; + + *vbnv_p = xmgmt_get_vbnv(pdev); + break; + } + default: + xrt_err(pdev, "unknown cmd: %d", cmd); + ret = -EINVAL; + break; + } + return ret; +} + +static int xmgmt_main_open(struct inode *inode, struct file *file) +{ + struct platform_device *pdev = xleaf_devnode_open(inode); + + /* Device may have gone already when we get here. */ + if (!pdev) + return -ENODEV; + + xrt_info(pdev, "opened"); + file->private_data = platform_get_drvdata(pdev); + return 0; +} + +static int xmgmt_main_close(struct inode *inode, struct file *file) +{ + struct xmgmt_main *xmm = file->private_data; + + xleaf_devnode_close(inode); + + xrt_info(xmm->pdev, "closed"); + return 0; +} + +/* + * Called for xclbin download xclbin load ioctl. + */ +static int xmgmt_bitstream_axlf_fpga_mgr(struct xmgmt_main *xmm, void *axlf, size_t size) +{ + int ret; + + WARN_ON(!mutex_is_locked(&xmm->busy_mutex)); + + /* + * Should any error happens during download, we can't trust + * the cached xclbin any more. + */ + vfree(xmm->firmware_ulp); + xmm->firmware_ulp = NULL; + + ret = xmgmt_process_xclbin(xmm->pdev, xmm->fmgr, axlf, XMGMT_ULP); + if (ret == 0) + xmm->firmware_ulp = axlf; + + return ret; +} + +static int bitstream_axlf_ioctl(struct xmgmt_main *xmm, const void __user *arg) +{ + void *copy_buffer = NULL; + size_t copy_buffer_size = 0; + struct xmgmt_ioc_bitstream_axlf ioc_obj = { 0 }; + struct axlf xclbin_obj = { {0} }; + int ret = 0; + + if (copy_from_user((void *)&ioc_obj, arg, sizeof(ioc_obj))) + return -EFAULT; + if (copy_from_user((void *)&xclbin_obj, ioc_obj.xclbin, sizeof(xclbin_obj))) + return -EFAULT; + if (memcmp(xclbin_obj.m_magic, ICAP_XCLBIN_V2, sizeof(ICAP_XCLBIN_V2))) + return -EINVAL; + + copy_buffer_size = xclbin_obj.m_header.m_length; + if (copy_buffer_size > MAX_XCLBIN_SIZE) + return -EINVAL; + copy_buffer = vmalloc(copy_buffer_size); + if (!copy_buffer) + return -ENOMEM; + + if (copy_from_user(copy_buffer, ioc_obj.xclbin, copy_buffer_size)) { + vfree(copy_buffer); + return -EFAULT; + } + + ret = xmgmt_bitstream_axlf_fpga_mgr(xmm, copy_buffer, copy_buffer_size); + if (ret) + vfree(copy_buffer); + + return ret; +} + +static long xmgmt_main_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long result = 0; + struct xmgmt_main *xmm = filp->private_data; + + if (_IOC_TYPE(cmd) != XMGMT_IOC_MAGIC) + return -ENOTTY; + + mutex_lock(&xmm->busy_mutex); + + xrt_info(xmm->pdev, "ioctl cmd %d, arg %ld", cmd, arg); + switch (cmd) { + case XMGMT_IOCICAPDOWNLOAD_AXLF: + result = bitstream_axlf_ioctl(xmm, (const void __user *)arg); + break; + default: + result = -ENOTTY; + break; + } + + mutex_unlock(&xmm->busy_mutex); + return result; +} + +static struct xrt_subdev_endpoints xrt_mgmt_main_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names []){ + { .ep_name = XRT_MD_NODE_MGMT_MAIN }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_subdev_drvdata xmgmt_main_data = { + .xsd_dev_ops = { + .xsd_ioctl = xmgmt_main_leaf_ioctl, + }, + .xsd_file_ops = { + .xsf_ops = { + .owner = THIS_MODULE, + .open = xmgmt_main_open, + .release = xmgmt_main_close, + .unlocked_ioctl = xmgmt_main_ioctl, + }, + .xsf_dev_name = "xmgmt", + }, +}; + +static const struct platform_device_id xmgmt_main_id_table[] = { + { XMGMT_MAIN, (kernel_ulong_t)&xmgmt_main_data }, + { }, +}; + +static struct platform_driver xmgmt_main_driver = { + .driver = { + .name = XMGMT_MAIN, + }, + .probe = xmgmt_main_probe, + .remove = xmgmt_main_remove, + .id_table = xmgmt_main_id_table, +}; + +int xmgmt_main_register_leaf(void) +{ + return xleaf_register_driver(XRT_SUBDEV_MGMT_MAIN, + &xmgmt_main_driver, xrt_mgmt_main_endpoints); +} + +void xmgmt_main_unregister_leaf(void) +{ + xleaf_unregister_driver(XRT_SUBDEV_MGMT_MAIN); +} diff --git a/include/uapi/linux/xrt/xmgmt-ioctl.h b/include/uapi/linux/xrt/xmgmt-ioctl.h new file mode 100644 index 000000000000..15834476f3b4 --- /dev/null +++ b/include/uapi/linux/xrt/xmgmt-ioctl.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2015-2021, Xilinx Inc + * + */ + +/** + * DOC: PCIe Kernel Driver for Managament Physical Function + * Interfaces exposed by *xclmgmt* driver are defined in file, *mgmt-ioctl.h*. + * Core functionality provided by *xmgmt* driver is described in the following table: + * + * =========== ============================== ================================== + * Functionality ioctl request code data format + * =========== ============================== ================================== + * 1 FPGA image download XMGMT_IOCICAPDOWNLOAD_AXLF xmgmt_ioc_bitstream_axlf + * =========== ============================== ================================== + */ + +#ifndef _XMGMT_IOCTL_H_ +#define _XMGMT_IOCTL_H_ + +#include + +#define XMGMT_IOC_MAGIC 'X' +#define XMGMT_IOC_ICAP_DOWNLOAD_AXLF 0x6 + +/** + * struct xmgmt_ioc_bitstream_axlf - load xclbin (AXLF) device image + * used with XMGMT_IOCICAPDOWNLOAD_AXLF ioctl + * + * @xclbin: Pointer to user's xclbin structure in memory + */ +struct xmgmt_ioc_bitstream_axlf { + struct axlf *xclbin; +}; + +#define XMGMT_IOCICAPDOWNLOAD_AXLF \ + _IOW(XMGMT_IOC_MAGIC, XMGMT_IOC_ICAP_DOWNLOAD_AXLF, struct xmgmt_ioc_bitstream_axlf) + +/* + * The following definitions are for binary compatibility with classic XRT management driver + */ +#define XCLMGMT_IOCICAPDOWNLOAD_AXLF XMGMT_IOCICAPDOWNLOAD_AXLF +#define xclmgmt_ioc_bitstream_axlf xmgmt_ioc_bitstream_axlf + +#endif From patchwork Thu Feb 18 06:40:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384525 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 04C15C433DB for ; Thu, 18 Feb 2021 06:55:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A8F2164E68 for ; Thu, 18 Feb 2021 06:55:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230138AbhBRGyb (ORCPT ); Thu, 18 Feb 2021 01:54:31 -0500 Received: from mail-mw2nam12on2074.outbound.protection.outlook.com ([40.107.244.74]:54657 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S231208AbhBRGss (ORCPT ); Thu, 18 Feb 2021 01:48:48 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=iOeiOahZjPtDa2hzj6riNRUmRxoHldS1oS0BiBXmxlV+SRuA9bxSNvtlB+iFLLihPxJ+6ghdir/Z2y1qU7A/m1/9kKp+iRqVj24j7mzPx7NWRn83SpImZVd7KAXZzCiAWY7yqIByNXW/fzRa3sndPBkmkHKAJ9FJe4aOjosmZHyUu3u0vYsY9idPBPzri7qpRjZWb4ixn7aUWjQWYK7CnXoD6scH5PW7iPpLDl4oDd5ladJVnAoLBPvOt2Yi/umbBB7goSch8xQkceTmxFzw41gY+7KJnBe1w3F+6FID00B/o0OIttHswndiCjR4uO3iAgvRj4vFowslSzJxWhwO/A== 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=opoz9l2kxQpDO37rCGk39sXMeyyCo/WAwug4x0FIuVo=; b=haOrkcQe0I7jygANzpP97MKIujtiG3ggFhWqu2CE21CR7j42lgFDN4gnpMOS852u4uFW7JrDitYkyWuPkFN2UOXYL2fkiPaYyVoKIp7024G03GaQC7huGIgh9iwwVdWOOTT2FNyRTHXfuByVcsmJjaYoTPivIm67O6a2wM1pItromRfj66hVtTMKdbWLGz42l+N1oLZXuvCJrDisEgP7t7Ia9u0dXKj6zJ46Z/o4WlueC8St1lzkDJlwX7g45vCKvMBXSYJhUFf5MUfN6tdwVMcep6J4rvNKgyf0BKiNokL4AUM0OmoYuES3cTkTKrxb2qqiIoBt8timGtEb6R4f+Q== 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=bestguesspass 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=opoz9l2kxQpDO37rCGk39sXMeyyCo/WAwug4x0FIuVo=; b=eQ/TWyFp3V4csAnY0Q8Yylvl8iHfYAvoDX7AYKz7e068DsFUr1FcWbzJvlN3WPg/IBOkbdReyvmRM9LEEkhwVQCioIw703CppJPPdLy4iiw7OFFUptf5dMpFmXW+u95kc2GXXlgXYShPsH/ea98NtxcCYLldCxAhf6DgUhAVfCk= Received: from DS7PR03CA0062.namprd03.prod.outlook.com (2603:10b6:5:3bb::7) by DM5PR02MB3387.namprd02.prod.outlook.com (2603:10b6:4:6a::35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.29; Thu, 18 Feb 2021 06:45:40 +0000 Received: from CY1NAM02FT033.eop-nam02.prod.protection.outlook.com (2603:10b6:5:3bb:cafe::49) by DS7PR03CA0062.outlook.office365.com (2603:10b6:5:3bb::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:45:40 +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=bestguesspass 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 CY1NAM02FT033.mail.protection.outlook.com (10.152.75.179) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:45:39 +0000 Received: from xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) 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.1913.5; Wed, 17 Feb 2021 22:45:28 -0800 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server id 15.1.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:45:28 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40186 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd44-00023N-1F; Wed, 17 Feb 2021 22:45:28 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 6CB38600129; Wed, 17 Feb 2021 22:41:06 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 13/18] fpga: xrt: devctl platform driver Date: Wed, 17 Feb 2021 22:40:14 -0800 Message-ID: <20210218064019.29189-14-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: cce6435f-9d32-4b1a-7973-08d8d3d8ce45 X-MS-TrafficTypeDiagnostic: DM5PR02MB3387: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1303; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: CwZ35hPs1EZ/cN/xqQGb4z+9F0Hx27JnXIUoC5+uDXsIX17mp/sEXK/SEIH3JfacbUPKTue5/ZiGZQxdOENFNA/f91l11Y/AEuW494BLI9xgBwYpD9W9Efy3I2SKCF0RBAxaa7XGZo3KEl1QQ4X3kjYp1cNON/ERi+gCKevmd7fHSIncHeq6kXLEfZqicJF/fiqUpiK9jVjaM5JYvS9Cv6Pqpe5x8nIRhMyh4DtaFv6M88sWYIlAdpuFOArbpX7jfL7mtr+sifxl63GeX83Bhsn5K1c/oePaGT/lscDWOFiyGwI+mT+AsZxO3nH7YTcS4AgSMOscFv54mskeXPVY4DG1v2ax90jF/Ec6zlfMzIWYmtr3ycrQ8bkEO/WIp/94cmtzcrZz41GrsOeebQ8rYGSfyg40M5Gmwnjq3XXJ4gEhgGnFN7W++vivTJ3XG6nXjsUGIeEL5CXtFHjd9Iyw5yteeKZ9trcLoor7+tvm2QqssEpN68bnWpZfraHJbyNomvNVBT8YRfMFXgM0yDL2rfLUWA8t68E/XzE/c6fSBbwF3Ow6PmauYFHlQBdbs1f/3G+zNhWgJs4w5t9BokNKVmo/o7q7og2Iht9ZsOw5fqD3s3RrPbfArPlablwBejShLf3W5MggRFyasFcQ8TQCamjKG7+UgW1KH8ZuuTFud1o= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(376002)(396003)(346002)(39860400002)(136003)(36840700001)(46966006)(26005)(2616005)(6666004)(44832011)(36860700001)(426003)(336012)(186003)(4326008)(54906003)(82740400003)(356005)(1076003)(82310400003)(8936002)(5660300002)(70586007)(7636003)(36906005)(8676002)(6266002)(478600001)(42186006)(107886003)(36756003)(6916009)(316002)(47076005)(2906002)(70206006); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:45:39.9351 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: cce6435f-9d32-4b1a-7973-08d8d3d8ce45 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: CY1NAM02FT033.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR02MB3387 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 --- drivers/fpga/xrt/include/xleaf/devctl.h | 43 +++++ drivers/fpga/xrt/lib/xleaf/devctl.c | 206 ++++++++++++++++++++++++ 2 files changed, 249 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..96a40e066f83 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/devctl.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for XRT DEVCTL Leaf Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_DEVCTL_H_ +#define _XRT_DEVCTL_H_ + +#include "xleaf.h" + +/* + * DEVCTL driver IOCTL calls. + */ +enum xrt_devctl_ioctl_cmd { + XRT_DEVCTL_READ = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_DEVCTL_WRITE, +}; + +enum xrt_devctl_id { + XRT_DEVCTL_ROM_UUID, + XRT_DEVCTL_DDR_CALIB, + XRT_DEVCTL_GOLDEN_VER, + XRT_DEVCTL_MAX +}; + +struct xrt_devctl_ioctl_rw { + u32 xgir_id; + void *xgir_buf; + u32 xgir_len; + u32 xgir_offset; +}; + +struct xrt_devctl_ioctl_intf_uuid { + u32 xgir_uuid_num; + uuid_t *xgir_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..caf8c6569f0f --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/devctl.c @@ -0,0 +1,206 @@ +// 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 "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 }, +}; + +struct xrt_devctl { + struct platform_device *pdev; + void __iomem *base_addrs[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_ioctl(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_ioctl_rw *rw_arg = arg; + u32 *p_src, *p_dst, i; + + if (rw_arg->xgir_len & 0x3) { + xrt_err(pdev, "invalid len %d", rw_arg->xgir_len); + return -EINVAL; + } + + if (rw_arg->xgir_id >= XRT_DEVCTL_MAX) { + xrt_err(pdev, "invalid id %d", rw_arg->xgir_id); + return -EINVAL; + } + + p_src = devctl->base_addrs[rw_arg->xgir_id]; + if (!p_src) { + xrt_err(pdev, "io not found, id %d", + rw_arg->xgir_id); + return -EINVAL; + } + if (rw_arg->xgir_offset + rw_arg->xgir_len > + devctl->sizes[rw_arg->xgir_id]) { + xrt_err(pdev, "invalid argument, off %d, len %d", + rw_arg->xgir_offset, rw_arg->xgir_len); + return -EINVAL; + } + p_dst = rw_arg->xgir_buf; + for (i = 0; i < rw_arg->xgir_len / sizeof(u32); i++) { + u32 val = ioread32(p_src + rw_arg->xgir_offset + i); + + memcpy(p_dst + i, &val, sizeof(u32)); + } + break; + } + default: + xrt_err(pdev, "unsupported cmd %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int xrt_devctl_remove(struct platform_device *pdev) +{ + struct xrt_devctl *devctl; + int i; + + devctl = platform_get_drvdata(pdev); + + for (i = 0; i < XRT_DEVCTL_MAX; i++) { + if (devctl->base_addrs[i]) + iounmap(devctl->base_addrs[i]); + } + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, devctl); + + return 0; +} + +static int xrt_devctl_probe(struct platform_device *pdev) +{ + struct xrt_devctl *devctl; + int i, id, ret = 0; + struct resource *res; + + 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)) { + id = xrt_devctl_name2id(devctl, res->name); + if (id < 0) { + xrt_err(pdev, "ep %s not found", res->name); + continue; + } + devctl->base_addrs[id] = ioremap(res->start, res->end - res->start + 1); + if (!devctl->base_addrs[id]) { + xrt_err(pdev, "map base failed %pR", res); + ret = -EIO; + goto failed; + } + devctl->sizes[id] = res->end - res->start + 1; + } + +failed: + if (ret) + xrt_devctl_remove(pdev); + + 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_ioctl = xrt_devctl_leaf_ioctl, + }, +}; + +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, + .remove = xrt_devctl_remove, + .id_table = xrt_devctl_table, +}; + +void devctl_leaf_init_fini(bool init) +{ + if (init) + xleaf_register_driver(XRT_SUBDEV_DEVCTL, &xrt_devctl_driver, xrt_devctl_endpoints); + else + xleaf_unregister_driver(XRT_SUBDEV_DEVCTL); +} From patchwork Thu Feb 18 06:40:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384524 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 64701C433DB for ; Thu, 18 Feb 2021 06:56:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 01B4764E68 for ; Thu, 18 Feb 2021 06:56:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230523AbhBRGy6 (ORCPT ); Thu, 18 Feb 2021 01:54:58 -0500 Received: from mail-mw2nam12on2061.outbound.protection.outlook.com ([40.107.244.61]:15584 "EHLO NAM12-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S231231AbhBRGsv (ORCPT ); Thu, 18 Feb 2021 01:48:51 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FHvIM24G8NBnSgwL4Le+getJ2mBVIEaCkYhf+LUgrUkJkOn5lfWKzM6fgDoWA44SFxzdLqBqVYQhCqKOjaEz6nDzCNF6wJjcl27nLisQ0pZ/kujBIOVJe4dHzPOK4l0kILpBPsRaxJ8Poe3qcclh0x69uYM11xJXj62LNBU9KHHrrF12kfTsMGdS2rjdzp21sUEk/97cdndastFqeIIdljNESlNH9nnVUZRE/sXk2EmB6k839SGSkfL6TstdHfUeAUtSDaLfmRFDQf5tlEOnDS6ku04sn065sPPPBp+U2NIq+l1fJMwHWv6ujcz5C3JiRjuuml8N+aTK1nJuXZlkmg== 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=Fleb1iBzWsGyuP1NKtPAbxh0lsXBFDXwdSCSN3VjQjI=; b=BzAx9ilRgMYbv4dJFuVOr5FB2eyPsiBJlpqTdwjBBjDqyh6Hi4uA6LBrNi8Mm1qytdI0Qjp4gzc/1pwrVDZeO6zf4fJWAhLBbCHj+yM9jC+h6scpGaEqk+U0YXr64vJf6z875AZS9snkpjGOc1Ohm4TmwB04tJgPesgxbMH8eHhbyiFKIBqt5MXFDOzeu8pZOTWidGIo/tfmz+qrd+tj7R9YMKlVWNanQ7AQoehPRwVDY1nHGAwctf1ahPSX0YpK7zmUxWDppiGXDpszvx2WbynGHJ34Kq7x1QK4Mz3X3fyaZ8OKEypminyOY3O8QRsiLy7ekz654ABLCA8BcKVXEQ== 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=bestguesspass 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=Fleb1iBzWsGyuP1NKtPAbxh0lsXBFDXwdSCSN3VjQjI=; b=JMyhezEpGvvhZRSKrEXTUz3PH8SKM2B8J3t4a3SxClI5bMTNk3mxMYOl/yKiTxExGz8eE7eL2p6XY1p2XK5I0CVLbCtBbTb/TrzH8H5sAdHXbG2puDlP36FpteB6nPwI3SAOX83ynzYg0u/gzVmtDDpYmBLVM1Ip1LiLCrvVNDE= Received: from CY4PR13CA0046.namprd13.prod.outlook.com (2603:10b6:903:99::32) by SN6PR02MB5536.namprd02.prod.outlook.com (2603:10b6:805:f0::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.31; Thu, 18 Feb 2021 06:45:49 +0000 Received: from CY1NAM02FT051.eop-nam02.prod.protection.outlook.com (2603:10b6:903:99:cafe::79) by CY4PR13CA0046.outlook.office365.com (2603:10b6:903:99::32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.12 via Frontend Transport; Thu, 18 Feb 2021 06:45:49 +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=bestguesspass 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 CY1NAM02FT051.mail.protection.outlook.com (10.152.74.148) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:45:49 +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.1913.5; Wed, 17 Feb 2021 22:45:40 -0800 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.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:45:40 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40188 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd4G-0000l4-2o; Wed, 17 Feb 2021 22:45:40 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 795F860012B; Wed, 17 Feb 2021 22:41:06 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 14/18] fpga: xrt: clock platform driver Date: Wed, 17 Feb 2021 22:40:15 -0800 Message-ID: <20210218064019.29189-15-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 6cb7b324-7a25-4f19-4911-08d8d3d8d3e0 X-MS-TrafficTypeDiagnostic: SN6PR02MB5536: 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: Q7wdU5+kUoyB8Z+fjIyCkpYXwI297eol5QnHU+v54UnXHtHIs1CVE3DgHY4Vf7wKHw3Xhrg6itSEsGSOygUrftz668KKo9m9Gx/SffIKDgrRatbZ9Z/Zn7KqDUid8sPT01hm91tWvWcZimXB0HUCHiFyNcYI9Tl60VeOm4IoIZ8cIUy/DVttEsl7e2RC02TXRNLNpOXL+T+12p5O4QcTvr3USMHXYni0aZhOBNLY0OSQVE3Tsmdpv1uFaf+01BbPuCqhFgFwV2pHc8jPlLPRIz1qjFh6TGeVlBQFHUCE7+FH5TOXwci5ZHb767VZplUl/GZHhu/6G2N+CQBfupdvduq1KN8/oZrhA/1YJVF7Fd0l5YWhxByAfHC9r/ac0qLbYa/3EB4/huEor8PwkMzgN4JkbceBaV12ZDipSBCx3buC0n5cHVVVsGtAJWXznv8x2Nc3e8tZaAvTV2nBOLxyu16EeBLeKXmyZJej8/cH2Dm2eOwe3KmHS2cXoioWZ81PrBovq+JVNYA0b5wXGKu26BB3pjCnEcpUl35cNS/FA1XeOWXbwO6l05A605XTsMggSPwUNy6mze/zgnW29yH83vWSOMf1vGCW1A8iEp3U0VY/eOK7HeYD27cpKdrqG9+zCiBAX+v4p2ziIXxU89L19VfC1yao+hrqasoJNFX5nYU= X-Forefront-Antispam-Report: CIP:149.199.62.198; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:xsj-pvapexch02.xlnx.xilinx.com; PTR:unknown-62-198.xilinx.com; CAT:NONE; SFS:(4636009)(346002)(136003)(376002)(396003)(39860400002)(46966006)(36840700001)(316002)(8936002)(70206006)(6666004)(6916009)(6266002)(478600001)(1076003)(336012)(36860700001)(42186006)(36756003)(8676002)(2616005)(83380400001)(54906003)(2906002)(30864003)(107886003)(36906005)(82740400003)(4326008)(70586007)(47076005)(426003)(82310400003)(356005)(7636003)(5660300002)(44832011)(26005)(186003); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:45:49.3389 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 6cb7b324-7a25-4f19-4911-08d8d3d8d3e0 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: CY1NAM02FT051.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN6PR02MB5536 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 --- drivers/fpga/xrt/include/xleaf/clock.h | 31 ++ drivers/fpga/xrt/lib/xleaf/clock.c | 648 +++++++++++++++++++++++++ 2 files changed, 679 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..a2da59b32551 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/clock.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for XRT Clock Leaf Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_CLOCK_H_ +#define _XRT_CLOCK_H_ + +#include "xleaf.h" +#include + +/* + * CLOCK driver IOCTL calls. + */ +enum xrt_clock_ioctl_cmd { + XRT_CLOCK_SET = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ + XRT_CLOCK_GET, + XRT_CLOCK_VERIFY, +}; + +struct xrt_clock_ioctl_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..a067b501a607 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/clock.c @@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Clock Wizard Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + * Sonal Santan + * David Zhang + */ + +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/clock.h" +#include "xleaf/clkfreq.h" + +/* CLOCK_MAX_NUM_CLOCKS should be a concept from XCLBIN_ in the future */ +#define CLOCK_MAX_NUM_CLOCKS 4 +#define OCL_CLKWIZ_STATUS_OFFSET 0x4 +#define OCL_CLKWIZ_STATUS_MASK 0xffff +#define OCL_CLKWIZ_STATUS_MEASURE_START 0x1 +#define OCL_CLKWIZ_STATUS_MEASURE_DONE 0x2 +#define OCL_CLKWIZ_CONFIG_OFFSET(n) (0x200 + 4 * (n)) +#define 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" + +struct clock { + struct platform_device *pdev; + void __iomem *clock_base; + 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 wiz.pl. + */ +static const struct xmgmt_ocl_clockwiz { + /* target frequency */ + unsigned short ocl; + /* config0 register */ + unsigned long config0; + /* config2 register */ + unsigned int config2; +} frequency_table[] = { + {/*1275.000*/ 10.000, 0x02EE0C01, 0x0001F47F}, + {/*1575.000*/ 15.000, 0x02EE0F01, 0x00000069}, + {/*1600.000*/ 20.000, 0x00001001, 0x00000050}, + {/*1600.000*/ 25.000, 0x00001001, 0x00000040}, + {/*1575.000*/ 30.000, 0x02EE0F01, 0x0001F434}, + {/*1575.000*/ 35.000, 0x02EE0F01, 0x0000002D}, + {/*1600.000*/ 40.000, 0x00001001, 0x00000028}, + {/*1575.000*/ 45.000, 0x02EE0F01, 0x00000023}, + {/*1600.000*/ 50.000, 0x00001001, 0x00000020}, + {/*1512.500*/ 55.000, 0x007D0F01, 0x0001F41B}, + {/*1575.000*/ 60.000, 0x02EE0F01, 0x0000FA1A}, + {/*1462.500*/ 65.000, 0x02710E01, 0x0001F416}, + {/*1575.000*/ 70.000, 0x02EE0F01, 0x0001F416}, + {/*1575.000*/ 75.000, 0x02EE0F01, 0x00000015}, + {/*1600.000*/ 80.000, 0x00001001, 0x00000014}, + {/*1487.500*/ 85.000, 0x036B0E01, 0x0001F411}, + {/*1575.000*/ 90.000, 0x02EE0F01, 0x0001F411}, + {/*1425.000*/ 95.000, 0x00FA0E01, 0x0000000F}, + {/*1600.000*/ 100.000, 0x00001001, 0x00000010}, + {/*1575.000*/ 105.000, 0x02EE0F01, 0x0000000F}, + {/*1512.500*/ 110.000, 0x007D0F01, 0x0002EE0D}, + {/*1437.500*/ 115.000, 0x01770E01, 0x0001F40C}, + {/*1575.000*/ 120.000, 0x02EE0F01, 0x00007D0D}, + {/*1562.500*/ 125.000, 0x02710F01, 0x0001F40C}, + {/*1462.500*/ 130.000, 0x02710E01, 0x0000FA0B}, + {/*1350.000*/ 135.000, 0x01F40D01, 0x0000000A}, + {/*1575.000*/ 140.000, 0x02EE0F01, 0x0000FA0B}, + {/*1450.000*/ 145.000, 0x01F40E01, 0x0000000A}, + {/*1575.000*/ 150.000, 0x02EE0F01, 0x0001F40A}, + {/*1550.000*/ 155.000, 0x01F40F01, 0x0000000A}, + {/*1600.000*/ 160.000, 0x00001001, 0x0000000A}, + {/*1237.500*/ 165.000, 0x01770C01, 0x0001F407}, + {/*1487.500*/ 170.000, 0x036B0E01, 0x0002EE08}, + {/*1575.000*/ 175.000, 0x02EE0F01, 0x00000009}, + {/*1575.000*/ 180.000, 0x02EE0F01, 0x0002EE08}, + {/*1387.500*/ 185.000, 0x036B0D01, 0x0001F407}, + {/*1425.000*/ 190.000, 0x00FA0E01, 0x0001F407}, + {/*1462.500*/ 195.000, 0x02710E01, 0x0001F407}, + {/*1600.000*/ 200.000, 0x00001001, 0x00000008}, + {/*1537.500*/ 205.000, 0x01770F01, 0x0001F407}, + {/*1575.000*/ 210.000, 0x02EE0F01, 0x0001F407}, + {/*1075.000*/ 215.000, 0x02EE0A01, 0x00000005}, + {/*1512.500*/ 220.000, 0x007D0F01, 0x00036B06}, + {/*1575.000*/ 225.000, 0x02EE0F01, 0x00000007}, + {/*1437.500*/ 230.000, 0x01770E01, 0x0000FA06}, + {/*1175.000*/ 235.000, 0x02EE0B01, 0x00000005}, + {/*1500.000*/ 240.000, 0x00000F01, 0x0000FA06}, + {/*1225.000*/ 245.000, 0x00FA0C01, 0x00000005}, + {/*1562.500*/ 250.000, 0x02710F01, 0x0000FA06}, + {/*1275.000*/ 255.000, 0x02EE0C01, 0x00000005}, + {/*1462.500*/ 260.000, 0x02710E01, 0x00027105}, + {/*1325.000*/ 265.000, 0x00FA0D01, 0x00000005}, + {/*1350.000*/ 270.000, 0x01F40D01, 0x00000005}, + {/*1512.500*/ 275.000, 0x007D0F01, 0x0001F405}, + {/*1575.000*/ 280.000, 0x02EE0F01, 0x00027105}, + {/*1425.000*/ 285.000, 0x00FA0E01, 0x00000005}, + {/*1450.000*/ 290.000, 0x01F40E01, 0x00000005}, + {/*1475.000*/ 295.000, 0x02EE0E01, 0x00000005}, + {/*1575.000*/ 300.000, 0x02EE0F01, 0x0000FA05}, + {/*1525.000*/ 305.000, 0x00FA0F01, 0x00000005}, + {/*1550.000*/ 310.000, 0x01F40F01, 0x00000005}, + {/*1575.000*/ 315.000, 0x02EE0F01, 0x00000005}, + {/*1600.000*/ 320.000, 0x00001001, 0x00000005}, + {/*1462.500*/ 325.000, 0x02710E01, 0x0001F404}, + {/*1237.500*/ 330.000, 0x01770C01, 0x0002EE03}, + {/*837.500*/ 335.000, 0x01770801, 0x0001F402}, + {/*1487.500*/ 340.000, 0x036B0E01, 0x00017704}, + {/*862.500*/ 345.000, 0x02710801, 0x0001F402}, + {/*1575.000*/ 350.000, 0x02EE0F01, 0x0001F404}, + {/*887.500*/ 355.000, 0x036B0801, 0x0001F402}, + {/*1575.000*/ 360.000, 0x02EE0F01, 0x00017704}, + {/*912.500*/ 365.000, 0x007D0901, 0x0001F402}, + {/*1387.500*/ 370.000, 0x036B0D01, 0x0002EE03}, + {/*1500.000*/ 375.000, 0x00000F01, 0x00000004}, + {/*1425.000*/ 380.000, 0x00FA0E01, 0x0002EE03}, + {/*962.500*/ 385.000, 0x02710901, 0x0001F402}, + {/*1462.500*/ 390.000, 0x02710E01, 0x0002EE03}, + {/*987.500*/ 395.000, 0x036B0901, 0x0001F402}, + {/*1600.000*/ 400.000, 0x00001001, 0x00000004}, + {/*1012.500*/ 405.000, 0x007D0A01, 0x0001F402}, + {/*1537.500*/ 410.000, 0x01770F01, 0x0002EE03}, + {/*1037.500*/ 415.000, 0x01770A01, 0x0001F402}, + {/*1575.000*/ 420.000, 0x02EE0F01, 0x0002EE03}, + {/*1487.500*/ 425.000, 0x036B0E01, 0x0001F403}, + {/*1075.000*/ 430.000, 0x02EE0A01, 0x0001F402}, + {/*1087.500*/ 435.000, 0x036B0A01, 0x0001F402}, + {/*1375.000*/ 440.000, 0x02EE0D01, 0x00007D03}, + {/*1112.500*/ 445.000, 0x007D0B01, 0x0001F402}, + {/*1575.000*/ 450.000, 0x02EE0F01, 0x0001F403}, + {/*1137.500*/ 455.000, 0x01770B01, 0x0001F402}, + {/*1437.500*/ 460.000, 0x01770E01, 0x00007D03}, + {/*1162.500*/ 465.000, 0x02710B01, 0x0001F402}, + {/*1175.000*/ 470.000, 0x02EE0B01, 0x0001F402}, + {/*1425.000*/ 475.000, 0x00FA0E01, 0x00000003}, + {/*1500.000*/ 480.000, 0x00000F01, 0x00007D03}, + {/*1212.500*/ 485.000, 0x007D0C01, 0x0001F402}, + {/*1225.000*/ 490.000, 0x00FA0C01, 0x0001F402}, + {/*1237.500*/ 495.000, 0x01770C01, 0x0001F402}, + {/*1562.500*/ 500.000, 0x02710F01, 0x00007D03}, + {/*1262.500*/ 505.000, 0x02710C01, 0x0001F402}, + {/*1275.000*/ 510.000, 0x02EE0C01, 0x0001F402}, + {/*1287.500*/ 515.000, 0x036B0C01, 0x0001F402}, + {/*1300.000*/ 520.000, 0x00000D01, 0x0001F402}, + {/*1575.000*/ 525.000, 0x02EE0F01, 0x00000003}, + {/*1325.000*/ 530.000, 0x00FA0D01, 0x0001F402}, + {/*1337.500*/ 535.000, 0x01770D01, 0x0001F402}, + {/*1350.000*/ 540.000, 0x01F40D01, 0x0001F402}, + {/*1362.500*/ 545.000, 0x02710D01, 0x0001F402}, + {/*1512.500*/ 550.000, 0x007D0F01, 0x0002EE02}, + {/*1387.500*/ 555.000, 0x036B0D01, 0x0001F402}, + {/*1400.000*/ 560.000, 0x00000E01, 0x0001F402}, + {/*1412.500*/ 565.000, 0x007D0E01, 0x0001F402}, + {/*1425.000*/ 570.000, 0x00FA0E01, 0x0001F402}, + {/*1437.500*/ 575.000, 0x01770E01, 0x0001F402}, + {/*1450.000*/ 580.000, 0x01F40E01, 0x0001F402}, + {/*1462.500*/ 585.000, 0x02710E01, 0x0001F402}, + {/*1475.000*/ 590.000, 0x02EE0E01, 0x0001F402}, + {/*1487.500*/ 595.000, 0x036B0E01, 0x0001F402}, + {/*1575.000*/ 600.000, 0x02EE0F01, 0x00027102}, + {/*1512.500*/ 605.000, 0x007D0F01, 0x0001F402}, + {/*1525.000*/ 610.000, 0x00FA0F01, 0x0001F402}, + {/*1537.500*/ 615.000, 0x01770F01, 0x0001F402}, + {/*1550.000*/ 620.000, 0x01F40F01, 0x0001F402}, + {/*1562.500*/ 625.000, 0x02710F01, 0x0001F402}, + {/*1575.000*/ 630.000, 0x02EE0F01, 0x0001F402}, + {/*1587.500*/ 635.000, 0x036B0F01, 0x0001F402}, + {/*1600.000*/ 640.000, 0x00001001, 0x0001F402}, + {/*1290.000*/ 645.000, 0x01F44005, 0x00000002}, + {/*1462.500*/ 650.000, 0x02710E01, 0x0000FA02} +}; + +static inline u32 reg_rd(struct clock *clock, u32 offset) +{ + return ioread32(clock->clock_base + offset); +} + +static inline void reg_wr(struct clock *clock, u32 val, u32 offset) +{ + iowrite32(val, clock->clock_base + offset); +} + +static u32 find_matching_freq_config(unsigned short freq, + const struct xmgmt_ocl_clockwiz *table, + int size) +{ + u32 start = 0; + u32 end = size - 1; + u32 idx = size - 1; + + if (freq < table[0].ocl) + return 0; + + if (freq > table[size - 1].ocl) + return size - 1; + + while (start < end) { + if (freq == table[idx].ocl) + break; + if (freq < table[idx].ocl) + end = idx; + else + start = idx + 1; + idx = start + (end - start) / 2; + } + 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; + + val = reg_rd(clock, OCL_CLKWIZ_STATUS_OFFSET); + for (count = 0; val != 1 && count < cycle; count++) { + mdelay(interval); + val = reg_rd(clock, OCL_CLKWIZ_STATUS_OFFSET); + } + if (val != 1) { + CLOCK_ERR(clock, "clockwiz is (%u) busy after %d ms", + val, cycle * interval); + return -ETIMEDOUT; + } + + return 0; +} + +static int get_freq(struct clock *clock, u16 *freq) +{ +#define XCL_INPUT_FREQ 100 + const u64 input = XCL_INPUT_FREQ; + u32 val; + u32 mul0, div0; + u32 mul_frac0 = 0; + u32 div1; + u32 div_frac1 = 0; + + WARN_ON(!mutex_is_locked(&clock->clock_lock)); + + val = reg_rd(clock, OCL_CLKWIZ_STATUS_OFFSET); + if ((val & 0x1) == 0) { + CLOCK_ERR(clock, "clockwiz is busy %x", val); + *freq = 0; + return -EBUSY; + } + + val = reg_rd(clock, OCL_CLKWIZ_CONFIG_OFFSET(0)); + + 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; + + val = reg_rd(clock, OCL_CLKWIZ_CONFIG_OFFSET(2)); + + 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; + } + + *freq = (u16)((input * mul0) / div0); + + return 0; +} + +static int set_freq(struct clock *clock, u16 freq) +{ + u32 config; + int err; + u32 idx = 0; + u32 val; + + WARN_ON(!mutex_is_locked(&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) + return -EBUSY; + + config = frequency_table[idx].config0; + reg_wr(clock, config, OCL_CLKWIZ_CONFIG_OFFSET(0)); + + config = frequency_table[idx].config2; + reg_wr(clock, config, OCL_CLKWIZ_CONFIG_OFFSET(2)); + + mdelay(10); + reg_wr(clock, 7, OCL_CLKWIZ_CONFIG_OFFSET(23)); + + mdelay(1); + reg_wr(clock, 2, OCL_CLKWIZ_CONFIG_OFFSET(23)); + + 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 */ + reg_wr(clock, 4, OCL_CLKWIZ_CONFIG_OFFSET(23)); + mdelay(10); + reg_wr(clock, 0, OCL_CLKWIZ_CONFIG_OFFSET(23)); + return err; + } + val = reg_rd(clock, OCL_CLKWIZ_CONFIG_OFFSET(0)); + CLOCK_INFO(clock, "clockwiz CONFIG(0) 0x%x", val); + val = reg_rd(clock, OCL_CLKWIZ_CONFIG_OFFSET(2)); + CLOCK_INFO(clock, "clockwiz CONFIG(2) 0x%x", val); + + return 0; +} + +static int get_freq_counter(struct clock *clock, u32 *freq) +{ + const void *cnter; + struct platform_device *cnter_leaf; + struct platform_device *pdev = clock->pdev; + struct xrt_subdev_platdata *pdata = DEV_PDATA(clock->pdev); + int err = xrt_md_get_prop(DEV(pdev), pdata->xsp_dtb, + clock->clock_ep_name, NULL, XRT_MD_PROP_CLK_CNT, &cnter, NULL); + + WARN_ON(!mutex_is_locked(&clock->clock_lock)); + + if (err) { + xrt_err(pdev, "no counter specified"); + return err; + } + + cnter_leaf = xleaf_get_leaf_by_epname(pdev, cnter); + if (!cnter_leaf) { + xrt_err(pdev, "can't find counter"); + return -ENOENT; + } + + err = xleaf_ioctl(cnter_leaf, XRT_CLKFREQ_READ, freq); + if (err) + xrt_err(pdev, "can't read counter"); + xleaf_put_leaf(clock->pdev, cnter_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_set_freq(struct clock *clock, u16 freq) +{ + int err; + + mutex_lock(&clock->clock_lock); + err = set_freq(clock, freq); + mutex_unlock(&clock->clock_lock); + + return err; +} + +static int clock_verify_freq(struct clock *clock) +{ + int err = 0; + u16 freq; + u32 lookup_freq, clock_freq_counter, request_in_khz, tolerance; + + 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); + int err = 0; + const u16 *freq; + + 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; + } + + mutex_lock(&clock->clock_lock); + err = set_freq(clock, be16_to_cpu(*freq)); + mutex_unlock(&clock->clock_lock); + + 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)); + u16 freq = 0; + ssize_t count; + + count = clock_get_freq(clock, &freq, NULL); + if (count < 0) + return count; + + count = snprintf(buf, 64, "%d\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_ioctl(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 = clock_set_freq(clock, freq); + break; + } + case XRT_CLOCK_VERIFY: { + ret = clock_verify_freq(clock); + break; + } + case XRT_CLOCK_GET: { + struct xrt_clock_ioctl_get *get = + (struct xrt_clock_ioctl_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) +{ + struct clock *clock; + + clock = platform_get_drvdata(pdev); + if (!clock) { + xrt_err(pdev, "driver data is NULL"); + return -EINVAL; + } + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, clock); + + CLOCK_INFO(clock, "successfully removed Clock subdev"); + return 0; +} + +static int clock_probe(struct platform_device *pdev) +{ + struct clock *clock = 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); + clock->clock_base = ioremap(res->start, res->end - res->start + 1); + if (!clock->clock_base) { + CLOCK_ERR(clock, "map base %pR failed", res); + ret = -EFAULT; + 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: + clock_remove(pdev); + 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_ioctl = xrt_clock_leaf_ioctl, + }, +}; + +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, +}; + +void clock_leaf_init_fini(bool init) +{ + if (init) + xleaf_register_driver(XRT_SUBDEV_CLOCK, &xrt_clock_driver, xrt_clock_endpoints); + else + xleaf_unregister_driver(XRT_SUBDEV_CLOCK); +} From patchwork Thu Feb 18 06:40:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384523 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 ED64FC433DB for ; Thu, 18 Feb 2021 07:11:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 86D1660241 for ; Thu, 18 Feb 2021 07:11:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230219AbhBRHJf (ORCPT ); Thu, 18 Feb 2021 02:09:35 -0500 Received: from mail-eopbgr750080.outbound.protection.outlook.com ([40.107.75.80]:4595 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S231168AbhBRHGc (ORCPT ); Thu, 18 Feb 2021 02:06:32 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=XU83QVmHw/+b5aZ5zbpws8Bhicna70TcbLCqCSkrQoKIthAnvckM0vbd15nW8hA+ZWHtpi9skbvZvQz0uQC7toWPVUbSqTtswf9TJSzS8hirLJoFuXRbHSe2Yce4/Tfw6xwZtT9rpZwwp5hh/pd2pjC6kVJ46hKL2nv5deltJ+u6KpvxeXQ9ErHsCpDiVm9OntE8hev03RbT+J9xezlOOXIFynaCaBFr9fZWLADJt8fz/A4Nw/cs0xLPZXwt6xMCjopiftzbsYDcUrSgpgiE9S/J/EfXtkmafhrPGek7R8fEeFp5EDnLEi61WGay0bhlNIWS9VHwVMKi9W5szexxPw== 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=0ZbFw/MxoWUpkZPb7ssXG+bPJeJnI1EaYLGzo96kVag=; b=h7Dv0P40q1KIa32Pv62P+35unhYgwDBc+3Mu/XOnEPFTUbx1dKjS0JNlFwqkIhDtrcVs0hYL95inQ29gJGZuB/JIvNbyd9XwTxkWprAiDlqCAR0x8ObQDuRVy0Pp4GjVJHt8brLlax7Ho9w8yNU+bLtyyD/QARxf0gT8b7LfOq1PwB8fRrYmkSzeALCLdKORrKxA15UnER3B1lQSCYoYINSv4gmFODJUJZKGj+XhPBr4tA4Vr7WgZTiyqV1jwWgwPsM6t7bsAkkzs3d+ZZJSEsYdkdJW64UUpQyCz+K2KaoRiLM7bNUkSQ61udAcFsPzN7bLq86Feje8v89RgYbjmA== 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=bestguesspass 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=0ZbFw/MxoWUpkZPb7ssXG+bPJeJnI1EaYLGzo96kVag=; b=KhzzO5RaHET/boTRMY9RvrN9lU7BvxCFsAaYbLZMSWlfYaTlvhjcsDhTs2HjYZL+Q3y2xaV+haLEM10iY6AHVMl0hxpR5l50hOt04SV3SAk6yE8DyUc5ixRgNGlx1ztQl++mMugfRGkY4Y7mkxTKK5zgWT+XmBHvAkFLs9FGDeM= Received: from MN2PR04CA0015.namprd04.prod.outlook.com (2603:10b6:208:d4::28) by BYAPR02MB4005.namprd02.prod.outlook.com (2603:10b6:a02:f8::29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27; Thu, 18 Feb 2021 06:45:53 +0000 Received: from BL2NAM02FT036.eop-nam02.prod.protection.outlook.com (2603:10b6:208:d4:cafe::bb) by MN2PR04CA0015.outlook.office365.com (2603:10b6:208:d4::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:45:53 +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=bestguesspass 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 BL2NAM02FT036.mail.protection.outlook.com (10.152.77.154) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:45:52 +0000 Received: from xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) 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.1913.5; Wed, 17 Feb 2021 22:45:52 -0800 Received: from smtp.xilinx.com (172.19.127.96) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server id 15.1.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:45:52 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40190 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd4S-0000mR-48; Wed, 17 Feb 2021 22:45:52 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id 96C4760012E; Wed, 17 Feb 2021 22:41:06 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 15/18] fpga: xrt: clock frequence counter platform driver Date: Wed, 17 Feb 2021 22:40:16 -0800 Message-ID: <20210218064019.29189-16-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 2b0e9a2b-9231-4ccc-6c47-08d8d3d8d615 X-MS-TrafficTypeDiagnostic: BYAPR02MB4005: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:8882; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: XY3aK/joJC42LeIRq8HI2gxzPxQyGyzQlEFP/XDdjxejd1gJBP+51NJVKZ/a4XcZ1puYUQ2eqRkeNTPBSkOzl+GiSamWMHoPbgEUPF3xJcFg3mYuh/KQbXqu75QLdz7g/BFZj3BKvKHiML+U0F1RLvQvWlVrx6L7GeafToK7VjsXDc0VDfXSqfSXKo5V6nWye3CqB80g2j3CUonHu2/lGRIYy20l0Vef/CgkqsKRhwoGSA2PLIkRHi4m2Cq8UKWTgIrzKlxl1kJASqj5jj2wjXEr3ZDtUOxb/cedX1WsWl+6YoriaTe4ljuW8nqk6hu78WGjk/R6Lyn1P2Bv06lUzagjYiRY9q2TxU/lrtYfUxo2Jt98cot4SWJP7TLFkFQlS9QdKj72qcmIy5XQivZtxYbk6Aon9nvhSkY4fnZVD+v3yPeXQAQHVdThfb7ozxGBWcNfF1EwpTvky6YgIPVzZ7NQ5Z/HpkBMMtjxeB6UeI5+WZC4aYn+zXLkx64iNNhGIEjP0xbOF+tU/rqozM0sutvdhV+ttfPhSREm3S//7U0ZeDfIYNazFrdcwcn/kwLbJBOw4WBbmzSSQsRuu0jKF6ALiWBqWURzxK+c0HcNjVrm9+wFNUa2V0ME3frextjFhWl3gIF26u1BDUJSivLmkn9aIHiU0C03tFiJ8m0jGY4= 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)(136003)(346002)(396003)(376002)(46966006)(36840700001)(26005)(47076005)(186003)(2906002)(82310400003)(7636003)(70206006)(70586007)(6916009)(36756003)(83380400001)(36860700001)(107886003)(8676002)(4326008)(8936002)(6266002)(82740400003)(478600001)(356005)(36906005)(2616005)(6666004)(336012)(426003)(1076003)(54906003)(42186006)(316002)(5660300002)(44832011); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:45:52.9620 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 2b0e9a2b-9231-4ccc-6c47-08d8d3d8d615 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: BL2NAM02FT036.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB4005 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add clock frequence counter driver. Clock frequence counter is a hardware function discovered by walking xclbin metadata. A platform device node will be created for it. Other part of driver can read the actual clock frequence through clock frequence counter driver. Signed-off-by: Sonal Santan Signed-off-by: Max Zhen Signed-off-by: Lizhi Hou --- drivers/fpga/xrt/include/xleaf/clkfreq.h | 23 +++ drivers/fpga/xrt/lib/xleaf/clkfreq.c | 221 +++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/clkfreq.h create mode 100644 drivers/fpga/xrt/lib/xleaf/clkfreq.c diff --git a/drivers/fpga/xrt/include/xleaf/clkfreq.h b/drivers/fpga/xrt/include/xleaf/clkfreq.h new file mode 100644 index 000000000000..29fc45e8a31b --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/clkfreq.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for XRT Clock Counter Leaf Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#ifndef _XRT_CLKFREQ_H_ +#define _XRT_CLKFREQ_H_ + +#include "xleaf.h" + +/* + * CLKFREQ driver IOCTL calls. + */ +enum xrt_clkfreq_ioctl_cmd { + XRT_CLKFREQ_READ = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ +}; + +#endif /* _XRT_CLKFREQ_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/clkfreq.c b/drivers/fpga/xrt/lib/xleaf/clkfreq.c new file mode 100644 index 000000000000..2482dd2cff47 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/clkfreq.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Alveo FPGA Clock Frequency Counter Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Lizhi Hou + */ + +#include +#include +#include +#include +#include +#include "metadata.h" +#include "xleaf.h" +#include "xleaf/clkfreq.h" + +#define CLKFREQ_ERR(clkfreq, fmt, arg...) \ + xrt_err((clkfreq)->pdev, fmt "\n", ##arg) +#define CLKFREQ_WARN(clkfreq, fmt, arg...) \ + xrt_warn((clkfreq)->pdev, fmt "\n", ##arg) +#define CLKFREQ_INFO(clkfreq, fmt, arg...) \ + xrt_info((clkfreq)->pdev, fmt "\n", ##arg) +#define CLKFREQ_DBG(clkfreq, fmt, arg...) \ + xrt_dbg((clkfreq)->pdev, fmt "\n", ##arg) + +#define XRT_CLKFREQ "xrt_clkfreq" + +#define OCL_CLKWIZ_STATUS_MASK 0xffff + +#define OCL_CLKWIZ_STATUS_MEASURE_START 0x1 +#define OCL_CLKWIZ_STATUS_MEASURE_DONE 0x2 +#define OCL_CLK_FREQ_COUNTER_OFFSET 0x8 +#define OCL_CLK_FREQ_V5_COUNTER_OFFSET 0x10 +#define OCL_CLK_FREQ_V5_CLK0_ENABLED 0x10000 + +struct clkfreq { + struct platform_device *pdev; + void __iomem *clkfreq_base; + const char *clkfreq_ep_name; + struct mutex clkfreq_lock; /* clock counter dev lock */ +}; + +static inline u32 reg_rd(struct clkfreq *clkfreq, u32 offset) +{ + return ioread32(clkfreq->clkfreq_base + offset); +} + +static inline void reg_wr(struct clkfreq *clkfreq, u32 val, u32 offset) +{ + iowrite32(val, clkfreq->clkfreq_base + offset); +} + +static u32 clkfreq_read(struct clkfreq *clkfreq) +{ + u32 freq = 0, status; + int times = 10; + + mutex_lock(&clkfreq->clkfreq_lock); + reg_wr(clkfreq, OCL_CLKWIZ_STATUS_MEASURE_START, 0); + while (times != 0) { + status = reg_rd(clkfreq, 0); + if ((status & OCL_CLKWIZ_STATUS_MASK) == + OCL_CLKWIZ_STATUS_MEASURE_DONE) + break; + mdelay(1); + times--; + }; + if (times > 0) { + freq = (status & OCL_CLK_FREQ_V5_CLK0_ENABLED) ? + reg_rd(clkfreq, OCL_CLK_FREQ_V5_COUNTER_OFFSET) : + reg_rd(clkfreq, OCL_CLK_FREQ_COUNTER_OFFSET); + } + mutex_unlock(&clkfreq->clkfreq_lock); + + return freq; +} + +static ssize_t freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct clkfreq *clkfreq = platform_get_drvdata(to_platform_device(dev)); + u32 freq; + ssize_t count; + + freq = clkfreq_read(clkfreq); + count = snprintf(buf, 64, "%d\n", freq); + + return count; +} +static DEVICE_ATTR_RO(freq); + +static struct attribute *clkfreq_attrs[] = { + &dev_attr_freq.attr, + NULL, +}; + +static struct attribute_group clkfreq_attr_group = { + .attrs = clkfreq_attrs, +}; + +static int +xrt_clkfreq_leaf_ioctl(struct platform_device *pdev, u32 cmd, void *arg) +{ + struct clkfreq *clkfreq; + int ret = 0; + + clkfreq = platform_get_drvdata(pdev); + + switch (cmd) { + case XRT_XLEAF_EVENT: + /* Does not handle any event. */ + break; + case XRT_CLKFREQ_READ: { + *(u32 *)arg = clkfreq_read(clkfreq); + break; + } + default: + xrt_err(pdev, "unsupported cmd %d", cmd); + return -EINVAL; + } + + return ret; +} + +static int clkfreq_remove(struct platform_device *pdev) +{ + struct clkfreq *clkfreq; + + clkfreq = platform_get_drvdata(pdev); + if (!clkfreq) { + xrt_err(pdev, "driver data is NULL"); + return -EINVAL; + } + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, clkfreq); + + CLKFREQ_INFO(clkfreq, "successfully removed clkfreq subdev"); + return 0; +} + +static int clkfreq_probe(struct platform_device *pdev) +{ + struct clkfreq *clkfreq = NULL; + struct resource *res; + int ret; + + clkfreq = devm_kzalloc(&pdev->dev, sizeof(*clkfreq), GFP_KERNEL); + if (!clkfreq) + return -ENOMEM; + + platform_set_drvdata(pdev, clkfreq); + clkfreq->pdev = pdev; + mutex_init(&clkfreq->clkfreq_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + clkfreq->clkfreq_base = ioremap(res->start, res->end - res->start + 1); + if (!clkfreq->clkfreq_base) { + CLKFREQ_ERR(clkfreq, "map base %pR failed", res); + ret = -EFAULT; + goto failed; + } + clkfreq->clkfreq_ep_name = res->name; + + ret = sysfs_create_group(&pdev->dev.kobj, &clkfreq_attr_group); + if (ret) { + CLKFREQ_ERR(clkfreq, "create clkfreq attrs failed: %d", ret); + goto failed; + } + + CLKFREQ_INFO(clkfreq, "successfully initialized clkfreq subdev"); + + return 0; + +failed: + clkfreq_remove(pdev); + return ret; +} + +static struct xrt_subdev_endpoints xrt_clkfreq_endpoints[] = { + { + .xse_names = (struct xrt_subdev_ep_names[]) { + { .regmap_name = "freq_cnt" }, + { NULL }, + }, + .xse_min_ep = 1, + }, + { 0 }, +}; + +static struct xrt_subdev_drvdata xrt_clkfreq_data = { + .xsd_dev_ops = { + .xsd_ioctl = xrt_clkfreq_leaf_ioctl, + }, +}; + +static const struct platform_device_id xrt_clkfreq_table[] = { + { XRT_CLKFREQ, (kernel_ulong_t)&xrt_clkfreq_data }, + { }, +}; + +static struct platform_driver xrt_clkfreq_driver = { + .driver = { + .name = XRT_CLKFREQ, + }, + .probe = clkfreq_probe, + .remove = clkfreq_remove, + .id_table = xrt_clkfreq_table, +}; + +void clkfreq_leaf_init_fini(bool init) +{ + if (init) { + xleaf_register_driver(XRT_SUBDEV_CLKFREQ, + &xrt_clkfreq_driver, xrt_clkfreq_endpoints); + } else { + xleaf_unregister_driver(XRT_SUBDEV_CLKFREQ); + } +} From patchwork Thu Feb 18 06:40:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lizhi Hou X-Patchwork-Id: 384522 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 6B180C433E6 for ; Thu, 18 Feb 2021 07:12:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2665A64E68 for ; Thu, 18 Feb 2021 07:12:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230527AbhBRHK2 (ORCPT ); Thu, 18 Feb 2021 02:10:28 -0500 Received: from mail-dm6nam11on2080.outbound.protection.outlook.com ([40.107.223.80]:22789 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229755AbhBRHGy (ORCPT ); Thu, 18 Feb 2021 02:06:54 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=HhivEzbpItUqYImjbzsP0lGd4y1u4oYi6sWhk1xpQLeEcIdG9uiEwPNCOrWzLR3SdHlyjjiTvI9WmmjynMS5FPxCVIAFV2U0lLdfOjsvYgiEpPSZXYZtKVmauq3cd4cRg7V6m0fYhtfLq7x+rrq23QtXMaVWKYsLeXVHFODgIKQltEHUcit6nYHvkOJpx9M4Q6bmtHRER1s2x/Q5MtDge26c3TJ0v1qimS5e6y/3HxwNSDtJY3BBqc7+R2WpYViGckUkGABiC0LVp7Ni6ERSkUnrOb87CVK00LFXPIZAZWTrUArU08STKnjMm8G+JiGChexbGUAoo3m1Lp2fwmqGow== 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=FFmxObRlu7vI6/d49+grAeWEWeE2gFP+5ov7xRE3fJI=; b=WMuI148a5+SEifnFLvtHQX+yFXDtOVhuCvIVxDHsp8sjpfPUy5jAwHoXBm+FCz2RduysjdGArhxqpGo35wzwGGLUUlyx1CrN2YnkI7tWpAKfm3TEUCrxX4yqOKcTGldxDBPHRcaUPbM5jX3faZV6H/9QPx3lJxV7rOym7xWCicK4dxpnPabU/Cul7ZAbzl4dnXuxd42N649ElCsM9jZ5y8CL/M0YLhc1z1ISI7pzWf+H2YXZlYOhEhprsRFWAr/OFAgsxAjmn/GRHBQhOXzXwf03A3Mw0xFs9Rl1JndngRQqvQhVN93imbi53u9sZ0cat5tEorSkr53o7+ATV2eoeg== 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=bestguesspass 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=FFmxObRlu7vI6/d49+grAeWEWeE2gFP+5ov7xRE3fJI=; b=r6+4Sxn0m5kGBALjF1FEoWYh6SxUqm3jDAZDsYD8zntFmuzHjVN+zzJb55vHEmYxWwMr9xsrK956G4H+aJW+VzVkDNljb7cQAd2QrtMLer9EPQYNbbbajd5NuFylDM6mQSAdE/YUyQEW+PTMvXU29ecyRZosR/l7xQ4SZ8pMfhE= Received: from DM5PR18CA0050.namprd18.prod.outlook.com (2603:10b6:3:22::12) by BYAPR02MB4485.namprd02.prod.outlook.com (2603:10b6:a03:58::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3846.31; Thu, 18 Feb 2021 06:46:19 +0000 Received: from CY1NAM02FT052.eop-nam02.prod.protection.outlook.com (2603:10b6:3:22:cafe::c0) by DM5PR18CA0050.outlook.office365.com (2603:10b6:3:22::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:46:18 +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=bestguesspass 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 CY1NAM02FT052.mail.protection.outlook.com (10.152.74.123) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.3868.27 via Frontend Transport; Thu, 18 Feb 2021 06:46:18 +0000 Received: from xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) 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.1913.5; Wed, 17 Feb 2021 22:46:04 -0800 Received: from smtp.xilinx.com (172.19.127.95) by xsj-pvapexch01.xlnx.xilinx.com (172.19.86.40) with Microsoft SMTP Server id 15.1.1913.5 via Frontend Transport; Wed, 17 Feb 2021 22:46:04 -0800 Envelope-to: maxz@xilinx.com, max.zhen@xilinx.com, michal.simek@xilinx.com, sonal.santan@xilinx.com, lizhih@xilinx.com, stefanos@xilinx.com, 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=40192 helo=xsj-xw9400.xilinx.com) by smtp.xilinx.com with esmtp (Exim 4.90) (envelope-from ) id 1lCd4e-0002FY-5r; Wed, 17 Feb 2021 22:46:04 -0800 Received: by xsj-xw9400.xilinx.com (Postfix, from userid 21952) id A44BC60012C; Wed, 17 Feb 2021 22:41:06 -0800 (PST) From: Lizhi Hou To: CC: Lizhi Hou , , , , , , , , , , Max Zhen Subject: [PATCH V3 XRT Alveo 16/18] fpga: xrt: DDR calibration platform driver Date: Wed, 17 Feb 2021 22:40:17 -0800 Message-ID: <20210218064019.29189-17-lizhih@xilinx.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210218064019.29189-1-lizhih@xilinx.com> References: <20210218064019.29189-1-lizhih@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: 420085f0-4c52-4d37-73b3-08d8d3d8e564 X-MS-TrafficTypeDiagnostic: BYAPR02MB4485: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:534; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: DxDsA9LQvhzhD4QE+dND72WDmFrSiGHAQgTrWsEc7XWhrz8KkDnZ0wiJp0gMNWPRaiBLonhilF1p3V6ZDN79yGfklWAnWWyMQc52LDYPQzdRoC0nB3tZ0Nwgys4MCspHyThamHbwDTC7AhQd6oe4k0P8plpSr3MpTQ3qSqO4DvG3d2TWmq4aCWKw8STTrIRbowjLQUu9ZsswjUJ1FPRpR2Wg+/VsW96VULlj2miu+QpYN+At8vTs34NEa3EI2eXiAJVmLOr7dysf8CotV4qM3aVdAG9wLEYvpOxKGJYUzR6nDnFSUYS1Lox6HILBX+OSWm7xOFbM4nOgrtFGmFuZz2/QUHhOKAYr9uEOPpfbrM5MqlmTTnSJuL37YmKhGEU1fO1MVUKMwkbHIDfSx49+89Q0TQiOMlYGFlPNNJm73ywvSVbbwG5dNtZJJ/n5g0dL8Vkd7b+aelSX48iTdMTlPmz6R2iYRS8VmSVI26E/cm3EUKOQLVObS1pDb8Ms4TMMfIWOYx1XuzTMlXDpO5PK1OSLs4fox9LA8Myv4IFdE7+nV3SCnVHn0bjuqMO9ztOcyt3B/nyLT+fesARwxB6uHaf60UdI+GxsQja7X5fvtYb5I1o1b7/H2TvtxjNEGySOLfhPUBu1CkQmGEu51tTMbJZFSJVvkRGoz2AV/2YAdk4= 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)(39860400002)(136003)(396003)(36840700001)(46966006)(44832011)(82310400003)(47076005)(1076003)(426003)(83380400001)(5660300002)(6666004)(2616005)(6266002)(70206006)(316002)(36860700001)(36756003)(107886003)(36906005)(6916009)(336012)(70586007)(42186006)(7636003)(26005)(54906003)(186003)(478600001)(4326008)(356005)(8676002)(8936002)(82740400003)(2906002); DIR:OUT; SFP:1101; X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Feb 2021 06:46:18.7247 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 420085f0-4c52-4d37-73b3-08d8d3d8e564 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: CY1NAM02FT052.eop-nam02.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB4485 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 --- drivers/fpga/xrt/include/xleaf/calib.h | 30 ++++ drivers/fpga/xrt/lib/xleaf/calib.c | 226 +++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 drivers/fpga/xrt/include/xleaf/calib.h create mode 100644 drivers/fpga/xrt/lib/xleaf/calib.c diff --git a/drivers/fpga/xrt/include/xleaf/calib.h b/drivers/fpga/xrt/include/xleaf/calib.h new file mode 100644 index 000000000000..f8aba4594c58 --- /dev/null +++ b/drivers/fpga/xrt/include/xleaf/calib.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for XRT DDR Calibration Leaf Driver + * + * Copyright (C) 2020-2021 Xilinx, Inc. + * + * Authors: + * Cheng Zhen + */ + +#ifndef _XRT_CALIB_H_ +#define _XRT_CALIB_H_ + +#include "xleaf.h" +#include + +/* + * Memory calibration driver IOCTL calls. + */ +enum xrt_calib_results { + XRT_CALIB_UNKNOWN, + XRT_CALIB_SUCCEEDED, + XRT_CALIB_FAILED, +}; + +enum xrt_calib_ioctl_cmd { + XRT_CALIB_RESULT = XRT_XLEAF_CUSTOM_BASE, /* See comments in xleaf.h */ +}; + +#endif /* _XRT_CALIB_H_ */ diff --git a/drivers/fpga/xrt/lib/xleaf/calib.c b/drivers/fpga/xrt/lib/xleaf/calib.c new file mode 100644 index 000000000000..fbb813636e76 --- /dev/null +++ b/drivers/fpga/xrt/lib/xleaf/calib.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 "xclbin-helper.h" +#include "metadata.h" +#include "xleaf/calib.h" + +#define XRT_CALIB "xrt_calib" + +struct calib_cache { + struct list_head link; + const char *ep_name; + char *data; + u32 data_size; +}; + +struct calib { + struct platform_device *pdev; + void *calib_base; + struct mutex lock; /* calibration dev lock */ + struct list_head cache_list; + u32 cache_num; + enum xrt_calib_results result; +}; + +#define CALIB_DONE(calib) \ + (ioread32((calib)->calib_base) & BIT(0)) + +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_srsr(struct calib *calib, struct platform_device *srsr_leaf) +{ + return -EOPNOTSUPP; +} + +static int calib_calibration(struct calib *calib) +{ + int i; + + for (i = 0; i < 20; i++) { + if (CALIB_DONE(calib)) + break; + msleep(500); + } + + if (i == 20) { + xrt_err(calib->pdev, + "MIG calibration timeout after bitstream download"); + return -ETIMEDOUT; + } + + xrt_info(calib->pdev, "took %dms", i * 500); + 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 = evt->xe_subdev.xevt_subdev_id; + int instance = evt->xe_subdev.xevt_subdev_instance; + struct platform_device *leaf; + int ret; + + switch (e) { + case XRT_EVENT_POST_CREATION: { + if (id == XRT_SUBDEV_SRSR) { + leaf = xleaf_get_leaf_by_id(pdev, + XRT_SUBDEV_SRSR, + instance); + if (!leaf) { + xrt_err(pdev, "does not get SRSR subdev"); + return; + } + ret = calib_srsr(calib, leaf); + xleaf_put_leaf(pdev, leaf); + calib->result = + ret ? XRT_CALIB_FAILED : XRT_CALIB_SUCCEEDED; + } else if (id == XRT_SUBDEV_UCS) { + ret = calib_calibration(calib); + calib->result = + ret ? XRT_CALIB_FAILED : XRT_CALIB_SUCCEEDED; + } + break; + } + default: + break; + } +} + +static int xrt_calib_remove(struct platform_device *pdev) +{ + struct calib *calib = platform_get_drvdata(pdev); + + calib_cache_clean(calib); + + if (calib->calib_base) + iounmap(calib->calib_base); + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, calib); + + return 0; +} + +static int xrt_calib_probe(struct platform_device *pdev) +{ + struct calib *calib; + struct resource *res; + 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) + goto failed; + + calib->calib_base = ioremap(res->start, res->end - res->start + 1); + if (!calib->calib_base) { + err = -EIO; + xrt_err(pdev, "Map iomem failed"); + goto failed; + } + + mutex_init(&calib->lock); + INIT_LIST_HEAD(&calib->cache_list); + + return 0; + +failed: + xrt_calib_remove(pdev); + return err; +} + +static int +xrt_calib_leaf_ioctl(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_ioctl = xrt_calib_leaf_ioctl, + }, +}; + +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, +}; + +void calib_leaf_init_fini(bool init) +{ + if (init) + xleaf_register_driver(XRT_SUBDEV_CALIB, &xrt_calib_driver, xrt_calib_endpoints); + else + xleaf_unregister_driver(XRT_SUBDEV_CALIB); +}