Skip to content

Commit

Permalink
Merge tag 'fpga-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mdf/linux-fpga into char-misc-next

Moritz writes:

FPGA Manager changes for 5.9-rc1

Here is the (slightly larger than usual) patch set for the 5.9-rc1 merge
window.

DFL:
- Xu's changes add support for AFU interrupt handling and puts them to
  use for error handling.
- Xu's other change also adds another device-id for the Intel FPGA PAC N3000.
- John's change converts from using get_user_pages() to
  pin_user_pages().
- Gustavo's patch cleans up some of the allocation by using
  struct_size().

Xilinx:
- Luca's changes clean up the xilinx-spi and xilinx-slave-serial drivers
  and updates the comments and dt-bindings to reflect the fact it also
  supports 7 series devices.

Core:
- Tom cleaned up the fpga-bridge / fpga-mgr core by removing some
  dead-stores.

All patches have been reviewed on the mailing list, and have been in the
last few linux-next releases (as part of my for-next branch) without issues.

Signed-off-by: Moritz Fischer <mdf@kernel.org>

* tag 'fpga-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga:
  fpga: dfl: pci: add device id for Intel FPGA PAC N3000
  Documentation: fpga: dfl: add descriptions for interrupt related interfaces.
  fpga: dfl: afu: add AFU interrupt support
  fpga: dfl: fme: add interrupt support for global error reporting
  fpga: dfl: afu: add interrupt support for port error reporting
  fpga: dfl: introduce interrupt trigger setting API
  fpga: dfl: pci: add irq info for feature devices enumeration
  fpga: dfl: parse interrupt info for feature devices on enumeration
  fpga manager: xilinx-spi: check INIT_B pin during write_init
  dt-bindings: fpga: xilinx-slave-serial: add optional INIT_B GPIO
  fpga: Fix dead store in fpga-bridge.c
  fpga: Fix dead store fpga-mgr.c
  fpga: dfl: Use struct_size() in kzalloc()
  fpga manager: xilinx-spi: remove unneeded, mistyped variables
  fpga manager: xilinx-spi: valid for the 7 Series too
  dt-bindings: fpga: xilinx-slave-serial: valid for the 7 Series too
  fpga: dfl: afu: convert get_user_pages() --> pin_user_pages()
  • Loading branch information
gregkh committed Jul 23, 2020
2 parents 575ec5e + eacfbf5 commit cb0cec2
Show file tree
Hide file tree
Showing 14 changed files with 687 additions and 47 deletions.
16 changes: 12 additions & 4 deletions Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
Xilinx Slave Serial SPI FPGA Manager

Xilinx Spartan-6 FPGAs support a method of loading the bitstream over
what is referred to as "slave serial" interface.
Xilinx Spartan-6 and 7 Series FPGAs support a method of loading the
bitstream over what is referred to as "slave serial" interface.
The slave serial link is not technically SPI, and might require extra
circuits in order to play nicely with other SPI slaves on the same bus.

See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
See:
- https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
- https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
- https://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf

Required properties:
- compatible: should contain "xlnx,fpga-slave-serial"
- reg: spi chip select of the FPGA
- prog_b-gpios: config pin (referred to as PROGRAM_B in the manual)
- done-gpios: config status pin (referred to as DONE in the manual)

Optional properties:
- init-b-gpios: initialization status and configuration error pin
(referred to as INIT_B in the manual)

Example for full FPGA configuration:

fpga-region0 {
Expand All @@ -37,7 +44,8 @@ Example for full FPGA configuration:
spi-max-frequency = <60000000>;
spi-cpha;
reg = <0>;
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
init-b-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
};
};
19 changes: 19 additions & 0 deletions Documentation/fpga/dfl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ The following functions are exposed through ioctls:
- Program bitstream (DFL_FPGA_FME_PORT_PR)
- Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN)
- Release port from PF (DFL_FPGA_FME_PORT_RELEASE)
- Get number of irqs of FME global error (DFL_FPGA_FME_ERR_GET_IRQ_NUM)
- Set interrupt trigger for FME error (DFL_FPGA_FME_ERR_SET_IRQ)

More functions are exposed through sysfs
(/sys/class/fpga_region/regionX/dfl-fme.n/):
Expand Down Expand Up @@ -149,6 +151,10 @@ The following functions are exposed through ioctls:
- Map DMA buffer (DFL_FPGA_PORT_DMA_MAP)
- Unmap DMA buffer (DFL_FPGA_PORT_DMA_UNMAP)
- Reset AFU (DFL_FPGA_PORT_RESET)
- Get number of irqs of port error (DFL_FPGA_PORT_ERR_GET_IRQ_NUM)
- Set interrupt trigger for port error (DFL_FPGA_PORT_ERR_SET_IRQ)
- Get number of irqs of UINT (DFL_FPGA_PORT_UINT_GET_IRQ_NUM)
- Set interrupt trigger for UINT (DFL_FPGA_PORT_UINT_SET_IRQ)

DFL_FPGA_PORT_RESET:
reset the FPGA Port and its AFU. Userspace can do Port
Expand Down Expand Up @@ -462,6 +468,19 @@ since they are system-wide counters on FPGA device.
The current driver does not support sampling. So "perf record" is unsupported.


Interrupt support
=================
Some FME and AFU private features are able to generate interrupts. As mentioned
above, users could call ioctl (DFL_FPGA_*_GET_IRQ_NUM) to know whether or how
many interrupts are supported for this private feature. Drivers also implement
an eventfd based interrupt handling mechanism for users to get notified when
interrupt happens. Users could set eventfds to driver via
ioctl (DFL_FPGA_*_SET_IRQ), and then poll/select on these eventfds waiting for
notification.
In Current DFL, 3 sub features (Port error, FME global error and AFU interrupt)
support interrupts.


