Commit bbc11b34 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'fpga-for-5.10' of...

Merge tag 'fpga-for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga into char-misc-next

Moritz writes:

Here is the first set of changes for the 5.10-rc1 merge window.

Xilinx:
- Luca's changes clean up the xilinx-spi driver and add better
  diagnostics on errors.

Core:
- I cleaned up a stray comment.
- Richard's change marks FPGA manager tasks un-interruptible.
- Tom has agreed to help out as Reviewer in the FPGA Manager subsystem.

DFL:
- Xu's changes  add a new bus that is the first part of a series to support
  adding devices via DFL (the other parts are still under review)

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: default avatarMoritz Fischer <mdf@kernel.org>

* tag 'fpga-for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mdf/linux-fpga:
  fpga: dfl: create a dfl bus type to support DFL devices
  fpga: fpga-region: Cleanup an outdated comment
  fpga: dfl: map feature mmio resources in their own feature drivers
  fpga manager: xilinx-spi: provide better diagnostics on programming failure
  fpga manager: xilinx-spi: add error checking after gpiod_get_value()
  fpga manager: xilinx-spi: fix write_complete timeout handling
  fpga manager: xilinx-spi: remove final dot from dev_err() strings
  fpga manager: xilinx-spi: remove stray comment
  fpga: dfl: change data type of feature id to u16
  MAINTAINERS: Add Tom Rix as fpga reviewer
  fpga: stratix10-soc: make FPGA task un-interruptible
