Skip to content

Commit

Permalink
fpga: dfl: look for vendor specific capability
Browse files Browse the repository at this point in the history
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@linux.intel.com>
  • Loading branch information
matthew-gerlach authored and intel-lab-lkp committed Nov 17, 2020
1 parent 5aaffa2 commit b7db30a
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Documentation/fpga/dfl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
===============
Expand Down
88 changes: 87 additions & 1 deletion drivers/fpga/dfl-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

struct cci_drvdata {
struct dfl_fpga_cdev *cdev; /* container device */
};
Expand Down Expand Up @@ -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);
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;

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;

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);

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

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);
}

return 0;
}

static int find_dfl_in_bar0(struct pci_dev *pcidev,
struct dfl_fpga_enum_info *info)
{
Expand Down Expand Up @@ -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);

if (ret)
goto irq_free_exit;
Expand Down

0 comments on commit b7db30a

Please sign in to comment.