lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20201117075626.GA14665@yilunxu-OptiPlex-7050>
Date:   Tue, 17 Nov 2020 15:56:26 +0800
From:   Xu Yilun <yilun.xu@...el.com>
To:     matthew.gerlach@...ux.intel.com
Cc:     linux-fpga@...r.kernel.org, linux-kernel@...r.kernel.org,
        mdf@...nel.org, hao.wu@...el.com, trix@...hat.com,
        linux-doc@...r.kernel.org, corbet@....net, yilun.xu@...el.com
Subject: Re: [PATCH 2/2] fpga: dfl: look for vendor specific capability

On Mon, Nov 16, 2020 at 05:25:52PM -0800, matthew.gerlach@...ux.intel.com wrote:
> From: Matthew Gerlach <matthew.gerlach@...ux.intel.com>
> 
> A DFL may not begin at offset 0 of BAR 0.  A PCIe vendor
> specific capability can be used to specify the start of a
> number of DFLs.
> 
> Signed-off-by: Matthew Gerlach <matthew.gerlach@...ux.intel.com>
> ---
>  Documentation/fpga/dfl.rst | 10 +++++
>  drivers/fpga/dfl-pci.c     | 88 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 97 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst
> index 0404fe6ffc74..c81ceb1e79e2 100644
> --- a/Documentation/fpga/dfl.rst
> +++ b/Documentation/fpga/dfl.rst
> @@ -501,6 +501,16 @@ 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 PCI bus
> +===========================
> +The start of the DFL is assumed to be offset 0 of bar 0.
> +Alternatively, a vendor specific capability structure can be used to
> +specify the location of one or more DFLs.  Intel has reserved the
> +vendor specific id of 0x43 for this purpose.  The vendor specific
> +data begins with a 4 byte count of the number of DFLs followed 4 byte
> +Offset/BIR fields for each DFL. Bits 2:0 of Offset/BIR field indicates
> +the BAR, and bits 31:3 form the 8 byte aligned offset where bits 2:0 are
> +zero.
>  
>  Open discussion
>  ===============
> diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c
> index b1b157b41942..5418e8bf2496 100644
> --- a/drivers/fpga/dfl-pci.c
> +++ b/drivers/fpga/dfl-pci.c
> @@ -27,6 +27,13 @@
>  #define DRV_VERSION	"0.8"
>  #define DRV_NAME	"dfl-pci"
>  
> +#define PCI_VNDR_ID_DFLS 0x43
> +
> +#define PCI_VNDR_DFLS_CNT_OFFSET 8
> +#define PCI_VNDR_DFLS_RES_OFFSET 0x0c
> +
> +#define PCI_VND_DFLS_RES_BAR_MASK 0x7

We could define the mask by GENMASK().

Also another macro PCI_VND_DFLS_RES_OFFSET_MASK is needed.

> +
>  struct cci_drvdata {
>  	struct dfl_fpga_cdev *cdev;	/* container device */
>  };
> @@ -119,6 +126,82 @@ static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
>  	return table;
>  }
>  
> +static int find_dfl_in_cfg(struct pci_dev *pcidev,
> +			   struct dfl_fpga_enum_info *info)
> +{
> +	u32 bar, offset, vndr_hdr, dfl_cnt, dfl_res;
> +	int dfl_res_off, i, voff = 0;
> +	resource_size_t start, len;
> +
> +	while ((voff = pci_find_next_ext_capability(pcidev, voff, PCI_EXT_CAP_ID_VNDR))) {
> +
> +		pci_read_config_dword(pcidev, voff + PCI_VNDR_HEADER, &vndr_hdr);
> +
> +		dev_dbg(&pcidev->dev,
> +			"vendor-specific capability id 0x%x, rev 0x%x len 0x%x\n",
> +			PCI_VNDR_HEADER_ID(vndr_hdr),
> +			PCI_VNDR_HEADER_REV(vndr_hdr),
> +			PCI_VNDR_HEADER_LEN(vndr_hdr));
> +
> +		if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VNDR_ID_DFLS)
> +			break;
> +	}
> +
> +	if (!voff) {
> +		dev_dbg(&pcidev->dev, "%s no VSEC found\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	pci_read_config_dword(pcidev, voff + PCI_VNDR_DFLS_CNT_OFFSET, &dfl_cnt);
> +	dev_info(&pcidev->dev, "dfl_cnt %d\n", dfl_cnt);

dev_dbg() is better?

> +	for (i = 0; i < dfl_cnt; i++) {
> +		dfl_res_off = voff + PCI_VNDR_DFLS_RES_OFFSET +
> +				      (i * sizeof(dfl_res));
> +		pci_read_config_dword(pcidev, dfl_res_off, &dfl_res);
> +
> +		dev_dbg(&pcidev->dev, "dfl_res 0x%x\n", dfl_res);
> +
> +		bar = dfl_res & PCI_VND_DFLS_RES_BAR_MASK;

FIELD_GET is better?

> +
> +		if (bar >= PCI_STD_NUM_BARS) {
> +			dev_err(&pcidev->dev, "%s bad bar number %d\n",
> +				__func__, bar);
> +			return -EINVAL;
> +		}
> +
> +		len = pci_resource_len(pcidev, bar);
> +
> +		if (len == 0) {
> +			dev_err(&pcidev->dev, "%s unmapped bar number %d\n",
> +				__func__, bar);
> +			return -EINVAL;
> +		}
> +
> +		offset = dfl_res & ~PCI_VND_DFLS_RES_BAR_MASK;

ditto

> +
> +		if (offset >= len) {
> +			dev_err(&pcidev->dev, "%s bad offset %u >= %llu\n",
> +				__func__, offset, len);
> +			return -EINVAL;
> +		}
> +
> +		dev_info(&pcidev->dev, "%s BAR %d offset 0x%x\n", __func__, bar, offset);

dev_dbg()?

> +
> +		start = pci_resource_start(pcidev, bar) + offset;
> +		len -= offset;

With these code, I have the following assumption:

1. There is only one DFL in one bar, multiple DFLs requires multiple
bars.

2. The DFL region is from the "offset" to the end of the bar.

Are they correct? If yes maybe we should specify them clearly in Doc.

> +
> +		if (!PAGE_ALIGNED(start)) {
> +			dev_err(&pcidev->dev, "%s unaliged start 0x%llx\n",
> +				__func__, start);
> +			return -EINVAL;
> +		}
> +
> +		dfl_fpga_enum_info_add_dfl(info, start, len);

Do we need some region overlapping check in this func? So we could find
the HW problem (e.g. same bar num for multiple DFLs) in early stage.

> +	}
> +
> +	return 0;
> +}
> +
>  static int find_dfl_in_bar0(struct pci_dev *pcidev,
>  			    struct dfl_fpga_enum_info *info)
>  {
> @@ -221,7 +304,10 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
>  			goto irq_free_exit;
>  	}
>  
> -	ret = find_dfl_in_bar0(pcidev, info);
> +	ret = find_dfl_in_cfg(pcidev, info);
> +
> +	if (ret)
> +		ret = find_dfl_in_bar0(pcidev, info);

The patch is more than the relocation support for DFL. Actually it
introduced a different way of DFL finding.

Previously it starts at bar0 offset 0, find dfl fme first, then find
dfl port according to fme header registers. Now it enumerates every DFL
by PCIe VSEC.

Maybe we should add more description about the change and why.

Thanks,
Yilun

>  
>  	if (ret)
>  		goto irq_free_exit;
> -- 
> 2.25.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