parents 05fa34dc 9ba3a0aa
What: /sys/bus/dfl/devices/dfl_dev.X/type
Date: Aug 2020
KernelVersion: 5.10
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. It returns type of DFL FIU of the device. Now DFL
supports 2 FIU types, 0 for FME, 1 for PORT.
Format: 0x%x
What: /sys/bus/dfl/devices/dfl_dev.X/feature_id
Date: Aug 2020
KernelVersion: 5.10
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. It returns feature identifier local to its DFL FIU
type.
Format: 0x%x
......@@ -6828,14 +6828,17 @@ F: drivers/net/ethernet/nvidia/*
FPGA DFL DRIVERS
M: Wu Hao <hao.wu@intel.com>
R: Tom Rix <trix@redhat.com>
L: linux-fpga@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-dfl
F: Documentation/fpga/dfl.rst
F: drivers/fpga/dfl*
F: include/uapi/linux/fpga-dfl.h
FPGA MANAGER FRAMEWORK
M: Moritz Fischer <mdf@kernel.org>
R: Tom Rix <trix@redhat.com>
L: linux-fpga@vger.kernel.org
S: Maintained
W: http://www.rocketboards.org
......
......@@ -148,7 +148,7 @@ struct fme_perf_priv {
struct device *dev;
void __iomem *ioaddr;
struct pmu pmu;
u64 id;
u16 id;
u32 fab_users;
u32 fab_port_id;
......
......@@ -31,12 +31,12 @@ struct cci_drvdata {
struct dfl_fpga_cdev *cdev; /* container device */
};
static void __iomem *cci_pci_ioremap_bar(struct pci_dev *pcidev, int bar)
static void __iomem *cci_pci_ioremap_bar0(struct pci_dev *pcidev)
{
if (pcim_iomap_regions(pcidev, BIT(bar), DRV_NAME))
if (pcim_iomap_regions(pcidev, BIT(0), DRV_NAME))
return NULL;
return pcim_iomap_table(pcidev)[bar];
return pcim_iomap_table(pcidev)[0];
}
static int cci_pci_alloc_irq(struct pci_dev *pcidev)
......@@ -156,8 +156,8 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
goto irq_free_exit;
}
/* start to find Device Feature List from Bar 0 */
base = cci_pci_ioremap_bar(pcidev, 0);
/* start to find Device Feature List in Bar 0 */
base = cci_pci_ioremap_bar0(pcidev);
if (!base) {
ret = -ENOMEM;
goto irq_free_exit;
......@@ -172,7 +172,7 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
start = pci_resource_start(pcidev, 0);
len = pci_resource_len(pcidev, 0);
dfl_fpga_enum_info_add_dfl(info, start, len, base);
dfl_fpga_enum_info_add_dfl(info, start, len);
/*
* find more Device Feature Lists (e.g. Ports) per information
......@@ -196,26 +196,24 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
*/
bar = FIELD_GET(FME_PORT_OFST_BAR_ID, v);
offset = FIELD_GET(FME_PORT_OFST_DFH_OFST, v);
base = cci_pci_ioremap_bar(pcidev, bar);
if (!base)
continue;
start = pci_resource_start(pcidev, bar) + offset;
len = pci_resource_len(pcidev, bar) - offset;
dfl_fpga_enum_info_add_dfl(info, start, len,
base + offset);
dfl_fpga_enum_info_add_dfl(info, start, len);
}
} else if (dfl_feature_is_port(base)) {
start = pci_resource_start(pcidev, 0);
len = pci_resource_len(pcidev, 0);
dfl_fpga_enum_info_add_dfl(info, start, len, base);
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));
/* start enumeration with prepared enumeration information */
cdev = dfl_fpga_feature_devs_enumerate(info);
if (IS_ERR(cdev)) {
......
This diff is collapsed.
......@@ -197,7 +197,7 @@ int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id);
* @id: unique dfl private feature id.
*/
struct dfl_feature_id {
u64 id;
u16 id;
};
/**
......@@ -236,16 +236,18 @@ struct dfl_feature_irq_ctx {
* @irq_ctx: interrupt context list.
* @nr_irqs: number of interrupt contexts.
* @ops: ops of this sub feature.
* @ddev: ptr to the dfl device of this sub feature.
* @priv: priv data of this feature.
*/
struct dfl_feature {
struct platform_device *dev;
u64 id;
u16 id;
int resource_index;
void __iomem *ioaddr;
struct dfl_feature_irq_ctx *irq_ctx;
unsigned int nr_irqs;
const struct dfl_feature_ops *ops;
struct dfl_device *ddev;
void *priv;
};
......@@ -365,7 +367,7 @@ struct platform_device *dfl_fpga_inode_to_feature_dev(struct inode *inode)
(feature) < (pdata)->features + (pdata)->num; (feature)++)
static inline
struct dfl_feature *dfl_get_feature_by_id(struct device *dev, u64 id)
struct dfl_feature *dfl_get_feature_by_id(struct device *dev, u16 id)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
struct dfl_feature *feature;
......@@ -378,7 +380,7 @@ struct dfl_feature *dfl_get_feature_by_id(struct device *dev, u64 id)
}
static inline
void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u64 id)
void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u16 id)
{
struct dfl_feature *feature = dfl_get_feature_by_id(dev, id);
......@@ -389,7 +391,7 @@ void __iomem *dfl_get_feature_ioaddr_by_id(struct device *dev, u64 id)
return NULL;
}
static inline bool is_dfl_feature_present(struct device *dev, u64 id)
static inline bool is_dfl_feature_present(struct device *dev, u16 id)
{
return !!dfl_get_feature_ioaddr_by_id(dev, id);
}
......@@ -441,22 +443,17 @@ struct dfl_fpga_enum_info {
*
* @start: base address of this device feature list.
* @len: size of this device feature list.
* @ioaddr: mapped base address of this device feature list.
* @node: node in list of device feature lists.
*/
struct dfl_fpga_enum_dfl {
resource_size_t start;
resource_size_t len;
void __iomem *ioaddr;
struct list_head node;
};
struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev);
int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
resource_size_t start, resource_size_t len,
void __iomem *ioaddr);
resource_size_t start, resource_size_t len);
int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info,
unsigned int nr_irqs, int *irq_table);
void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info);
......@@ -519,4 +516,88 @@ 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,
PORT_ID,
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.
* @driver_data: driver specific data.
*/
struct dfl_device_id {
u8 type;
u16 feature_id;
unsigned long driver_data;
};
/**
* 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: 16 bits 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;
u8 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 */
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Region - Device Tree support for FPGA programming under Linux
* FPGA Region - Support for FPGA programming under Linux
*
* Copyright (C) 2013-2016 Altera Corporation
* Copyright (C) 2017 Intel Corporation
......
......@@ -196,17 +196,13 @@ static int s10_ops_write_init(struct fpga_manager *mgr,
if (ret < 0)
goto init_done;
ret = wait_for_completion_interruptible_timeout(
ret = wait_for_completion_timeout(
&priv->status_return_completion, S10_RECONFIG_TIMEOUT);
if (!ret) {
dev_err(dev, "timeout waiting for RECONFIG_REQUEST\n");
ret = -ETIMEDOUT;
goto init_done;
}
if (ret < 0) {
dev_err(dev, "error (%d) waiting for RECONFIG_REQUEST\n", ret);
goto init_done;
}
ret = 0;
if (!test_and_clear_bit(SVC_STATUS_OK, &priv->status)) {
......@@ -318,7 +314,7 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
*/
wait_status = 1; /* not timed out */
if (!priv->status)
wait_status = wait_for_completion_interruptible_timeout(
wait_status = wait_for_completion_timeout(
&priv->status_return_completion,
S10_BUFFER_TIMEOUT);
......@@ -340,13 +336,6 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
ret = -ETIMEDOUT;
break;
}
if (wait_status < 0) {
ret = wait_status;
dev_err(dev,
"error (%d) waiting for svc layer buffers\n",
ret);
break;
}
}
if (!s10_free_buffers(mgr))
......@@ -372,7 +361,7 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
if (ret < 0)
break;
ret = wait_for_completion_interruptible_timeout(
ret = wait_for_completion_timeout(
&priv->status_return_completion, timeout);
if (!ret) {
dev_err(dev,
......@@ -380,12 +369,6 @@ static int s10_ops_write_complete(struct fpga_manager *mgr,
ret = -ETIMEDOUT;
break;
}
if (ret < 0) {
dev_err(dev,
"error (%d) waiting for RECONFIG_COMPLETED\n",
ret);
break;
}
/* Not error or timeout, so ret is # of jiffies until timeout */
timeout = ret;
ret = 0;
......
......@@ -27,11 +27,22 @@ struct xilinx_spi_conf {
struct gpio_desc *done;
};
static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
static int get_done_gpio(struct fpga_manager *mgr)
{
struct xilinx_spi_conf *conf = mgr->priv;
int ret;
ret = gpiod_get_value(conf->done);
if (ret < 0)
dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
return ret;
}
if (!gpiod_get_value(conf->done))
static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
{
if (!get_done_gpio(mgr))
return FPGA_MGR_STATE_RESET;
return FPGA_MGR_STATE_UNKNOWN;
......@@ -57,11 +68,21 @@ static int wait_for_init_b(struct fpga_manager *mgr, int value,
if (conf->init_b) {
while (time_before(jiffies, timeout)) {
/* dump_state(conf, "wait for init_d .."); */
if (gpiod_get_value(conf->init_b) == value)
int ret = gpiod_get_value(conf->init_b);
if (ret == value)
return 0;
if (ret < 0) {
dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
return ret;
}
usleep_range(100, 400);
}
dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
value ? "assert" : "deassert");
return -ETIMEDOUT;
}
......@@ -78,7 +99,7 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
int err;
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
return -EINVAL;
}
......@@ -86,7 +107,6 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
if (err) {
dev_err(&mgr->dev, "INIT_B pin did not go low\n");
gpiod_set_value(conf->prog_b, 0);
return err;
}
......@@ -94,12 +114,10 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
gpiod_set_value(conf->prog_b, 0);
err = wait_for_init_b(mgr, 0, 0);
if (err) {
dev_err(&mgr->dev, "INIT_B pin did not go high\n");
if (err)
return err;
}
if (gpiod_get_value(conf->done)) {
if (get_done_gpio(mgr)) {
dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
return -EIO;
}
......@@ -152,25 +170,46 @@ static int xilinx_spi_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
struct xilinx_spi_conf *conf = mgr->priv;
unsigned long timeout;
unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
bool expired = false;
int done;
int ret;
if (gpiod_get_value(conf->done))
return xilinx_spi_apply_cclk_cycles(conf);
/*
* This loop is carefully written such that if the driver is
* scheduled out for more than 'timeout', we still check for DONE
* before giving up and we apply 8 extra CCLK cycles in all cases.
*/
while (!expired) {
expired = time_after(jiffies, timeout);
timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
while (time_before(jiffies, timeout)) {
done = get_done_gpio(mgr);
if (done < 0)
return done;
ret = xilinx_spi_apply_cclk_cycles(conf);
if (ret)
return ret;
if (gpiod_get_value(conf->done))
return xilinx_spi_apply_cclk_cycles(conf);
if (done)
return 0;
}
if (conf->init_b) {
ret = gpiod_get_value(conf->init_b);
if (ret < 0) {
dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
return ret;
}
dev_err(&mgr->dev,
ret ? "CRC error or invalid device\n"
: "Missing sync word or incomplete bitstream\n");
} else {
dev_err(&mgr->dev, "Timeout after config data transfer\n");
}
dev_err(&mgr->dev, "Timeout after config data transfer.\n");
return -ETIMEDOUT;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment