From patchwork Thu Dec 10 16:57:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965615 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=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6B10C433FE for ; Thu, 10 Dec 2020 16:59:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 88658207A2 for ; Thu, 10 Dec 2020 16:59:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388961AbgLJQ7K (ORCPT ); Thu, 10 Dec 2020 11:59:10 -0500 Received: from mail-pf1-f196.google.com ([209.85.210.196]:45516 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392155AbgLJQ66 (ORCPT ); Thu, 10 Dec 2020 11:58:58 -0500 Received: by mail-pf1-f196.google.com with SMTP id q22so4644830pfk.12 for ; Thu, 10 Dec 2020 08:58:42 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=R5s8bOluMHY3VNyIJi/uGnyyvKSEAGl02n+N99993IY=; b=GcUodZJautuencAkDtWdpp0AOKlDtllSvDHNuRHOwHiNRegM0RzCCCT9qSab/J9B5t 5Ae51xRMgXgbhLfyetiV5Gt3AsUEug75qqgYr1Sx0ZKFIrQW7WSwzpUReSwfw6yiJ4e9 gs5F32YBQB9wMsXIAmTom7TN7JKhy+n5PsxF8jJ7mBqjvxxOE5SPRnotmvXKjh5vIDY0 rXzNdEaro/B/xL+Vi0L9TYEU5O92RhEZ8I1s78f8B3pzBwMbN/Cwd96mezVXuUMZJclM QRpLjPUe5kvw1RUQ4zTMsW85aiRPOq3uj3p5VmIeZBxAifjg9s7KqcjP684h+0/F9gPS aV9A== X-Gm-Message-State: AOAM533ILHVWOm8sEUGypdDioDgniDyOYNoJhQSJze+xLfi0ciBAzSnQ ZUecfvK7jFTmFunHMUi8GRI= X-Google-Smtp-Source: ABdhPJzeGypVKgKVf6WqoLaU23TbWgO3rSj4Zt4whhZ3m/gLUQjkeboCUrGzIW2xPEJ6+fGQg+yKbQ== X-Received: by 2002:a17:90a:db49:: with SMTP id u9mr8481783pjx.0.1607619497626; Thu, 10 Dec 2020 08:58:17 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id x10sm7036879pfc.179.2020.12.10.08.58.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:16 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Matthew Gerlach , Moritz Fischer Subject: [PATCH 1/8] fpga: dfl: refactor cci_enumerate_feature_devs() Date: Thu, 10 Dec 2020 08:57:57 -0800 Message-Id: <20201210165804.44234-2-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Matthew Gerlach In preparation of looking for dfls based on a vendor specific pci capability, move the code for the default method of finding the first dfl at offset 0 of Bar 0 to its own function. Signed-off-by: Matthew Gerlach Acked-by: Wu Hao Signed-off-by: Moritz Fischer --- drivers/fpga/dfl-pci.c | 84 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index a2203d03c9e2..5100695e27cd 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -119,49 +119,20 @@ static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec) return table; } -/* enumerate feature devices under pci device */ -static int cci_enumerate_feature_devs(struct pci_dev *pcidev) +/* default method of finding dfls starting at offset 0 of bar 0 */ +static int find_dfls_by_default(struct pci_dev *pcidev, + struct dfl_fpga_enum_info *info) { - struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); - int port_num, bar, i, nvec, ret = 0; - struct dfl_fpga_enum_info *info; - struct dfl_fpga_cdev *cdev; + int port_num, bar, i, ret = 0; resource_size_t start, len; void __iomem *base; - int *irq_table; u32 offset; u64 v; - /* allocate enumeration info via pci_dev */ - info = dfl_fpga_enum_info_alloc(&pcidev->dev); - if (!info) - return -ENOMEM; - - /* add irq info for enumeration if the device support irq */ - nvec = cci_pci_alloc_irq(pcidev); - if (nvec < 0) { - dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec); - ret = nvec; - goto enum_info_free_exit; - } else if (nvec) { - irq_table = cci_pci_create_irq_table(pcidev, nvec); - if (!irq_table) { - ret = -ENOMEM; - goto irq_free_exit; - } - - ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table); - kfree(irq_table); - if (ret) - goto irq_free_exit; - } - - /* start to find Device Feature List in Bar 0 */ + /* start to find Device Feature List from Bar 0 */ base = cci_pci_ioremap_bar0(pcidev); - if (!base) { - ret = -ENOMEM; - goto irq_free_exit; - } + if (!base) + return -ENOMEM; /* * PF device has FME and Ports/AFUs, and VF device only has one @@ -208,12 +179,51 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev) dfl_fpga_enum_info_add_dfl(info, start, len); } else { ret = -ENODEV; - goto irq_free_exit; } /* release I/O mappings for next step enumeration */ pcim_iounmap_regions(pcidev, BIT(0)); + return ret; +} + +/* enumerate feature devices under pci device */ +static int cci_enumerate_feature_devs(struct pci_dev *pcidev) +{ + struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); + struct dfl_fpga_enum_info *info; + struct dfl_fpga_cdev *cdev; + int nvec, ret = 0; + int *irq_table; + + /* allocate enumeration info via pci_dev */ + info = dfl_fpga_enum_info_alloc(&pcidev->dev); + if (!info) + return -ENOMEM; + + /* add irq info for enumeration if the device support irq */ + nvec = cci_pci_alloc_irq(pcidev); + if (nvec < 0) { + dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec); + ret = nvec; + goto enum_info_free_exit; + } else if (nvec) { + irq_table = cci_pci_create_irq_table(pcidev, nvec); + if (!irq_table) { + ret = -ENOMEM; + goto irq_free_exit; + } + + ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table); + kfree(irq_table); + if (ret) + goto irq_free_exit; + } + + ret = find_dfls_by_default(pcidev, info); + if (ret) + goto irq_free_exit; + /* start enumeration with prepared enumeration information */ cdev = dfl_fpga_feature_devs_enumerate(info); if (IS_ERR(cdev)) { From patchwork Thu Dec 10 16:57:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965625 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=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E8079C433FE for ; Thu, 10 Dec 2020 16:59:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 98736221E3 for ; Thu, 10 Dec 2020 16:59:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390527AbgLJQ7p (ORCPT ); Thu, 10 Dec 2020 11:59:45 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:44648 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392160AbgLJQ7A (ORCPT ); Thu, 10 Dec 2020 11:59:00 -0500 Received: by mail-pf1-f193.google.com with SMTP id f9so4649212pfc.11 for ; Thu, 10 Dec 2020 08:58:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=h2oSgYeQZxR87ohN6KF0gETYZLnwVlanqQCGgABmfao=; b=LMB69VwPWmboPvdPNRelgc6iWnFkRbmOfY2Y2SV2NAOv3Nj0IS1UvFCcOkbhAlVc9y aYPjmphfCZjfO4qsOqIm/aHxeANT0C8hUgj46D665t1r48liVzroMAx/GXUPQYB1vbxR R3CaTcKvIny2zlSzUu5KFUpwGOUpa8AAOpaFcrAAI1fV3byO1RRLLQOwgDJSK79pZ/7X HIztLTqSjT3m/cS6XfCAaZNXKAMTUxPNrWWpY/moRbcqCMXX1cvlkQ5Or5Fc2BATBn6e baim3LAgepSDHfnETJp7sl+Zv47wU2w3holckikbnBavdVgzI0xN6NwEzrWcF5Lw1nDD cIXQ== X-Gm-Message-State: AOAM5322skqC6Bm7PBgh0s2QcASXcgHc4luVBgkK97TRd1u6kGkNRYcK lLJYrAy3ocGXWcGAR2uJDyk= X-Google-Smtp-Source: ABdhPJwIbgwUEEch9Rksk4U2BL24NjlR5RyLMOhEfnA9gzxCmSs9LspZu/hrHqhgbAtGqiBsw12WJA== X-Received: by 2002:a65:5b84:: with SMTP id i4mr7458053pgr.282.1607619499622; Thu, 10 Dec 2020 08:58:19 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id y19sm6784224pfp.211.2020.12.10.08.58.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:18 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Matthew Gerlach , Moritz Fischer Subject: [PATCH 2/8] fpga: dfl-pci: locate DFLs by PCIe vendor specific capability Date: Thu, 10 Dec 2020 08:57:58 -0800 Message-Id: <20201210165804.44234-3-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Matthew Gerlach A PCIe vendor specific extended capability is introduced by Intel to specify the start of a number of DFLs. Signed-off-by: Matthew Gerlach Signed-off-by: Moritz Fischer --- Documentation/fpga/dfl.rst | 27 ++++++++++++ drivers/fpga/dfl-pci.c | 87 +++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst index 0404fe6ffc74..ea8cefc18bdb 100644 --- a/Documentation/fpga/dfl.rst +++ b/Documentation/fpga/dfl.rst @@ -501,6 +501,33 @@ Developer only needs to provide a sub feature driver with matched feature id. FME Partial Reconfiguration Sub Feature driver (see drivers/fpga/dfl-fme-pr.c) could be a reference. +Location of DFLs on a PCI Device +=========================== +The original method for finding a DFL on a PCI device assumed the start of the +first DFL to offset 0 of bar 0. If the first node of the DFL is an FME, +then further DFLs in the port(s) are specified in FME header registers. +Alternatively, a PCIe vendor specific capability structure can be used to +specify the location of all the DFLs on the device, providing flexibility +for the type of starting node in the DFL. Intel has reserved the +VSEC ID of 0x43 for this purpose. The vendor specific +data begins with a 4 byte vendor specific register for the number of DFLs followed 4 byte +Offset/BIR vendor specific registers for each DFL. Bits 2:0 of Offset/BIR register +indicates the BAR, and bits 31:3 form the 8 byte aligned offset where bits 2:0 are +zero. + + +----------------------------+ + |31 Number of DFLS 0| + +----------------------------+ + |31 Offset 3|2 BIR 0| + +----------------------------+ + . . . + +----------------------------+ + |31 Offset 3|2 BIR 0| + +----------------------------+ + +Being able to specify more than one DFL per BAR has been considered, but it +was determined the use case did not provide value. Specifying a single DFL +per BAR simplifies the implementation and allows for extra error checking. Open discussion =============== diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 5100695e27cd..04e47e266f26 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -27,6 +27,14 @@ #define DRV_VERSION "0.8" #define DRV_NAME "dfl-pci" +#define PCI_VSEC_ID_INTEL_DFLS 0x43 + +#define PCI_VNDR_DFLS_CNT 0x8 +#define PCI_VNDR_DFLS_RES 0xc + +#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0) +#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3) + struct cci_drvdata { struct dfl_fpga_cdev *cdev; /* container device */ }; @@ -119,6 +127,80 @@ static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec) return table; } +static int find_dfls_by_vsec(struct pci_dev *pcidev, struct dfl_fpga_enum_info *info) +{ + u32 bir, offset, vndr_hdr, dfl_cnt, dfl_res; + int dfl_res_off, i, bars, voff = 0; + resource_size_t start, len; + + while ((voff = pci_find_next_ext_capability(pcidev, voff, PCI_EXT_CAP_ID_VNDR))) { + vndr_hdr = 0; + pci_read_config_dword(pcidev, voff + PCI_VNDR_HEADER, &vndr_hdr); + + if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS && + pcidev->vendor == PCI_VENDOR_ID_INTEL) + break; + } + + if (!voff) { + dev_dbg(&pcidev->dev, "%s no DFL VSEC found\n", __func__); + return -ENODEV; + } + + dfl_cnt = 0; + pci_read_config_dword(pcidev, voff + PCI_VNDR_DFLS_CNT, &dfl_cnt); + if (dfl_cnt > PCI_STD_NUM_BARS) { + dev_err(&pcidev->dev, "%s too many DFLs %d > %d\n", + __func__, dfl_cnt, PCI_STD_NUM_BARS); + return -EINVAL; + } + + dfl_res_off = voff + PCI_VNDR_DFLS_RES; + if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) { + dev_err(&pcidev->dev, "%s DFL VSEC too big for PCIe config space\n", + __func__); + return -EINVAL; + } + + for (i = 0, bars = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) { + dfl_res = GENMASK(31, 0); + pci_read_config_dword(pcidev, dfl_res_off, &dfl_res); + + bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK; + if (bir >= PCI_STD_NUM_BARS) { + dev_err(&pcidev->dev, "%s bad bir number %d\n", + __func__, bir); + return -EINVAL; + } + + if (bars & BIT(bir)) { + dev_err(&pcidev->dev, "%s DFL for BAR %d already specified\n", + __func__, bir); + return -EINVAL; + } + + bars |= BIT(bir); + + len = pci_resource_len(pcidev, bir); + offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK; + if (offset >= len) { + dev_err(&pcidev->dev, "%s bad offset %u >= %pa\n", + __func__, offset, &len); + return -EINVAL; + } + + dev_dbg(&pcidev->dev, "%s BAR %d offset 0x%x\n", __func__, bir, offset); + + len -= offset; + + start = pci_resource_start(pcidev, bir) + offset; + + dfl_fpga_enum_info_add_dfl(info, start, len); + } + + return 0; +} + /* default method of finding dfls starting at offset 0 of bar 0 */ static int find_dfls_by_default(struct pci_dev *pcidev, struct dfl_fpga_enum_info *info) @@ -220,7 +302,10 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev) goto irq_free_exit; } - ret = find_dfls_by_default(pcidev, info); + ret = find_dfls_by_vsec(pcidev, info); + if (ret == -ENODEV) + ret = find_dfls_by_default(pcidev, info); + if (ret) goto irq_free_exit; From patchwork Thu Dec 10 16:57:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965613 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=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E85AEC0018C for ; Thu, 10 Dec 2020 16:59:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BE959230FC for ; Thu, 10 Dec 2020 16:59:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392367AbgLJQ7L (ORCPT ); Thu, 10 Dec 2020 11:59:11 -0500 Received: from mail-pl1-f195.google.com ([209.85.214.195]:46105 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391047AbgLJQ7C (ORCPT ); Thu, 10 Dec 2020 11:59:02 -0500 Received: by mail-pl1-f195.google.com with SMTP id v3so3058736plz.13 for ; Thu, 10 Dec 2020 08:58:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FB/dx3m3KpkN+8L+NF1K6qL9jxEZGu8bEPcBWOE4EPE=; b=IptAvlSAtFtqUGjFdiZwTeDr6n7vAkxLvmOuz/+rRp41IdE1QhLgKBwGtr9kbdmOIG ORXJTOzYKxyGwUp58IWqDcg76M5bjc5xClIFIyaW77vI+1skZxz+fmHk0+42PLr4XY/b k1k5Iv0Uy/fK8gxOtsbq7I3/3ABDcBMZo0icJKdKJWAPZJ64kxV5cHXmHFGk9gn7YmKE uK2dnMgTwJCHeanVtfLBx7RTVWB2dAIWLW4EoPCMwUW8OOx/z1z5wmd8gK5QDJfl36Xw eIxTX8beVlP/jJObEeg+bzQE3cDH9zJ6bhn1Z6hxaHM8W/N+FnIdil8gvhAbkyuFd4Mb Rh4g== X-Gm-Message-State: AOAM532jT/xFmNRmMaTqF+CMUV6IAzxTe7a0+gRSRZa8KKHdBN+jKUaa l4rrnUkxftHL5zOlsW3axgk= X-Google-Smtp-Source: ABdhPJyFFMcOtrRutS0+HYwS5RuXWLx1qzbyP1PbzP0tCFUu8hKcJp7MMk+LNxBidGG1Ku5K+Seuow== X-Received: by 2002:a17:902:8649:b029:d9:fcd9:522a with SMTP id y9-20020a1709028649b02900d9fcd9522amr7289863plt.83.1607619501431; Thu, 10 Dec 2020 08:58:21 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id c8sm7081791pgg.51.2020.12.10.08.58.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:20 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Moritz Fischer Subject: [PATCH 3/8] fpga: dfl: fix the definitions of type & feature_id for dfl devices Date: Thu, 10 Dec 2020 08:57:59 -0800 Message-Id: <20201210165804.44234-4-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun The value of the field dfl_device.type comes from the 12 bits register field DFH_ID according to DFL spec. So this patch changes the definition of the type field to u16. Also it is not necessary to illustrate the valid bits of the type field in comments. Instead we should explicitly define the possible values in the enumeration type for it, because they are shared by hardware spec. We should not let the compiler decide these values. Similar changes are also applied to dfl_device.feature_id. This patch also fixed the MODALIAS format according to the changes above. Signed-off-by: Xu Yilun Signed-off-by: Moritz Fischer Reviewed-by: Tom Rix --- drivers/fpga/dfl.c | 3 +-- drivers/fpga/dfl.h | 14 +++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index b450870b75ed..5a6ba3b2fa05 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -298,8 +298,7 @@ static int dfl_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct dfl_device *ddev = to_dfl_dev(dev); - /* The type has 4 valid bits and feature_id has 12 valid bits */ - return add_uevent_var(env, "MODALIAS=dfl:t%01Xf%03X", + return add_uevent_var(env, "MODALIAS=dfl:t%04Xf%04X", ddev->type, ddev->feature_id); } diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 5dc758f655b7..ac373b1fcff9 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -520,19 +520,19 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, * enum dfl_id_type - define the DFL FIU types */ enum dfl_id_type { - FME_ID, - PORT_ID, + FME_ID = 0, + PORT_ID = 1, DFL_ID_MAX, }; /** * struct dfl_device_id - dfl device identifier - * @type: contains 4 bits DFL FIU type of the device. See enum dfl_id_type. - * @feature_id: contains 12 bits feature identifier local to its DFL FIU type. + * @type: DFL FIU type of the device. See enum dfl_id_type. + * @feature_id: feature identifier local to its DFL FIU type. * @driver_data: driver specific data. */ struct dfl_device_id { - u8 type; + u16 type; u16 feature_id; unsigned long driver_data; }; @@ -543,7 +543,7 @@ struct dfl_device_id { * @dev: generic device interface. * @id: id of the dfl device. * @type: type of DFL FIU of the device. See enum dfl_id_type. - * @feature_id: 16 bits feature identifier local to its DFL FIU type. + * @feature_id: feature identifier local to its DFL FIU type. * @mmio_res: mmio resource of this dfl device. * @irqs: list of Linux IRQ numbers of this dfl device. * @num_irqs: number of IRQs supported by this dfl device. @@ -553,7 +553,7 @@ struct dfl_device_id { struct dfl_device { struct device dev; int id; - u8 type; + u16 type; u16 feature_id; struct resource mmio_res; int *irqs; From patchwork Thu Dec 10 16:58:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965619 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=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BD4CC4167B for ; Thu, 10 Dec 2020 16:59:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3B79E221E3 for ; Thu, 10 Dec 2020 16:59:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392373AbgLJQ7T (ORCPT ); Thu, 10 Dec 2020 11:59:19 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:40148 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392369AbgLJQ7F (ORCPT ); Thu, 10 Dec 2020 11:59:05 -0500 Received: by mail-pf1-f193.google.com with SMTP id t7so4655495pfh.7 for ; Thu, 10 Dec 2020 08:58:50 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=X2GZ+ePoFiu9QiVFXfkzqTqbUH2vMpi+ch5sofOIR7Q=; b=dzplKMQTvDRzZz/ldQGN9+0wHPRPVUmDG81sbJ8OqUsFlQZf03/unwVWl3TojR7j1n Tv/xTpMUynvd/BtUDcvgejPBCd926X6J8luyMz6UXirDLMlCrWGVEI0QSsClj2IwperI CQ2+pS6jGa+Zqc6axZGAGssl0xQkPqyUzEzu9sA9FspKx2vGOGXSgU0X4p7oQ6Lxt8zc P6teUUTechDJFp34rS0CbvaN+EAtDC2Om698BA6XK356bTcaqqoJgokR/YJI/tYG59OW 5B7e9eJLgWTJTjYOgPmJZWjf1+QKAYgMyUh+6OjVts935621XdfSv9ctmOQIUDsPbDFX 8bGg== X-Gm-Message-State: AOAM5305yjKpmVacPFs6gTY6GWSwnJsz6fJt3cD7fSpRdj2SaQY/pY/z A1yXV5YDLqG510kCTu/9/8M= X-Google-Smtp-Source: ABdhPJxYn72jlzshOuLIRhMdbvr/rsQ2gyHpHPcLykN9hYEGAxbP2oGzr58b7EGoXj3hZHIdKMRbdg== X-Received: by 2002:a62:7b86:0:b029:19d:f996:44f3 with SMTP id w128-20020a627b860000b029019df99644f3mr7591086pfc.65.1607619505042; Thu, 10 Dec 2020 08:58:25 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id k14sm6842070pfp.132.2020.12.10.08.58.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:24 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Matthew Gerlach , Moritz Fischer Subject: [PATCH 4/8] fpga: dfl: move dfl_device_id to mod_devicetable.h Date: Thu, 10 Dec 2020 08:58:00 -0800 Message-Id: <20201210165804.44234-5-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun In order to support MODULE_DEVICE_TABLE() for dfl device driver, this patch moves struct dfl_device_id to mod_devicetable.h Some brief description for DFL (Device Feature List) is added to make the DFL known to the whole kernel. Signed-off-by: Xu Yilun Signed-off-by: Wu Hao Signed-off-by: Matthew Gerlach Signed-off-by: Russ Weight Signed-off-by: Moritz Fischer Reviewed-by: Tom Rix Acked-by: Wu Hao --- drivers/fpga/dfl.h | 13 +------------ include/linux/mod_devicetable.h | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index ac373b1fcff9..549c7900dcfd 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -525,18 +526,6 @@ enum dfl_id_type { DFL_ID_MAX, }; -/** - * struct dfl_device_id - dfl device identifier - * @type: DFL FIU type of the device. See enum dfl_id_type. - * @feature_id: feature identifier local to its DFL FIU type. - * @driver_data: driver specific data. - */ -struct dfl_device_id { - u16 type; - u16 feature_id; - unsigned long driver_data; -}; - /** * struct dfl_device - represent an dfl device on dfl bus * diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 5b08a473cdba..7d36c8c0fdc2 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -838,4 +838,28 @@ struct mhi_device_id { kernel_ulong_t driver_data; }; +/* + * DFL (Device Feature List) + * + * DFL defines a linked list of feature headers within the device MMIO space to + * provide an extensible way of adding features. Software can walk through these + * predefined data structures to enumerate features. It is now used in the FPGA. + * See Documentation/fpga/dfl.rst for more information. + * + * The dfl bus type is introduced to match the individual feature devices (dfl + * devices) for specific dfl drivers. + */ + +/** + * struct dfl_device_id - dfl device identifier + * @type: DFL FIU type of the device. See enum dfl_id_type. + * @feature_id: feature identifier local to its DFL FIU type. + * @driver_data: driver specific data. + */ +struct dfl_device_id { + __u16 type; + __u16 feature_id; + kernel_ulong_t driver_data; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ From patchwork Thu Dec 10 16:58:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965611 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=-17.0 required=3.0 tests=BAYES_00,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 D5067C4361B for ; Thu, 10 Dec 2020 16:59:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A3F9E221E3 for ; Thu, 10 Dec 2020 16:59:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391024AbgLJQ7L (ORCPT ); Thu, 10 Dec 2020 11:59:11 -0500 Received: from mail-pl1-f195.google.com ([209.85.214.195]:46113 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387776AbgLJQ7J (ORCPT ); Thu, 10 Dec 2020 11:59:09 -0500 Received: by mail-pl1-f195.google.com with SMTP id v3so3058891plz.13 for ; Thu, 10 Dec 2020 08:58:54 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3RjWYFS0t1qwCCykWF+LwjjyJCld4uAnADZtHP/eQeo=; b=CKwvGYNwc0tHKJKGJkRaOBjsKG3jpp4DhX+eKdXfbqC6M6N8D6ehJKfuLXWgt4Tvh7 Y7W6crIvo8GGqwJH3RF1bQouAmXl9E/tBhxm1rj1MfDAwI9tqOw8P+C4Fua2/U5z71+i +1HqsJb1yR8tYUcGVxTbVvDDkgbbZ6EWicFMy+p9dUQpXlbx4VqWyWjkdLHlksXyToZY 1jtjFNAyVOxpagOeoEsbD9fZrK6KL6sh1H2XNA9jwkAUpai6COVdfhNtu181HkMzG+1F hCWu0z/RGickf62AT4ZhXhFAtBHUce8pPO4ykIqCuLjaFtwwgivb1Z9Avgg68yBIrlkr 9+Nw== X-Gm-Message-State: AOAM530TEvMiJWW4bj2DMwRk+8uETA3hzoZtJOfm7gFvCkMNhWEgzRFj hmdWVB/2rUJUZzz+I8lnzu4= X-Google-Smtp-Source: ABdhPJww3r/MMhIvblrkwmJMxMP5jc9E/FBTV0hiZXleYhZVSa8+7DDBJXvz7/5xB9hN2OMynfMiIg== X-Received: by 2002:a17:902:a9c1:b029:da:8227:65f7 with SMTP id b1-20020a170902a9c1b02900da822765f7mr7216439plr.49.1607619508699; Thu, 10 Dec 2020 08:58:28 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id b20sm6235969pfi.218.2020.12.10.08.58.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:27 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Matthew Gerlach , Moritz Fischer Subject: [PATCH 5/8] fpga: dfl: add dfl bus support to MODULE_DEVICE_TABLE() Date: Thu, 10 Dec 2020 08:58:01 -0800 Message-Id: <20201210165804.44234-6-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun Device Feature List (DFL) is a linked list of feature headers within the device MMIO space. It is used by FPGA to enumerate multiple sub features within it. Each feature can be uniquely identified by DFL type and feature id, which can be read out from feature headers. A dfl bus helps DFL framework modularize DFL device drivers for different sub features. The dfl bus matches its devices and drivers by DFL type and feature id. This patch adds dfl bus support to MODULE_DEVICE_TABLE() by adding info about struct dfl_device_id in devicetable-offsets.c and add a dfl entry point in file2alias.c. Signed-off-by: Xu Yilun Signed-off-by: Wu Hao Signed-off-by: Matthew Gerlach Signed-off-by: Russ Weight Signed-off-by: Moritz Fischer Acked-by: Wu Hao --- scripts/mod/devicetable-offsets.c | 4 ++++ scripts/mod/file2alias.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 27007c18e754..d8350eea6d1a 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -243,5 +243,9 @@ int main(void) DEVID(mhi_device_id); DEVID_FIELD(mhi_device_id, chan); + DEVID(dfl_device_id); + DEVID_FIELD(dfl_device_id, type); + DEVID_FIELD(dfl_device_id, feature_id); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 2417dd1dee33..8a438c94dcd9 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1368,6 +1368,18 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: dfl:tNfN */ +static int do_dfl_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, dfl_device_id, type); + DEF_FIELD(symval, dfl_device_id, feature_id); + + sprintf(alias, "dfl:t%04Xf%04X", type, feature_id); + + add_wildcard(alias); + return 1; +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1442,6 +1454,7 @@ static const struct devtable devtable[] = { {"tee", SIZE_tee_client_device_id, do_tee_entry}, {"wmi", SIZE_wmi_device_id, do_wmi_entry}, {"mhi", SIZE_mhi_device_id, do_mhi_entry}, + {"dfl", SIZE_dfl_device_id, do_dfl_entry}, }; /* Create MODULE_ALIAS() statements. From patchwork Thu Dec 10 16:58:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965617 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=-17.0 required=3.0 tests=BAYES_00,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E25E8C4361B for ; Thu, 10 Dec 2020 16:59:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A90C0221E3 for ; Thu, 10 Dec 2020 16:59:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387776AbgLJQ7N (ORCPT ); Thu, 10 Dec 2020 11:59:13 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:38982 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391047AbgLJQ7L (ORCPT ); Thu, 10 Dec 2020 11:59:11 -0500 Received: by mail-pf1-f193.google.com with SMTP id i3so4665152pfd.6 for ; Thu, 10 Dec 2020 08:58:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8xrVQLkOkYqMOiYDbITEs6MQ6JjKj9uyPsCqicxADHU=; b=HMJoNU8uFOoK3ixL3343nNn7092hLvkY5OXwxQXBDTAYg+SaPRDq9ndSqIeB2XBJIl 5T7krOQb3crMZaF4Hx99imjLOTyjaYBxqkiKDqzd4PaVe0AyUkc7blfNhfW5ZSFAyIx7 1sXiCWZOHFEATGG12+pN3K6K1b6hqQj//mDhMLzgGQblCB4mE5IZFWrlYpiAuMCpTb7f qB+gu8IrLaoSUjvDHeOo3BP2ko+EAR6LD2EoXZKdXWplhpZ3cH8IvN5b55vd0Wq0kUcQ /WuOgWzNPDT/n9242clyCCDKM2+Dg0jFhcKkk+9MCzvY8mDps2wjON08DrQPnmDECW4n HFeg== X-Gm-Message-State: AOAM531Ro/cSldEf0kCbR4T1hSuv45T4Cc7d/o+Ho4ud4OVWZgrdt7fu QRegEHyXR1X/3w/XTsO/59XtBRFC14TM6g== X-Google-Smtp-Source: ABdhPJwchHdNPm6g6Wh4QYJzqn9IPbocgUIHPFT8kn/jvG3CaZhIN9HUjgIyFuLi2A7df/Sl1Llqcw== X-Received: by 2002:a63:dd53:: with SMTP id g19mr7392522pgj.291.1607619510868; Thu, 10 Dec 2020 08:58:30 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id x12sm6954350pfj.25.2020.12.10.08.58.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:30 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Moritz Fischer Subject: [PATCH 6/8] fpga: dfl: move dfl bus related APIs to include/linux/dfl.h Date: Thu, 10 Dec 2020 08:58:02 -0800 Message-Id: <20201210165804.44234-7-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun Now the dfl drivers could be made as independent modules and put in different folders according to their functionalities. In order for scattered dfl device drivers to include dfl bus APIs, move the dfl bus APIs to a new header file in the public folder. [mdf@kernel.org: Fixed up header guards to match filename] Signed-off-by: Xu Yilun Signed-off-by: Moritz Fischer Reviewed-by: Tom Rix Acked-by: Wu Hao --- MAINTAINERS | 1 + drivers/fpga/dfl.c | 1 + drivers/fpga/dfl.h | 72 ------------------------------------- include/linux/dfl.h | 86 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 72 deletions(-) create mode 100644 include/linux/dfl.h diff --git a/MAINTAINERS b/MAINTAINERS index 52086876ce40..5fe658a6d846 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6895,6 +6895,7 @@ S: Maintained F: Documentation/ABI/testing/sysfs-bus-dfl F: Documentation/fpga/dfl.rst F: drivers/fpga/dfl* +F: include/linux/dfl.h F: include/uapi/linux/fpga-dfl.h FPGA MANAGER FRAMEWORK diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index 5a6ba3b2fa05..511b20ff35a3 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -10,6 +10,7 @@ * Wu Hao * Xiao Guangrong */ +#include #include #include #include diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 549c7900dcfd..2b82c96ba56c 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -517,76 +517,4 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, struct dfl_feature *feature, unsigned long arg); -/** - * enum dfl_id_type - define the DFL FIU types - */ -enum dfl_id_type { - FME_ID = 0, - PORT_ID = 1, - DFL_ID_MAX, -}; - -/** - * struct dfl_device - represent an dfl device on dfl bus - * - * @dev: generic device interface. - * @id: id of the dfl device. - * @type: type of DFL FIU of the device. See enum dfl_id_type. - * @feature_id: feature identifier local to its DFL FIU type. - * @mmio_res: mmio resource of this dfl device. - * @irqs: list of Linux IRQ numbers of this dfl device. - * @num_irqs: number of IRQs supported by this dfl device. - * @cdev: pointer to DFL FPGA container device this dfl device belongs to. - * @id_entry: matched id entry in dfl driver's id table. - */ -struct dfl_device { - struct device dev; - int id; - u16 type; - u16 feature_id; - struct resource mmio_res; - int *irqs; - unsigned int num_irqs; - struct dfl_fpga_cdev *cdev; - const struct dfl_device_id *id_entry; -}; - -/** - * struct dfl_driver - represent an dfl device driver - * - * @drv: driver model structure. - * @id_table: pointer to table of device IDs the driver is interested in. - * { } member terminated. - * @probe: mandatory callback for device binding. - * @remove: callback for device unbinding. - */ -struct dfl_driver { - struct device_driver drv; - const struct dfl_device_id *id_table; - - int (*probe)(struct dfl_device *dfl_dev); - void (*remove)(struct dfl_device *dfl_dev); -}; - -#define to_dfl_dev(d) container_of(d, struct dfl_device, dev) -#define to_dfl_drv(d) container_of(d, struct dfl_driver, drv) - -/* - * use a macro to avoid include chaining to get THIS_MODULE. - */ -#define dfl_driver_register(drv) \ - __dfl_driver_register(drv, THIS_MODULE) -int __dfl_driver_register(struct dfl_driver *dfl_drv, struct module *owner); -void dfl_driver_unregister(struct dfl_driver *dfl_drv); - -/* - * module_dfl_driver() - Helper macro for drivers that don't do - * anything special in module init/exit. This eliminates a lot of - * boilerplate. Each module may only use this macro once, and - * calling it replaces module_init() and module_exit(). - */ -#define module_dfl_driver(__dfl_driver) \ - module_driver(__dfl_driver, dfl_driver_register, \ - dfl_driver_unregister) - #endif /* __FPGA_DFL_H */ diff --git a/include/linux/dfl.h b/include/linux/dfl.h new file mode 100644 index 000000000000..6cc10982351a --- /dev/null +++ b/include/linux/dfl.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header file for DFL driver and device API + * + * Copyright (C) 2020 Intel Corporation, Inc. + */ + +#ifndef __LINUX_DFL_H +#define __LINUX_DFL_H + +#include +#include + +/** + * enum dfl_id_type - define the DFL FIU types + */ +enum dfl_id_type { + FME_ID = 0, + PORT_ID = 1, + DFL_ID_MAX, +}; + +/** + * struct dfl_device - represent an dfl device on dfl bus + * + * @dev: generic device interface. + * @id: id of the dfl device. + * @type: type of DFL FIU of the device. See enum dfl_id_type. + * @feature_id: feature identifier local to its DFL FIU type. + * @mmio_res: mmio resource of this dfl device. + * @irqs: list of Linux IRQ numbers of this dfl device. + * @num_irqs: number of IRQs supported by this dfl device. + * @cdev: pointer to DFL FPGA container device this dfl device belongs to. + * @id_entry: matched id entry in dfl driver's id table. + */ +struct dfl_device { + struct device dev; + int id; + u16 type; + u16 feature_id; + struct resource mmio_res; + int *irqs; + unsigned int num_irqs; + struct dfl_fpga_cdev *cdev; + const struct dfl_device_id *id_entry; +}; + +/** + * struct dfl_driver - represent an dfl device driver + * + * @drv: driver model structure. + * @id_table: pointer to table of device IDs the driver is interested in. + * { } member terminated. + * @probe: mandatory callback for device binding. + * @remove: callback for device unbinding. + */ +struct dfl_driver { + struct device_driver drv; + const struct dfl_device_id *id_table; + + int (*probe)(struct dfl_device *dfl_dev); + void (*remove)(struct dfl_device *dfl_dev); +}; + +#define to_dfl_dev(d) container_of(d, struct dfl_device, dev) +#define to_dfl_drv(d) container_of(d, struct dfl_driver, drv) + +/* + * use a macro to avoid include chaining to get THIS_MODULE. + */ +#define dfl_driver_register(drv) \ + __dfl_driver_register(drv, THIS_MODULE) +int __dfl_driver_register(struct dfl_driver *dfl_drv, struct module *owner); +void dfl_driver_unregister(struct dfl_driver *dfl_drv); + +/* + * module_dfl_driver() - Helper macro for drivers that don't do + * anything special in module init/exit. This eliminates a lot of + * boilerplate. Each module may only use this macro once, and + * calling it replaces module_init() and module_exit(). + */ +#define module_dfl_driver(__dfl_driver) \ + module_driver(__dfl_driver, dfl_driver_register, \ + dfl_driver_unregister) + +#endif /* __LINUX_DFL_H */ From patchwork Thu Dec 10 16:58:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965623 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=-17.0 required=3.0 tests=BAYES_00,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 8F983C4361B for ; Thu, 10 Dec 2020 16:59:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 504A7221E3 for ; Thu, 10 Dec 2020 16:59:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731400AbgLJQ7a (ORCPT ); Thu, 10 Dec 2020 11:59:30 -0500 Received: from mail-pf1-f173.google.com ([209.85.210.173]:43431 "EHLO mail-pf1-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391047AbgLJQ7O (ORCPT ); Thu, 10 Dec 2020 11:59:14 -0500 Received: by mail-pf1-f173.google.com with SMTP id c12so4647922pfo.10 for ; Thu, 10 Dec 2020 08:58:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Cua7B9zQkM2RGISLzia4GjwCIyG7DxunT089SreDfzQ=; b=e1IslZeP2FM/+/Fmb8daKRNcgP8S8VMZAPh6ZdQW6yDDwfQjqtPa3Mgrvd72+6OeHH 0sBJLeY6pU3QNbgd+VqzU3OZgFl8Bh1eftL7mfH6PUKjhcmEa+XFyr0jhhTdGMAiIbl4 3Jgd6IEd7QTbS+gZe5oNm9zPEDxxd1e9PCbqJQJRyXfIBZLYY73ndqnA6I1TSNA1hgqM HHSbkS3faKQpKZpIsWYUrqJ79u7oIXHk2uvcLXuOAEa6zMDLmpMBjzVlnJreB6NS+V3E qR8zU9ux4lKBhRoLufUvzsQofoFjAyBHUigV3pvugtMQWMs973r30Ogl18koHFOgiVVA imZQ== X-Gm-Message-State: AOAM531IbKgk+AHeWVPliQGN4cVWPEcxnOOa4NpH1EbCJf63GKJHDDI7 BEiqKB5peqTM10dMeDbIj1Q= X-Google-Smtp-Source: ABdhPJxc4V8RZkEq8iPx/lef7M5rZDc8+i6Wj+hqe9UlRKEhgF0QA7KTEqCb9l3ojK0oGBjvXtMteQ== X-Received: by 2002:a17:90a:4209:: with SMTP id o9mr8596931pjg.75.1607619513006; Thu, 10 Dec 2020 08:58:33 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id i11sm6884812pjl.53.2020.12.10.08.58.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:32 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Matthew Gerlach , YueHaibing , Moritz Fischer Subject: [PATCH 7/8] fpga: dfl: add support for N3000 Nios private feature Date: Thu, 10 Dec 2020 08:58:03 -0800 Message-Id: <20201210165804.44234-8-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun This patch adds support for the Nios handshake private feature on Intel PAC (Programmable Acceleration Card) N3000. The Nios is the embedded processor on the FPGA card. This private feature provides a handshake interface to FPGA Nios firmware, which receives retimer configuration command from host and executes via an internal SPI master (spi-altera). When Nios finishes the configuration, host takes over the ownership of the SPI master to control an Intel MAX10 BMC (Board Management Controller) Chip on the SPI bus. For Nios firmware handshake part, this driver requests the retimer configuration for Nios firmware on probe, and adds some sysfs nodes for user to query the onboard retimer's working mode and Nios firmware version. For SPI part, this driver adds a spi-altera platform device as well as the MAX10 BMC spi slave info. A spi-altera driver will be matched to handle the following SPI work. [mdf@kernel.org: Fixed up MAINTAINERS file to include added ABI doc] Signed-off-by: Xu Yilun Signed-off-by: Wu Hao Signed-off-by: Matthew Gerlach Signed-off-by: Russ Weight Signed-off-by: YueHaibing Reviewed-by: Tom Rix Signed-off-by: Moritz Fischer --- .../testing/sysfs-bus-dfl-devices-n3000-nios | 47 ++ MAINTAINERS | 2 +- drivers/fpga/Kconfig | 11 + drivers/fpga/Makefile | 2 + drivers/fpga/dfl-n3000-nios.c | 588 ++++++++++++++++++ 5 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios create mode 100644 drivers/fpga/dfl-n3000-nios.c diff --git a/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios new file mode 100644 index 000000000000..a50553764654 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-dfl-devices-n3000-nios @@ -0,0 +1,47 @@ +What: /sys/bus/dfl/devices/dfl_dev.X/fec_mode +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. Returns the FEC mode of the 25G links of the + ethernet retimers configured by Nios firmware. "rs" for Reed + Solomon FEC, "kr" for Fire Code FEC, "no" for NO FEC. + "not supported" if the FEC mode setting is not supported, this + happens when the Nios firmware version major < 3, or no link is + configured to 25G. + Format: string + +What: /sys/bus/dfl/devices/dfl_dev.X/retimer_A_mode +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. Returns the enumeration value of the working mode of + the retimer A configured by the Nios firmware. The value is + read out from shared registers filled by the Nios firmware. Now + the values could be: + + - "0": Reset + - "1": 4x10G + - "2": 4x25G + - "3": 2x25G + - "4": 2x25G+2x10G + - "5": 1x25G + + If the Nios firmware is updated in future to support more + retimer modes, more enumeration value is expected. + Format: 0x%x + +What: /sys/bus/dfl/devices/dfl_dev.X/retimer_B_mode +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. Returns the enumeration value of the working mode of + the retimer B configured by the Nios firmware. The value format + is the same as retimer_A_mode. + +What: /sys/bus/dfl/devices/dfl_dev.X/nios_fw_version +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. Returns the version of the Nios firmware in the + FPGA. Its format is "major.minor.patch". + Format: %x.%x.%x diff --git a/MAINTAINERS b/MAINTAINERS index 5fe658a6d846..c1012a23f05a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6892,7 +6892,7 @@ M: Wu Hao R: Tom Rix L: linux-fpga@vger.kernel.org S: Maintained -F: Documentation/ABI/testing/sysfs-bus-dfl +F: Documentation/ABI/testing/sysfs-bus-dfl* F: Documentation/fpga/dfl.rst F: drivers/fpga/dfl* F: include/linux/dfl.h diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 5645226ca3ce..5ff9438b7b46 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -192,6 +192,17 @@ config FPGA_DFL_AFU to the FPGA infrastructure via a Port. There may be more than one Port/AFU per DFL based FPGA device. +config FPGA_DFL_NIOS_INTEL_PAC_N3000 + tristate "FPGA DFL NIOS Driver for Intel PAC N3000" + depends on FPGA_DFL + select REGMAP + help + This is the driver for the N3000 Nios private feature on Intel + PAC (Programmable Acceleration Card) N3000. It communicates + with the embedded Nios processor to configure the retimers on + the card. It also instantiates the SPI master (spi-altera) for + the card's BMC (Board Management Controller). + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index d8e21dfc6778..18dc9885883a 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -44,5 +44,7 @@ dfl-fme-objs += dfl-fme-perf.o dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o dfl-afu-objs += dfl-afu-error.o +obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o + # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o diff --git a/drivers/fpga/dfl-n3000-nios.c b/drivers/fpga/dfl-n3000-nios.c new file mode 100644 index 000000000000..7a95366f6516 --- /dev/null +++ b/drivers/fpga/dfl-n3000-nios.c @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DFL device driver for Nios private feature on Intel PAC (Programmable + * Acceleration Card) N3000 + * + * Copyright (C) 2019-2020 Intel Corporation, Inc. + * + * Authors: + * Wu Hao + * Xu Yilun + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * N3000 Nios private feature registers, named as NIOS_SPI_XX on spec. + * NS is the abbreviation of NIOS_SPI. + */ +#define N3000_NS_PARAM 0x8 +#define N3000_NS_PARAM_SHIFT_MODE_MSK BIT_ULL(1) +#define N3000_NS_PARAM_SHIFT_MODE_MSB 0 +#define N3000_NS_PARAM_SHIFT_MODE_LSB 1 +#define N3000_NS_PARAM_DATA_WIDTH GENMASK_ULL(7, 2) +#define N3000_NS_PARAM_NUM_CS GENMASK_ULL(13, 8) +#define N3000_NS_PARAM_CLK_POL BIT_ULL(14) +#define N3000_NS_PARAM_CLK_PHASE BIT_ULL(15) +#define N3000_NS_PARAM_PERIPHERAL_ID GENMASK_ULL(47, 32) + +#define N3000_NS_CTRL 0x10 +#define N3000_NS_CTRL_WR_DATA GENMASK_ULL(31, 0) +#define N3000_NS_CTRL_ADDR GENMASK_ULL(44, 32) +#define N3000_NS_CTRL_CMD_MSK GENMASK_ULL(63, 62) +#define N3000_NS_CTRL_CMD_NOP 0 +#define N3000_NS_CTRL_CMD_RD 1 +#define N3000_NS_CTRL_CMD_WR 2 + +#define N3000_NS_STAT 0x18 +#define N3000_NS_STAT_RD_DATA GENMASK_ULL(31, 0) +#define N3000_NS_STAT_RW_VAL BIT_ULL(32) + +/* Nios handshake registers, indirect access */ +#define N3000_NIOS_INIT 0x1000 +#define N3000_NIOS_INIT_DONE BIT(0) +#define N3000_NIOS_INIT_START BIT(1) +/* Mode for retimer A, link 0, the same below */ +#define N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK GENMASK(9, 8) +#define N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK GENMASK(11, 10) +#define N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK GENMASK(13, 12) +#define N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK GENMASK(15, 14) +#define N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK GENMASK(17, 16) +#define N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK GENMASK(19, 18) +#define N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK GENMASK(21, 20) +#define N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK GENMASK(23, 22) +#define N3000_NIOS_INIT_REQ_FEC_MODE_NO 0x0 +#define N3000_NIOS_INIT_REQ_FEC_MODE_KR 0x1 +#define N3000_NIOS_INIT_REQ_FEC_MODE_RS 0x2 + +#define N3000_NIOS_FW_VERSION 0x1004 +#define N3000_NIOS_FW_VERSION_PATCH GENMASK(23, 20) +#define N3000_NIOS_FW_VERSION_MINOR GENMASK(27, 24) +#define N3000_NIOS_FW_VERSION_MAJOR GENMASK(31, 28) + +/* The retimers we use on Intel PAC N3000 is Parkvale, abbreviated to PKVL */ +#define N3000_NIOS_PKVL_A_MODE_STS 0x1020 +#define N3000_NIOS_PKVL_B_MODE_STS 0x1024 +#define N3000_NIOS_PKVL_MODE_STS_GROUP_MSK GENMASK(15, 8) +#define N3000_NIOS_PKVL_MODE_STS_GROUP_OK 0x0 +#define N3000_NIOS_PKVL_MODE_STS_ID_MSK GENMASK(7, 0) +/* When GROUP MASK field == GROUP_OK */ +#define N3000_NIOS_PKVL_MODE_ID_RESET 0x0 +#define N3000_NIOS_PKVL_MODE_ID_4X10G 0x1 +#define N3000_NIOS_PKVL_MODE_ID_4X25G 0x2 +#define N3000_NIOS_PKVL_MODE_ID_2X25G 0x3 +#define N3000_NIOS_PKVL_MODE_ID_2X25G_2X10G 0x4 +#define N3000_NIOS_PKVL_MODE_ID_1X25G 0x5 + +#define N3000_NIOS_REGBUS_RETRY_COUNT 10000 /* loop count */ + +#define N3000_NIOS_INIT_TIMEOUT 10000000 /* usec */ +#define N3000_NIOS_INIT_TIME_INTV 100000 /* usec */ + +#define N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL \ + (N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK | \ + N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK) + +#define N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL \ + (FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_NO)) + +#define N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL \ + (FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_KR)) + +#define N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL \ + (FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \ + FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \ + N3000_NIOS_INIT_REQ_FEC_MODE_RS)) + +struct n3000_nios { + void __iomem *base; + struct regmap *regmap; + struct device *dev; + struct platform_device *altera_spi; +}; + +static ssize_t nios_fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct n3000_nios *nn = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%x.%x.%x\n", + (u8)FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val), + (u8)FIELD_GET(N3000_NIOS_FW_VERSION_MINOR, val), + (u8)FIELD_GET(N3000_NIOS_FW_VERSION_PATCH, val)); +} +static DEVICE_ATTR_RO(nios_fw_version); + +#define IS_MODE_STATUS_OK(mode_stat) \ + (FIELD_GET(N3000_NIOS_PKVL_MODE_STS_GROUP_MSK, (mode_stat)) == \ + N3000_NIOS_PKVL_MODE_STS_GROUP_OK) + +#define IS_RETIMER_FEC_SUPPORTED(retimer_mode) \ + ((retimer_mode) != N3000_NIOS_PKVL_MODE_ID_RESET && \ + (retimer_mode) != N3000_NIOS_PKVL_MODE_ID_4X10G) + +static int get_retimer_mode(struct n3000_nios *nn, unsigned int mode_stat_reg, + unsigned int *retimer_mode) +{ + unsigned int val; + int ret; + + ret = regmap_read(nn->regmap, mode_stat_reg, &val); + if (ret) + return ret; + + if (!IS_MODE_STATUS_OK(val)) + return -EFAULT; + + *retimer_mode = FIELD_GET(N3000_NIOS_PKVL_MODE_STS_ID_MSK, val); + + return 0; +} + +static ssize_t retimer_A_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct n3000_nios *nn = dev_get_drvdata(dev); + unsigned int mode; + int ret; + + ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &mode); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%x\n", mode); +} +static DEVICE_ATTR_RO(retimer_A_mode); + +static ssize_t retimer_B_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct n3000_nios *nn = dev_get_drvdata(dev); + unsigned int mode; + int ret; + + ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &mode); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%x\n", mode); +} +static DEVICE_ATTR_RO(retimer_B_mode); + +static ssize_t fec_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int val, retimer_a_mode, retimer_b_mode, fec_modes; + struct n3000_nios *nn = dev_get_drvdata(dev); + int ret; + + /* FEC mode setting is not supported in early FW versions */ + ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val); + if (ret) + return ret; + + if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) < 3) + return sysfs_emit(buf, "not supported\n"); + + /* If no 25G links, FEC mode setting is not supported either */ + ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &retimer_a_mode); + if (ret) + return ret; + + ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &retimer_b_mode); + if (ret) + return ret; + + if (!IS_RETIMER_FEC_SUPPORTED(retimer_a_mode) && + !IS_RETIMER_FEC_SUPPORTED(retimer_b_mode)) + return sysfs_emit(buf, "not supported\n"); + + /* get the valid FEC mode for 25G links */ + ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val); + if (ret) + return ret; + + /* + * FEC mode should always be the same for all links, as we set them + * in this way. + */ + fec_modes = (val & N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL); + if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL) + return sysfs_emit(buf, "no\n"); + else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL) + return sysfs_emit(buf, "kr\n"); + else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL) + return sysfs_emit(buf, "rs\n"); + + return -EFAULT; +} +static DEVICE_ATTR_RO(fec_mode); + +static struct attribute *n3000_nios_attrs[] = { + &dev_attr_nios_fw_version.attr, + &dev_attr_retimer_A_mode.attr, + &dev_attr_retimer_B_mode.attr, + &dev_attr_fec_mode.attr, + NULL, +}; +ATTRIBUTE_GROUPS(n3000_nios); + +static int n3000_nios_init_done_check(struct n3000_nios *nn) +{ + unsigned int val, state_a, state_b; + struct device *dev = nn->dev; + int ret, ret2; + + /* + * The SPI is shared by the Nios core inside the FPGA, Nios will use + * this SPI master to do some one time initialization after power up, + * and then release the control to OS. The driver needs to poll on + * INIT_DONE to see when driver could take the control. + * + * Please note that after Nios firmware version 3.0.0, INIT_START is + * introduced, so driver needs to trigger START firstly and then check + * INIT_DONE. + */ + + ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val); + if (ret) + return ret; + + /* + * If Nios version register is totally uninitialized(== 0x0), then the + * Nios firmware is missing. So host could take control of SPI master + * safely, but initialization work for Nios is not done. To restore the + * card, we need to reprogram a new Nios firmware via the BMC chip on + * SPI bus. So the driver doesn't error out, it continues to create the + * spi controller device and spi_board_info for BMC. + */ + if (val == 0) { + dev_err(dev, "Nios version reg = 0x%x, skip INIT_DONE check, but the retimer may be uninitialized\n", + val); + return 0; + } + + if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) >= 3) { + /* read NIOS_INIT to check if retimer initialization is done */ + ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val); + if (ret) + return ret; + + /* check if retimers are initialized already */ + if (val & (N3000_NIOS_INIT_DONE | N3000_NIOS_INIT_START)) + goto nios_init_done; + + /* configure FEC mode per module param */ + val = N3000_NIOS_INIT_START; + + /* + * When the retimer is to be set to 10G mode, there is no FEC + * mode setting, so the REQ_FEC_MODE field will be ignored by + * Nios firmware in this case. But we should still fill the FEC + * mode field cause host could not get the retimer working mode + * until the Nios init is done. + * + * For now the driver doesn't support the retimer FEC mode + * switching per user's request. It is always set to Reed + * Solomon FEC. + * + * The driver will set the same FEC mode for all links. + */ + val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL; + + ret = regmap_write(nn->regmap, N3000_NIOS_INIT, val); + if (ret) + return ret; + } + +nios_init_done: + /* polls on NIOS_INIT_DONE */ + ret = regmap_read_poll_timeout(nn->regmap, N3000_NIOS_INIT, val, + val & N3000_NIOS_INIT_DONE, + N3000_NIOS_INIT_TIME_INTV, + N3000_NIOS_INIT_TIMEOUT); + if (ret) + dev_err(dev, "NIOS_INIT_DONE %s\n", + (ret == -ETIMEDOUT) ? "timed out" : "check error"); + + ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_A_MODE_STS, &state_a); + if (ret2) + return ret2; + + ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_B_MODE_STS, &state_b); + if (ret2) + return ret2; + + if (!ret) { + /* + * After INIT_DONE is detected, it still needs to check if the + * Nios firmware reports any error during the retimer + * configuration. + */ + if (IS_MODE_STATUS_OK(state_a) && IS_MODE_STATUS_OK(state_b)) + return 0; + + /* + * If the retimer configuration is failed, the Nios firmware + * will still release the spi controller for host to + * communicate with the BMC. It makes possible for people to + * reprogram a new Nios firmware and restore the card. So the + * driver doesn't error out, it continues to create the spi + * controller device and spi_board_info for BMC. + */ + dev_err(dev, "NIOS_INIT_DONE OK, but err on retimer init\n"); + } + + dev_err(nn->dev, "PKVL_A_MODE_STS 0x%x\n", state_a); + dev_err(nn->dev, "PKVL_B_MODE_STS 0x%x\n", state_b); + + return ret; +} + +static struct spi_board_info m10_n3000_info = { + .modalias = "m10-n3000", + .max_speed_hz = 12500000, + .bus_num = 0, + .chip_select = 0, +}; + +static int create_altera_spi_controller(struct n3000_nios *nn) +{ + struct altera_spi_platform_data pdata = { 0 }; + struct platform_device_info pdevinfo = { 0 }; + void __iomem *base = nn->base; + u64 v; + + v = readq(base + N3000_NS_PARAM); + + pdata.mode_bits = SPI_CS_HIGH; + if (FIELD_GET(N3000_NS_PARAM_CLK_POL, v)) + pdata.mode_bits |= SPI_CPOL; + if (FIELD_GET(N3000_NS_PARAM_CLK_PHASE, v)) + pdata.mode_bits |= SPI_CPHA; + + pdata.num_chipselect = FIELD_GET(N3000_NS_PARAM_NUM_CS, v); + pdata.bits_per_word_mask = + SPI_BPW_RANGE_MASK(1, FIELD_GET(N3000_NS_PARAM_DATA_WIDTH, v)); + + pdata.num_devices = 1; + pdata.devices = &m10_n3000_info; + + dev_dbg(nn->dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__, + pdata.num_chipselect, pdata.bits_per_word_mask, + pdata.mode_bits); + + pdevinfo.name = "subdev_spi_altera"; + pdevinfo.id = PLATFORM_DEVID_AUTO; + pdevinfo.parent = nn->dev; + pdevinfo.data = &pdata; + pdevinfo.size_data = sizeof(pdata); + + nn->altera_spi = platform_device_register_full(&pdevinfo); + return PTR_ERR_OR_ZERO(nn->altera_spi); +} + +static void destroy_altera_spi_controller(struct n3000_nios *nn) +{ + platform_device_unregister(nn->altera_spi); +} + +static int n3000_nios_poll_stat_timeout(void __iomem *base, u64 *v) +{ + int loops; + + /* + * We don't use the time based timeout here for performance. + * + * The regbus read/write is on the critical path of Intel PAC N3000 + * image programing. The time based timeout checking will add too much + * overhead on it. Usually the state changes in 1 or 2 loops on the + * test server, and we set 10000 times loop here for safety. + */ + for (loops = N3000_NIOS_REGBUS_RETRY_COUNT; loops > 0 ; loops--) { + *v = readq(base + N3000_NS_STAT); + if (*v & N3000_NS_STAT_RW_VAL) + break; + cpu_relax(); + } + + return (loops > 0) ? 0 : -ETIMEDOUT; +} + +static int n3000_nios_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct n3000_nios *nn = context; + u64 v; + int ret; + + v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_WR) | + FIELD_PREP(N3000_NS_CTRL_ADDR, reg) | + FIELD_PREP(N3000_NS_CTRL_WR_DATA, val); + writeq(v, nn->base + N3000_NS_CTRL); + + ret = n3000_nios_poll_stat_timeout(nn->base, &v); + if (ret) + dev_err(nn->dev, "fail to write reg 0x%x val 0x%x: %d\n", + reg, val, ret); + + return ret; +} + +static int n3000_nios_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct n3000_nios *nn = context; + u64 v; + int ret; + + v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_RD) | + FIELD_PREP(N3000_NS_CTRL_ADDR, reg); + writeq(v, nn->base + N3000_NS_CTRL); + + ret = n3000_nios_poll_stat_timeout(nn->base, &v); + if (ret) + dev_err(nn->dev, "fail to read reg 0x%x: %d\n", reg, ret); + else + *val = FIELD_GET(N3000_NS_STAT_RD_DATA, v); + + return ret; +} + +static const struct regmap_config n3000_nios_regbus_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + + .reg_write = n3000_nios_reg_write, + .reg_read = n3000_nios_reg_read, +}; + +static int n3000_nios_probe(struct dfl_device *ddev) +{ + struct device *dev = &ddev->dev; + struct n3000_nios *nn; + int ret; + + nn = devm_kzalloc(dev, sizeof(*nn), GFP_KERNEL); + if (!nn) + return -ENOMEM; + + dev_set_drvdata(&ddev->dev, nn); + + nn->dev = dev; + + nn->base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res); + if (IS_ERR(nn->base)) + return PTR_ERR(nn->base); + + nn->regmap = devm_regmap_init(dev, NULL, nn, &n3000_nios_regbus_cfg); + if (IS_ERR(nn->regmap)) + return PTR_ERR(nn->regmap); + + ret = n3000_nios_init_done_check(nn); + if (ret) + return ret; + + ret = create_altera_spi_controller(nn); + if (ret) + dev_err(dev, "altera spi controller create failed: %d\n", ret); + + return ret; +} + +static void n3000_nios_remove(struct dfl_device *ddev) +{ + struct n3000_nios *nn = dev_get_drvdata(&ddev->dev); + + destroy_altera_spi_controller(nn); +} + +#define FME_FEATURE_ID_N3000_NIOS 0xd + +static const struct dfl_device_id n3000_nios_ids[] = { + { FME_ID, FME_FEATURE_ID_N3000_NIOS }, + { } +}; +MODULE_DEVICE_TABLE(dfl, n3000_nios_ids); + +static struct dfl_driver n3000_nios_driver = { + .drv = { + .name = "dfl-n3000-nios", + .dev_groups = n3000_nios_groups, + }, + .id_table = n3000_nios_ids, + .probe = n3000_nios_probe, + .remove = n3000_nios_remove, +}; + +module_dfl_driver(n3000_nios_driver); + +MODULE_DESCRIPTION("Driver for Nios private feature on Intel PAC N3000"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); From patchwork Thu Dec 10 16:58:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Moritz Fischer X-Patchwork-Id: 11965621 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=-17.0 required=3.0 tests=BAYES_00,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 A9C71C433FE for ; Thu, 10 Dec 2020 16:59:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 76A3023BE5 for ; Thu, 10 Dec 2020 16:59:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2392369AbgLJQ7Y (ORCPT ); Thu, 10 Dec 2020 11:59:24 -0500 Received: from mail-pf1-f180.google.com ([209.85.210.180]:42760 "EHLO mail-pf1-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731400AbgLJQ7Q (ORCPT ); Thu, 10 Dec 2020 11:59:16 -0500 Received: by mail-pf1-f180.google.com with SMTP id 131so4653794pfb.9 for ; Thu, 10 Dec 2020 08:59:00 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9Jgm2nqfpaiT7ZHURhtzV6pP11aFn7fPtwRSdjvlJeQ=; b=kiYe4XR77K+7WaA6N2R45eLc2C5pJ0gq3kFw1pMSp1DBUys/U58P+qGG+ohVXXmiJ7 545cZ1z4ho77uOT6cWQgzSW1HuwyLimTRY5obkHkX6uedoAVNGx7QBL6r55V8/uPBjqg sHCEKS/BoK1eZ0Tpf6/CsKfX8jHpyajulUuTceNqq73GLfK2Drw4+Z2yU/l9NXEvQwvW G6FEx+iTYZ7mPjgW9w6sBUDdX6VRFIDlSung6HmQGAi42ARjbI3zrgz8ZP8rkoDv9iNH UpY0L9DWBxcz5zdh3/wKQKRDMZGAVFoaLGp7+FkbRtLnKmbTkV931uEM00r85FIkIPPd MagQ== X-Gm-Message-State: AOAM533JQlG0TCFuEQKdsm/p3S6WjF2DzMhRqvw82pRrbSRohSyGJUf9 yVi2coiAG0/9MGuZqdzjDzU= X-Google-Smtp-Source: ABdhPJwtekABbysExT2vZ1BBNHAF++A4bgHRtW7W5f02VEC07Tfy9lVSzp8EFxNwJnMQmQHkz+Dz8w== X-Received: by 2002:a17:90b:2392:: with SMTP id mr18mr8436265pjb.225.1607619514925; Thu, 10 Dec 2020 08:58:34 -0800 (PST) Received: from localhost ([2601:647:5b00:1162:1ac0:17a6:4cc6:d1ef]) by smtp.gmail.com with ESMTPSA id y22sm6647626pgi.35.2020.12.10.08.58.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 08:58:34 -0800 (PST) From: Moritz Fischer To: gregkh@linuxfoundation.org Cc: linux-fpga@vger.kernel.org, trix@redhat.com, hao.wu@intel.com, yilun.xu@intel.com, russell.h.weight@intel.com, Krzysztof Kozlowski , Moritz Fischer Subject: [PATCH 8/8] memory: dfl-emif: add the DFL EMIF private feature driver Date: Thu, 10 Dec 2020 08:58:04 -0800 Message-Id: <20201210165804.44234-9-mdf@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201210165804.44234-1-mdf@kernel.org> References: <20201210165804.44234-1-mdf@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fpga@vger.kernel.org From: Xu Yilun This driver is for the EMIF private feature implemented under FPGA Device Feature List (DFL) framework. It is used to expose memory interface status information as well as memory clearing control. The purpose of memory clearing block is to zero out all private memory when FPGA is to be reprogrammed. This gives users a reliable method to prevent potential data leakage. Signed-off-by: Xu Yilun Signed-off-by: Russ Weight Reviewed-by: Tom Rix Acked-by: Krzysztof Kozlowski Signed-off-by: Moritz Fischer --- .../ABI/testing/sysfs-bus-dfl-devices-emif | 25 +++ drivers/memory/Kconfig | 9 + drivers/memory/Makefile | 2 + drivers/memory/dfl-emif.c | 207 ++++++++++++++++++ 4 files changed, 243 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-dfl-devices-emif create mode 100644 drivers/memory/dfl-emif.c diff --git a/Documentation/ABI/testing/sysfs-bus-dfl-devices-emif b/Documentation/ABI/testing/sysfs-bus-dfl-devices-emif new file mode 100644 index 000000000000..1ae8ebd15b93 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-dfl-devices-emif @@ -0,0 +1,25 @@ +What: /sys/bus/dfl/devices/dfl_dev.X/infX_cal_fail +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. It indicates if the calibration failed on this + memory interface. "1" for calibration failure, "0" for OK. + Format: %u + +What: /sys/bus/dfl/devices/dfl_dev.X/infX_init_done +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Read-only. It indicates if the initialization completed on + this memory interface. "1" for initialization complete, "0" + for not yet. + Format: %u + +What: /sys/bus/dfl/devices/dfl_dev.X/infX_clear +Date: Oct 2020 +KernelVersion: 5.11 +Contact: Xu Yilun +Description: Write-only. Writing "1" to this file will zero out all memory + data in this memory interface. Writing of other values is + invalid. + Format: %u diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 00e013b14703..2495bc4913e2 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -137,6 +137,15 @@ config TI_EMIF_SRAM sequence so this driver provides several relocatable PM functions for the SoC PM code to use. +config FPGA_DFL_EMIF + tristate "FPGA DFL EMIF Driver" + depends on FPGA_DFL && HAS_IOMEM + help + This driver is for the EMIF private feature implemented under + FPGA Device Feature List (DFL) framework. It is used to expose + memory interface status information as well as memory clearing + control. + config MVEBU_DEVBUS bool "Marvell EBU Device Bus Controller" default y if PLAT_ORION diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index e71cf7b99641..bc7663ed1c25 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o obj-$(CONFIG_SAMSUNG_MC) += samsung/ obj-$(CONFIG_TEGRA_MC) += tegra/ obj-$(CONFIG_TI_EMIF_SRAM) += ti-emif-sram.o +obj-$(CONFIG_FPGA_DFL_EMIF) += dfl-emif.o + ti-emif-sram-objs := ti-emif-pm.o ti-emif-sram-pm.o AFLAGS_ti-emif-sram-pm.o :=-Wa,-march=armv7-a diff --git a/drivers/memory/dfl-emif.c b/drivers/memory/dfl-emif.c new file mode 100644 index 000000000000..3f719816771d --- /dev/null +++ b/drivers/memory/dfl-emif.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DFL device driver for EMIF private feature + * + * Copyright (C) 2020 Intel Corporation, Inc. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FME_FEATURE_ID_EMIF 0x9 + +#define EMIF_STAT 0x8 +#define EMIF_STAT_INIT_DONE_SFT 0 +#define EMIF_STAT_CALC_FAIL_SFT 8 +#define EMIF_STAT_CLEAR_BUSY_SFT 16 +#define EMIF_CTRL 0x10 +#define EMIF_CTRL_CLEAR_EN_SFT 0 +#define EMIF_CTRL_CLEAR_EN_MSK GENMASK_ULL(3, 0) + +#define EMIF_POLL_INVL 10000 /* us */ +#define EMIF_POLL_TIMEOUT 5000000 /* us */ + +struct dfl_emif { + struct device *dev; + void __iomem *base; + spinlock_t lock; /* Serialises access to EMIF_CTRL reg */ +}; + +struct emif_attr { + struct device_attribute attr; + u32 shift; + u32 index; +}; + +#define to_emif_attr(dev_attr) \ + container_of(dev_attr, struct emif_attr, attr) + +static ssize_t emif_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct emif_attr *eattr = to_emif_attr(attr); + struct dfl_emif *de = dev_get_drvdata(dev); + u64 val; + + val = readq(de->base + EMIF_STAT); + + return sysfs_emit(buf, "%u\n", + !!(val & BIT_ULL(eattr->shift + eattr->index))); +} + +static ssize_t emif_clear_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct emif_attr *eattr = to_emif_attr(attr); + struct dfl_emif *de = dev_get_drvdata(dev); + u64 clear_busy_msk, clear_en_msk, val; + void __iomem *base = de->base; + + if (!sysfs_streq(buf, "1")) + return -EINVAL; + + clear_busy_msk = BIT_ULL(EMIF_STAT_CLEAR_BUSY_SFT + eattr->index); + clear_en_msk = BIT_ULL(EMIF_CTRL_CLEAR_EN_SFT + eattr->index); + + spin_lock(&de->lock); + /* The CLEAR_EN field is WO, but other fields are RW */ + val = readq(base + EMIF_CTRL); + val &= ~EMIF_CTRL_CLEAR_EN_MSK; + val |= clear_en_msk; + writeq(val, base + EMIF_CTRL); + spin_unlock(&de->lock); + + if (readq_poll_timeout(base + EMIF_STAT, val, + !(val & clear_busy_msk), + EMIF_POLL_INVL, EMIF_POLL_TIMEOUT)) { + dev_err(de->dev, "timeout, fail to clear\n"); + return -ETIMEDOUT; + } + + return count; +} + +#define emif_state_attr(_name, _shift, _index) \ + static struct emif_attr emif_attr_##inf##_index##_##_name = \ + { .attr = __ATTR(inf##_index##_##_name, 0444, \ + emif_state_show, NULL), \ + .shift = (_shift), .index = (_index) } + +#define emif_clear_attr(_index) \ + static struct emif_attr emif_attr_##inf##_index##_clear = \ + { .attr = __ATTR(inf##_index##_clear, 0200, \ + NULL, emif_clear_store), \ + .index = (_index) } + +emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 0); +emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 1); +emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 2); +emif_state_attr(init_done, EMIF_STAT_INIT_DONE_SFT, 3); + +emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 0); +emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 1); +emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 2); +emif_state_attr(cal_fail, EMIF_STAT_CALC_FAIL_SFT, 3); + +emif_clear_attr(0); +emif_clear_attr(1); +emif_clear_attr(2); +emif_clear_attr(3); + +static struct attribute *dfl_emif_attrs[] = { + &emif_attr_inf0_init_done.attr.attr, + &emif_attr_inf0_cal_fail.attr.attr, + &emif_attr_inf0_clear.attr.attr, + + &emif_attr_inf1_init_done.attr.attr, + &emif_attr_inf1_cal_fail.attr.attr, + &emif_attr_inf1_clear.attr.attr, + + &emif_attr_inf2_init_done.attr.attr, + &emif_attr_inf2_cal_fail.attr.attr, + &emif_attr_inf2_clear.attr.attr, + + &emif_attr_inf3_init_done.attr.attr, + &emif_attr_inf3_cal_fail.attr.attr, + &emif_attr_inf3_clear.attr.attr, + + NULL, +}; + +static umode_t dfl_emif_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct dfl_emif *de = dev_get_drvdata(kobj_to_dev(kobj)); + struct emif_attr *eattr = container_of(attr, struct emif_attr, + attr.attr); + u64 val; + + /* + * This device supports upto 4 memory interfaces, but not all + * interfaces are used on different platforms. The read out value of + * CLEAN_EN field (which is a bitmap) could tell how many interfaces + * are available. + */ + val = FIELD_GET(EMIF_CTRL_CLEAR_EN_MSK, readq(de->base + EMIF_CTRL)); + + return (val & BIT_ULL(eattr->index)) ? attr->mode : 0; +} + +static const struct attribute_group dfl_emif_group = { + .is_visible = dfl_emif_visible, + .attrs = dfl_emif_attrs, +}; + +static const struct attribute_group *dfl_emif_groups[] = { + &dfl_emif_group, + NULL, +}; + +static int dfl_emif_probe(struct dfl_device *ddev) +{ + struct device *dev = &ddev->dev; + struct dfl_emif *de; + + de = devm_kzalloc(dev, sizeof(*de), GFP_KERNEL); + if (!de) + return -ENOMEM; + + de->base = devm_ioremap_resource(dev, &ddev->mmio_res); + if (IS_ERR(de->base)) + return PTR_ERR(de->base); + + de->dev = dev; + spin_lock_init(&de->lock); + dev_set_drvdata(dev, de); + + return 0; +} + +static const struct dfl_device_id dfl_emif_ids[] = { + { FME_ID, FME_FEATURE_ID_EMIF }, + { } +}; +MODULE_DEVICE_TABLE(dfl, dfl_emif_ids); + +static struct dfl_driver dfl_emif_driver = { + .drv = { + .name = "dfl-emif", + .dev_groups = dfl_emif_groups, + }, + .id_table = dfl_emif_ids, + .probe = dfl_emif_probe, +}; +module_dfl_driver(dfl_emif_driver); + +MODULE_DESCRIPTION("DFL EMIF driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2");