From a0e1b618585979bf2520a6a6e954a3bb56cd610b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 21 Nov 2016 22:26:42 +0000 Subject: [PATCH 1/6] fpga: Add COMPILE_TEST to all drivers Like Zynq the Altera drivers compile fine on x86 and others too, so make it easier to compile test this stuff. A10 requires REGMAP_MMIO to compile, so be explicit rather than relying on it via ARCH_SOCFPGA. Signed-off-by: Jason Gunthorpe Acked-by: Alan Tull --- drivers/fpga/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 889e4c3983042..ce861a2853a4b 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -22,13 +22,14 @@ config FPGA_REGION config FPGA_MGR_SOCFPGA tristate "Altera SOCFPGA FPGA Manager" - depends on ARCH_SOCFPGA + depends on ARCH_SOCFPGA || COMPILE_TEST help FPGA manager driver support for Altera SOCFPGA. config FPGA_MGR_SOCFPGA_A10 tristate "Altera SoCFPGA Arria10" - depends on ARCH_SOCFPGA + depends on ARCH_SOCFPGA || COMPILE_TEST + select REGMAP_MMIO help FPGA manager driver support for Altera Arria10 SoCFPGA. From 1930c2865108d5510d9013aaced3c12be5f413f6 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 21 Nov 2016 22:26:43 +0000 Subject: [PATCH 2/6] fpga zynq: Add missing \n to messages Function dev_err doesn't add a newline at the end of the string. This will lead to a hard to read kernel log. Signed-off-by: Jason Gunthorpe Reviewed-by: Moritz Fischer Reviewed-by: Matthias Brugger Acked-by: Alan Tull --- drivers/fpga/zynq-fpga.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 249682e92502a..86011b07026dd 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -218,7 +218,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for PCFG_INIT"); + dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); goto out_err; } @@ -232,7 +232,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for !PCFG_INIT"); + dev_err(priv->dev, "Timeout waiting for !PCFG_INIT\n"); goto out_err; } @@ -246,7 +246,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for PCFG_INIT"); + dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); goto out_err; } } @@ -263,7 +263,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, /* check that we have room in the command queue */ status = zynq_fpga_read(priv, STATUS_OFFSET); if (status & STATUS_DMA_Q_F) { - dev_err(priv->dev, "DMA command queue full"); + dev_err(priv->dev, "DMA command queue full\n"); err = -EBUSY; goto out_err; } @@ -332,7 +332,7 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr, zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { - dev_err(priv->dev, "Error configuring FPGA"); + dev_err(priv->dev, "Error configuring FPGA\n"); err = -EFAULT; } @@ -428,7 +428,7 @@ static int zynq_fpga_probe(struct platform_device *pdev) priv->slcr = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); if (IS_ERR(priv->slcr)) { - dev_err(dev, "unable to get zynq-slcr regmap"); + dev_err(dev, "unable to get zynq-slcr regmap\n"); return PTR_ERR(priv->slcr); } @@ -436,26 +436,26 @@ static int zynq_fpga_probe(struct platform_device *pdev) priv->irq = platform_get_irq(pdev, 0); if (priv->irq < 0) { - dev_err(dev, "No IRQ available"); + dev_err(dev, "No IRQ available\n"); return priv->irq; } err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, dev_name(dev), priv); if (err) { - dev_err(dev, "unable to request IRQ"); + dev_err(dev, "unable to request IRQ\n"); return err; } priv->clk = devm_clk_get(dev, "ref_clk"); if (IS_ERR(priv->clk)) { - dev_err(dev, "input clock not found"); + dev_err(dev, "input clock not found\n"); return PTR_ERR(priv->clk); } err = clk_prepare_enable(priv->clk); if (err) { - dev_err(dev, "unable to enable clock"); + dev_err(dev, "unable to enable clock\n"); return err; } @@ -467,7 +467,7 @@ static int zynq_fpga_probe(struct platform_device *pdev) err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager", &zynq_fpga_ops, priv); if (err) { - dev_err(dev, "unable to register FPGA manager"); + dev_err(dev, "unable to register FPGA manager\n"); clk_unprepare(priv->clk); return err; } From 80baf649c2778bb8900cb9011bc712b89faddbdb Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 21 Nov 2016 22:26:44 +0000 Subject: [PATCH 3/6] fpga zynq: Remove priv->dev socfpga uses mgr->dev for debug prints, there should be consistency here, so standardize on that. The only other use was for dma which can be replaced with mgr->dev.parent. Signed-off-by: Jason Gunthorpe Acked-by: Alan Tull Acked-by: Moritz Fischer --- drivers/fpga/zynq-fpga.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 86011b07026dd..bc8e3ec2b1343 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -118,7 +118,6 @@ #define FPGA_RST_NONE_MASK 0x0 struct zynq_fpga_priv { - struct device *dev; int irq; struct clk *clk; @@ -218,7 +217,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); + dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n"); goto out_err; } @@ -232,7 +231,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for !PCFG_INIT\n"); + dev_err(&mgr->dev, "Timeout waiting for !PCFG_INIT\n"); goto out_err; } @@ -246,7 +245,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, INIT_POLL_DELAY, INIT_POLL_TIMEOUT); if (err) { - dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); + dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n"); goto out_err; } } @@ -263,7 +262,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, /* check that we have room in the command queue */ status = zynq_fpga_read(priv, STATUS_OFFSET); if (status & STATUS_DMA_Q_F) { - dev_err(priv->dev, "DMA command queue full\n"); + dev_err(&mgr->dev, "DMA command queue full\n"); err = -EBUSY; goto out_err; } @@ -296,7 +295,8 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr, in_count = count; priv = mgr->priv; - kbuf = dma_alloc_coherent(priv->dev, count, &dma_addr, GFP_KERNEL); + kbuf = + dma_alloc_coherent(mgr->dev.parent, count, &dma_addr, GFP_KERNEL); if (!kbuf) return -ENOMEM; @@ -332,15 +332,14 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr, zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { - dev_err(priv->dev, "Error configuring FPGA\n"); + dev_err(&mgr->dev, "Error configuring FPGA\n"); err = -EFAULT; } clk_disable(priv->clk); out_free: - dma_free_coherent(priv->dev, in_count, kbuf, dma_addr); - + dma_free_coherent(mgr->dev.parent, count, kbuf, dma_addr); return err; } @@ -418,8 +417,6 @@ static int zynq_fpga_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->io_base = devm_ioremap_resource(dev, res); if (IS_ERR(priv->io_base)) From 340c0c53ea3073107d5bb7a61f3158e50bf189e0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 21 Nov 2016 22:26:45 +0000 Subject: [PATCH 4/6] fpga zynq: Fix incorrect ISR state on bootup It is best practice to clear and mask all interrupts before associating the IRQ, and this should be done after the clock is enabled. This corrects a bad result from zynq_fpga_ops_state on bootup where left over latched values in INT_STS_OFFSET caused it to report an unconfigured FPGA as configured. After this change the boot up operating state for an unconfigured FPGA reports 'unknown'. Signed-off-by: Jason Gunthorpe Acked-by: Alan Tull Acked-by: Moritz Fischer --- drivers/fpga/zynq-fpga.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index bc8e3ec2b1343..1812bf7614e1d 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -437,13 +437,6 @@ static int zynq_fpga_probe(struct platform_device *pdev) return priv->irq; } - err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, - dev_name(dev), priv); - if (err) { - dev_err(dev, "unable to request IRQ\n"); - return err; - } - priv->clk = devm_clk_get(dev, "ref_clk"); if (IS_ERR(priv->clk)) { dev_err(dev, "input clock not found\n"); @@ -459,6 +452,16 @@ static int zynq_fpga_probe(struct platform_device *pdev) /* unlock the device */ zynq_fpga_write(priv, UNLOCK_OFFSET, UNLOCK_MASK); + zynq_fpga_write(priv, INT_MASK_OFFSET, 0xFFFFFFFF); + zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK); + err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, dev_name(dev), + priv); + if (err) { + dev_err(dev, "unable to request IRQ\n"); + clk_disable_unprepare(priv->clk); + return err; + } + clk_disable(priv->clk); err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager", From 1d7f1589d341344c0c598b00de44891a7968c6a0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Nov 2016 18:22:09 +0000 Subject: [PATCH 5/6] fpga: Clarify how write_init works streaming modes This interface was designed for streaming, but write_init's buf argument has an unclear purpose. Define it to be the first bytes of the bitstream. Each driver gets to set how many bytes (at most) it wants to see. Short bitstreams will be passed through as-is, while long ones will be truncated. The intent is to allow drivers to peek at the header before the transfer actually starts. Signed-off-by: Jason Gunthorpe Acked-by: Alan Tull --- Documentation/fpga/fpga-mgr.txt | 5 ++++- drivers/fpga/fpga-mgr.c | 6 ++++-- drivers/fpga/socfpga-a10.c | 1 + include/linux/fpga/fpga-mgr.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt index 087924f2b20c8..86ee5078fd034 100644 --- a/Documentation/fpga/fpga-mgr.txt +++ b/Documentation/fpga/fpga-mgr.txt @@ -169,7 +169,10 @@ The programming sequence is: 2. .write (may be called once or multiple times) 3. .write_complete -The .write_init function will prepare the FPGA to receive the image data. +The .write_init function will prepare the FPGA to receive the image data. The +buffer passed into .write_init will be atmost .initial_header_size bytes long, +if the whole bitstream is not immediately available then the core code will +buffer up at least this much before starting. The .write function writes a buffer to the FPGA. The buffer may be contain the whole FPGA image or may be a smaller chunk of an FPGA image. In the latter diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 79ce2eea44dbb..f0a69d3e60a58 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -53,10 +53,12 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, /* * Call the low level driver's write_init function. This will do the * device-specific things to get the FPGA into the state where it is - * ready to receive an FPGA image. + * ready to receive an FPGA image. The low level driver only gets to + * see the first initial_header_size bytes in the buffer. */ mgr->state = FPGA_MGR_STATE_WRITE_INIT; - ret = mgr->mops->write_init(mgr, info, buf, count); + ret = mgr->mops->write_init(mgr, info, buf, + min(mgr->mops->initial_header_size, count)); if (ret) { dev_err(dev, "Error preparing FPGA for writing\n"); mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index ccd9fb23bd528..f8770af0f6b51 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -470,6 +470,7 @@ static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) } static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { + .initial_header_size = (RBF_DECOMPRESS_OFFSET + 1) * 4, .state = socfpga_a10_fpga_state, .write_init = socfpga_a10_fpga_write_init, .write = socfpga_a10_fpga_write, diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 96a1a33116495..16551d5eac36a 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -84,6 +84,7 @@ struct fpga_image_info { /** * struct fpga_manager_ops - ops for low level fpga manager drivers + * @initial_header_size: Maximum number of bytes that should be passed into write_init * @state: returns an enum value of the FPGA's state * @write_init: prepare the FPGA to receive confuration data * @write: write count bytes of configuration data to the FPGA @@ -95,6 +96,7 @@ struct fpga_image_info { * called, so leaving them out is fine. */ struct fpga_manager_ops { + size_t initial_header_size; enum fpga_mgr_states (*state)(struct fpga_manager *mgr); int (*write_init)(struct fpga_manager *mgr, struct fpga_image_info *info, From e499807737b75387bcc9d146927dc36a0b7e4cff Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Tue, 29 Nov 2016 15:15:45 -0600 Subject: [PATCH 6/6] MAINTAINERS: add git url for fpga Add git url for fpga stuff. Signed-off-by: Alan Tull --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2f89c3be2a393..b0fee8c451354 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4958,6 +4958,7 @@ M: Alan Tull R: Moritz Fischer L: linux-fpga@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git F: drivers/fpga/ F: include/linux/fpga/fpga-mgr.h W: http://www.rocketboards.org