Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp1458354ybz; Wed, 22 Apr 2020 22:14:49 -0700 (PDT) X-Google-Smtp-Source: APiQypIS6jXOOY9GZuTjmJ89JfXG7yJXnXC8LK48xWfRiQKuBhpsqhuJc7sk0bMNNlnCi0rQ7DtH X-Received: by 2002:a17:906:304d:: with SMTP id d13mr1196678ejd.159.1587618889821; Wed, 22 Apr 2020 22:14:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1587618889; cv=none; d=google.com; s=arc-20160816; b=pyR60u5mzQazwbK0YDa1lZ0KJ/yVks5GI8M3NboLfMXP6MbPiOIPoKQ00axkzKVjXk Rc6+5pXQvfKsW7iY1dRn06AKgiiD0DLAocIqRw9KEN0EZBbAQOgavDCsArWyHA9AdvNE Iy4Evo7sK1ZRJ1MkJo5lWGlny8OwnPasobG3dG7/LxrIVX5OlTAM/QOSKjNFelRFO9yN cwMUqtKA5DVl210wiYjay8ZGyBc4vnnoQG9PK4xw7/bAPIgTBSY5PQfJBFa7SvfNjx7r Agc4VXbuPjeH1q5jmzjMsekAYgbCuRrzf5xrsKVDG3+OXeFRUqPvwbfuaxcZGlPajPRg 8KyA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:ironport-sdr:ironport-sdr; bh=ADuaWoB7m4qbZQPPaWL48yqx2crR1cXUjG3tw50DDIQ=; b=aBMTkcJKxmxok8mnuyuv+yzan/xp6JDt/Px6Fy+ulqqcHGR1Fxv0ME2NvBNnUeEn1r TzTN5hwiuOd7ahkTEHUFfhsiV+BeGoRTMO/trDMCfwJ9UzcaexUFl6u64maNKTyPyElH FYX85zjgMiEBg3S91ljDJq+JXB74nbulDCCz82FpMbb2I8WPUewJsZAjNhOoi8YnB5Jl ziZf/4F5NIcAE6/lHkF/G4+5bNkQhINiPO1IGd2K6Ktc6ogz+WD8203iMvdHX6Fsmk3z D2FQjtkxfRmtOn7ts3wKeeKvp0SH/r2G/boZ981y5+UTScnVpPIf0iG7BtluWsV72ERZ imiw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id y14si665083edm.185.2020.04.22.22.14.27; Wed, 22 Apr 2020 22:14:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726496AbgDWFMW (ORCPT + 99 others); Thu, 23 Apr 2020 01:12:22 -0400 Received: from mga11.intel.com ([192.55.52.93]:37814 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725961AbgDWFMV (ORCPT ); Thu, 23 Apr 2020 01:12:21 -0400 IronPort-SDR: WrhYc+t6JOklM1PUaz60L6OKaRrTcVjckYaBWBGx7BZJjlvDplEinWkHLxDnQgIQhTcpC4XtnV 3vzqHIQliPQQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 22:12:21 -0700 IronPort-SDR: CaLeYimjrE1X7uWVc9FtYpX1vYLIdIO3dWZk/8E64x85IpEKhr0IbiEnZ4StGXbr+va5BgiGpm 84jyyHJAt8tQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,305,1583222400"; d="scan'208";a="365895105" Received: from yilunxu-optiplex-7050.sh.intel.com (HELO localhost) ([10.239.159.141]) by fmsmga001.fm.intel.com with ESMTP; 22 Apr 2020 22:12:19 -0700 Date: Thu, 23 Apr 2020 13:09:34 +0800 From: Xu Yilun To: Moritz Fischer Cc: Sascha Hauer , linux-fpga@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: How to upload fpga firmware Message-ID: <20200423050934.GC30060@yilunxu-OptiPlex-7050> References: <20200422114432.GM1694@pengutronix.de> <20200423013648.GA2430@epycbox.lan> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200423013648.GA2430@epycbox.lan> User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Moritz: On Wed, Apr 22, 2020 at 06:36:48PM -0700, Moritz Fischer wrote: > Hi Sascha, > > On Wed, Apr 22, 2020 at 01:44:32PM +0200, Sascha Hauer wrote: > > Hi, > > > > I wonder what can be done with the mainline state of drivers/fpga/. The > > entry to the framework seems to be fpga_mgr_load(). The only user of > > this function is fpga_region_program_fpga(). This in turn is only called > > in response of applying a device tree overlay. A device tree overlay is > > applied with of_overlay_fdt_apply() which has no users in the Kernel. > > Yes. It is waiting for dt_overlays one way or another. I personally > don't currently have the bandwidth to work actively on this. > > > My current task is to load a firmware to a FPGA. The code all seems to > > be there in the Kernel, it only lacks a way to trigger it. I am not very > > interested in device tree overlays since the FPGA appears as a PCI > > device (although applying a dtbo could enable the PCIe controller device > > tree node). Is there some mainline way to upload FPGA firmware? At the > > moment we are using the attached patch to trigger loading the firmware > > from userspace. Would something like this be acceptable for mainline? > > We've looked into this sort of patches over the years and never came to > a general interface that really works. > > The OPAE folks (and other users I know of) usually use FPGA Manager with > a higher layer on top of it that moves the bitstream into the kernel via > an ioctl(). > > One concept I had toyed with mentally, but haven't really gotten around > to implement is a 'discoverable' region, that would deal with the > necessary re-enumeration via a callback and have a sysfs interface > similar to what the patch below has. > This would essentially cover use-cases where you have a discoverable > device implemented in FPGA logic, such as say an FPGA hanging off of > PCIe bus that can get loaded over USB, a CPLD or some other side-band > mechanism. After loading the image you'd have to rescan the PCIe bus - > which - imho is the kernel's job. Seems you mentioned the static region update. I have the pcie based FPGA card, and the pcie endpoint is implemented in FPGA static region. So after I have written image into Flash (over USB or other ways), and trying to load it to FPGA, the pcie endpoint is also disfunctional, the pcie device is actually lost. We need to rescan the pcie bus after loading is finished. The concern is that when the pcie device lost, the 'discoverable' region created by the pcie driver is also destroyed. When you rescaned the pcie device back, it is like everything is start over again (pci probe, fpga region creation, subdev enumeration ...) rather than just a re-enumeration callback for discoverable region. How do you think about it? > > What I really wanna avoid is creating another /dev/fpga0 / /dev/xdevcfg > that completely leaves the kernel in the dark about the fact that it > reconfigures a bit of hardware hanging off the bus. I have the FPGA board whose image binary for static region is stored in Flash. I was able to enumerate the Flash as MTD device and update it directly, (now switch to another interface for security support). Do you mean I should avoid doing that cause FPGA region device is unaware of the update? Some interface in FPGA region would be better choice? Thanks! > > In my ideal world you'd create a pci driver that binds to your device, > and creates mfd style subdevices for whatever you'd want your design to > do. One of these devices would be an FPGA and a FPGA region attached to > that FPGA manager. Your top level driver would co-ordinate the fact that > you are re-programming parts of the FPGA and create / destroy devices as > needed for the hardware contained in the bitstream. > > [..] > > +static ssize_t firmware_name_show(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct fpga_region *region = to_fpga_region(dev); > > + > > + if (!region->info || !region->info->firmware_name) > > + return 0; > > + > > + return sprintf(buf, "%s\n", region->info->firmware_name); > > +} > > + > > +static ssize_t firmware_name_store(struct device *dev, > > + struct device_attribute *attr, > > + const char *firmware_name, size_t count) > > +{ > > + struct fpga_region *region = to_fpga_region(dev); > > + struct fpga_image_info *info = region->info; > > + int error; > > + > > + if (!info) { > > + info = fpga_image_info_alloc(dev); > > + if (!info) > > + return -ENOMEM; > > + } else if (info->firmware_name) { > > + devm_kfree(dev, info->firmware_name); > > + } > > + > > + info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); > > + if (!info->firmware_name) > > + return -ENOMEM; > > + > > + if (count > 0 && info->firmware_name[count - 1] == '\n') > > + info->firmware_name[count - 1] = '\0'; > > + > > + region->info = info; > > + error = fpga_region_program_fpga(region); > > + if (error) { > > + devm_kfree(dev, info->firmware_name); > > + info->firmware_name = NULL; > > + } > > + > > + return error ? error : count; > > +} > > Cheers, > Moritz