Add new FIUs support
====================
It's possible that developers made some new function blocks (FIUs) under this
Expand Down
19 changes: 5 additions & 14 deletions drivers/fpga/dfl-afu-dma-region.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@

#include "dfl-afu.h"

static void put_all_pages(struct page **pages, int npages)
{
int i;

for (i = 0; i < npages; i++)
if (pages[i])
put_page(pages[i]);
}

void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
{
struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);
Expand Down Expand Up @@ -57,22 +48,22 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
goto unlock_vm;
}

pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
pinned = pin_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
region->pages);
if (pinned < 0) {
ret = pinned;
goto free_pages;
} else if (pinned != npages) {
ret = -EFAULT;
goto put_pages;
goto unpin_pages;
}

dev_dbg(dev, "%d pages pinned\n", pinned);

return 0;

put_pages:
put_all_pages(region->pages, pinned);
unpin_pages:
unpin_user_pages(region->pages, pinned);
free_pages:
kfree(region->pages);
unlock_vm:
Expand All @@ -94,7 +85,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
long npages = region->length >> PAGE_SHIFT;
struct device *dev = &pdata->dev->dev;

put_all_pages(region->pages, npages);
unpin_user_pages(region->pages, npages);
kfree(region->pages);
account_locked_vm(current->mm, npages, false);

Expand Down
17 changes: 17 additions & 0 deletions drivers/fpga/dfl-afu-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Mitchel Henry <henry.mitchel@intel.com>
*/

#include <linux/fpga-dfl.h>
#include <linux/uaccess.h>

#include "dfl-afu.h"
Expand Down Expand Up @@ -219,6 +220,21 @@ static void port_err_uinit(struct platform_device *pdev,
afu_port_err_mask(&pdev->dev, true);
}

static long
port_err_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_PORT_ERR_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_PORT_ERR_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}

const struct dfl_feature_id port_err_id_table[] = {
{.id = PORT_FEATURE_ID_ERROR,},
{0,}
Expand All @@ -227,4 +243,5 @@ const struct dfl_feature_id port_err_id_table[] = {
const struct dfl_feature_ops port_err_ops = {
.init = port_err_init,
.uinit = port_err_uinit,
.ioctl = port_err_ioctl,
};
32 changes: 32 additions & 0 deletions drivers/fpga/dfl-afu-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,30 @@ static const struct dfl_feature_ops port_stp_ops = {
.init = port_stp_init,
};

static long
port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_PORT_UINT_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_PORT_UINT_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}

static const struct dfl_feature_id port_uint_id_table[] = {
{.id = PORT_FEATURE_ID_UINT,},
{0,}
};

static const struct dfl_feature_ops port_uint_ops = {
.ioctl = port_uint_ioctl,
};

static struct dfl_feature_driver port_feature_drvs[] = {
{
.id_table = port_hdr_id_table,
Expand All @@ -546,6 +570,10 @@ static struct dfl_feature_driver port_feature_drvs[] = {
.id_table = port_stp_id_table,
.ops = &port_stp_ops,
},
{
.id_table = port_uint_id_table,
.ops = &port_uint_ops,
},
{
.ops = NULL,
}
Expand Down Expand Up @@ -577,6 +605,7 @@ static int afu_release(struct inode *inode, struct file *filp)
{
struct platform_device *pdev = filp->private_data;
struct dfl_feature_platform_data *pdata;
struct dfl_feature *feature;

dev_dbg(&pdev->dev, "Device File Release\n");

Expand All @@ -586,6 +615,9 @@ static int afu_release(struct inode *inode, struct file *filp)
dfl_feature_dev_use_end(pdata);

if (!dfl_feature_dev_use_count(pdata)) {
dfl_fpga_dev_for_each_feature(pdata, feature)
dfl_fpga_set_irq_triggers(feature, 0,
feature->nr_irqs, NULL);
__port_reset(pdev);
afu_dma_region_destroy(pdata);
}
Expand Down
18 changes: 18 additions & 0 deletions drivers/fpga/dfl-fme-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Mitchel, Henry <henry.mitchel@intel.com>
*/

#include <linux/fpga-dfl.h>
#include <linux/uaccess.h>

#include "dfl.h"
Expand Down Expand Up @@ -348,6 +349,22 @@ static void fme_global_err_uinit(struct platform_device *pdev,
fme_err_mask(&pdev->dev, true);
}

static long
fme_global_error_ioctl(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_FME_ERR_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}

const struct dfl_feature_id fme_global_err_id_table[] = {
{.id = FME_FEATURE_ID_GLOBAL_ERR,},
{0,}
Expand All @@ -356,4 +373,5 @@ const struct dfl_feature_id fme_global_err_id_table[] = {
const struct dfl_feature_ops fme_global_err_ops = {
.init = fme_global_err_init,
.uinit = fme_global_err_uinit,
.ioctl = fme_global_error_ioctl,
};
6 changes: 6 additions & 0 deletions drivers/fpga/dfl-fme-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,11 +620,17 @@ static int fme_release(struct inode *inode, struct file *filp)
{
struct dfl_feature_platform_data *pdata = filp->private_data;
struct platform_device *pdev = pdata->dev;
struct dfl_feature *feature;

dev_dbg(&pdev->dev, "Device File Release\n");

mutex_lock(&pdata->lock);
dfl_feature_dev_use_end(pdata);

if (!dfl_feature_dev_use_count(pdata))
dfl_fpga_dev_for_each_feature(pdata, feature)
dfl_fpga_set_irq_triggers(feature, 0,
feature->nr_irqs, NULL);
mutex_unlock(&pdata->lock);

return 0;
Expand Down
Loading

0 comments on commit cb0cec2

Please sign in to comment.