Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'fpga-for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/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()

+687 -47
+12 -4
Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt
··· 1 1 Xilinx Slave Serial SPI FPGA Manager 2 2 3 - Xilinx Spartan-6 FPGAs support a method of loading the bitstream over 4 - what is referred to as "slave serial" interface. 3 + Xilinx Spartan-6 and 7 Series FPGAs support a method of loading the 4 + bitstream over what is referred to as "slave serial" interface. 5 5 The slave serial link is not technically SPI, and might require extra 6 6 circuits in order to play nicely with other SPI slaves on the same bus. 7 7 8 - See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf 8 + See: 9 + - https://www.xilinx.com/support/documentation/user_guides/ug380.pdf 10 + - https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf 11 + - https://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf 9 12 10 13 Required properties: 11 14 - compatible: should contain "xlnx,fpga-slave-serial" 12 15 - reg: spi chip select of the FPGA 13 16 - prog_b-gpios: config pin (referred to as PROGRAM_B in the manual) 14 17 - done-gpios: config status pin (referred to as DONE in the manual) 18 + 19 + Optional properties: 20 + - init-b-gpios: initialization status and configuration error pin 21 + (referred to as INIT_B in the manual) 15 22 16 23 Example for full FPGA configuration: 17 24 ··· 44 37 spi-max-frequency = <60000000>; 45 38 spi-cpha; 46 39 reg = <0>; 47 - done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; 48 40 prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; 41 + init-b-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; 42 + done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; 49 43 }; 50 44 };
+19
Documentation/fpga/dfl.rst
··· 89 89 - Program bitstream (DFL_FPGA_FME_PORT_PR) 90 90 - Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN) 91 91 - Release port from PF (DFL_FPGA_FME_PORT_RELEASE) 92 + - Get number of irqs of FME global error (DFL_FPGA_FME_ERR_GET_IRQ_NUM) 93 + - Set interrupt trigger for FME error (DFL_FPGA_FME_ERR_SET_IRQ) 92 94 93 95 More functions are exposed through sysfs 94 96 (/sys/class/fpga_region/regionX/dfl-fme.n/): ··· 151 149 - Map DMA buffer (DFL_FPGA_PORT_DMA_MAP) 152 150 - Unmap DMA buffer (DFL_FPGA_PORT_DMA_UNMAP) 153 151 - Reset AFU (DFL_FPGA_PORT_RESET) 152 + - Get number of irqs of port error (DFL_FPGA_PORT_ERR_GET_IRQ_NUM) 153 + - Set interrupt trigger for port error (DFL_FPGA_PORT_ERR_SET_IRQ) 154 + - Get number of irqs of UINT (DFL_FPGA_PORT_UINT_GET_IRQ_NUM) 155 + - Set interrupt trigger for UINT (DFL_FPGA_PORT_UINT_SET_IRQ) 154 156 155 157 DFL_FPGA_PORT_RESET: 156 158 reset the FPGA Port and its AFU. Userspace can do Port ··· 466 460 since they are system-wide counters on FPGA device. 467 461 468 462 The current driver does not support sampling. So "perf record" is unsupported. 463 + 464 + 465 + Interrupt support 466 + ================= 467 + Some FME and AFU private features are able to generate interrupts. As mentioned 468 + above, users could call ioctl (DFL_FPGA_*_GET_IRQ_NUM) to know whether or how 469 + many interrupts are supported for this private feature. Drivers also implement 470 + an eventfd based interrupt handling mechanism for users to get notified when 471 + interrupt happens. Users could set eventfds to driver via 472 + ioctl (DFL_FPGA_*_SET_IRQ), and then poll/select on these eventfds waiting for 473 + notification. 474 + In Current DFL, 3 sub features (Port error, FME global error and AFU interrupt) 475 + support interrupts. 469 476 470 477 471 478 Add new FIUs support
+5 -14
drivers/fpga/dfl-afu-dma-region.c
··· 16 16 17 17 #include "dfl-afu.h" 18 18 19 - static void put_all_pages(struct page **pages, int npages) 20 - { 21 - int i; 22 - 23 - for (i = 0; i < npages; i++) 24 - if (pages[i]) 25 - put_page(pages[i]); 26 - } 27 - 28 19 void afu_dma_region_init(struct dfl_feature_platform_data *pdata) 29 20 { 30 21 struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); ··· 48 57 goto unlock_vm; 49 58 } 50 59 51 - pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE, 60 + pinned = pin_user_pages_fast(region->user_addr, npages, FOLL_WRITE, 52 61 region->pages); 53 62 if (pinned < 0) { 54 63 ret = pinned; 55 64 goto free_pages; 56 65 } else if (pinned != npages) { 57 66 ret = -EFAULT; 58 - goto put_pages; 67 + goto unpin_pages; 59 68 } 60 69 61 70 dev_dbg(dev, "%d pages pinned\n", pinned); 62 71 63 72 return 0; 64 73 65 - put_pages: 66 - put_all_pages(region->pages, pinned); 74 + unpin_pages: 75 + unpin_user_pages(region->pages, pinned); 67 76 free_pages: 68 77 kfree(region->pages); 69 78 unlock_vm: ··· 85 94 long npages = region->length >> PAGE_SHIFT; 86 95 struct device *dev = &pdata->dev->dev; 87 96 88 - put_all_pages(region->pages, npages); 97 + unpin_user_pages(region->pages, npages); 89 98 kfree(region->pages); 90 99 account_locked_vm(current->mm, npages, false); 91 100
+17
drivers/fpga/dfl-afu-error.c
··· 14 14 * Mitchel Henry <henry.mitchel@intel.com> 15 15 */ 16 16 17 + #include <linux/fpga-dfl.h> 17 18 #include <linux/uaccess.h> 18 19 19 20 #include "dfl-afu.h" ··· 220 219 afu_port_err_mask(&pdev->dev, true); 221 220 } 222 221 222 + static long 223 + port_err_ioctl(struct platform_device *pdev, struct dfl_feature *feature, 224 + unsigned int cmd, unsigned long arg) 225 + { 226 + switch (cmd) { 227 + case DFL_FPGA_PORT_ERR_GET_IRQ_NUM: 228 + return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg); 229 + case DFL_FPGA_PORT_ERR_SET_IRQ: 230 + return dfl_feature_ioctl_set_irq(pdev, feature, arg); 231 + default: 232 + dev_dbg(&pdev->dev, "%x cmd not handled", cmd); 233 + return -ENODEV; 234 + } 235 + } 236 + 223 237 const struct dfl_feature_id port_err_id_table[] = { 224 238 {.id = PORT_FEATURE_ID_ERROR,}, 225 239 {0,} ··· 243 227 const struct dfl_feature_ops port_err_ops = { 244 228 .init = port_err_init, 245 229 .uinit = port_err_uinit, 230 + .ioctl = port_err_ioctl, 246 231 };
+32
drivers/fpga/dfl-afu-main.c
··· 529 529 .init = port_stp_init, 530 530 }; 531 531 532 + static long 533 + port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature, 534 + unsigned int cmd, unsigned long arg) 535 + { 536 + switch (cmd) { 537 + case DFL_FPGA_PORT_UINT_GET_IRQ_NUM: 538 + return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg); 539 + case DFL_FPGA_PORT_UINT_SET_IRQ: 540 + return dfl_feature_ioctl_set_irq(pdev, feature, arg); 541 + default: 542 + dev_dbg(&pdev->dev, "%x cmd not handled", cmd); 543 + return -ENODEV; 544 + } 545 + } 546 + 547 + static const struct dfl_feature_id port_uint_id_table[] = { 548 + {.id = PORT_FEATURE_ID_UINT,}, 549 + {0,} 550 + }; 551 + 552 + static const struct dfl_feature_ops port_uint_ops = { 553 + .ioctl = port_uint_ioctl, 554 + }; 555 + 532 556 static struct dfl_feature_driver port_feature_drvs[] = { 533 557 { 534 558 .id_table = port_hdr_id_table, ··· 569 545 { 570 546 .id_table = port_stp_id_table, 571 547 .ops = &port_stp_ops, 548 + }, 549 + { 550 + .id_table = port_uint_id_table, 551 + .ops = &port_uint_ops, 572 552 }, 573 553 { 574 554 .ops = NULL, ··· 605 577 { 606 578 struct platform_device *pdev = filp->private_data; 607 579 struct dfl_feature_platform_data *pdata; 580 + struct dfl_feature *feature; 608 581 609 582 dev_dbg(&pdev->dev, "Device File Release\n"); 610 583 ··· 615 586 dfl_feature_dev_use_end(pdata); 616 587 617 588 if (!dfl_feature_dev_use_count(pdata)) { 589 + dfl_fpga_dev_for_each_feature(pdata, feature) 590 + dfl_fpga_set_irq_triggers(feature, 0, 591 + feature->nr_irqs, NULL); 618 592 __port_reset(pdev); 619 593 afu_dma_region_destroy(pdata); 620 594 }
+18
drivers/fpga/dfl-fme-error.c
··· 15 15 * Mitchel, Henry <henry.mitchel@intel.com> 16 16 */ 17 17 18 + #include <linux/fpga-dfl.h> 18 19 #include <linux/uaccess.h> 19 20 20 21 #include "dfl.h" ··· 349 348 fme_err_mask(&pdev->dev, true); 350 349 } 351 350 351 + static long 352 + fme_global_error_ioctl(struct platform_device *pdev, 353 + struct dfl_feature *feature, 354 + unsigned int cmd, unsigned long arg) 355 + { 356 + switch (cmd) { 357 + case DFL_FPGA_FME_ERR_GET_IRQ_NUM: 358 + return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg); 359 + case DFL_FPGA_FME_ERR_SET_IRQ: 360 + return dfl_feature_ioctl_set_irq(pdev, feature, arg); 361 + default: 362 + dev_dbg(&pdev->dev, "%x cmd not handled", cmd); 363 + return -ENODEV; 364 + } 365 + } 366 + 352 367 const struct dfl_feature_id fme_global_err_id_table[] = { 353 368 {.id = FME_FEATURE_ID_GLOBAL_ERR,}, 354 369 {0,} ··· 373 356 const struct dfl_feature_ops fme_global_err_ops = { 374 357 .init = fme_global_err_init, 375 358 .uinit = fme_global_err_uinit, 359 + .ioctl = fme_global_error_ioctl, 376 360 };
+6
drivers/fpga/dfl-fme-main.c
··· 620 620 { 621 621 struct dfl_feature_platform_data *pdata = filp->private_data; 622 622 struct platform_device *pdev = pdata->dev; 623 + struct dfl_feature *feature; 623 624 624 625 dev_dbg(&pdev->dev, "Device File Release\n"); 625 626 626 627 mutex_lock(&pdata->lock); 627 628 dfl_feature_dev_use_end(pdata); 629 + 630 + if (!dfl_feature_dev_use_count(pdata)) 631 + dfl_fpga_dev_for_each_feature(pdata, feature) 632 + dfl_fpga_set_irq_triggers(feature, 0, 633 + feature->nr_irqs, NULL); 628 634 mutex_unlock(&pdata->lock); 629 635 630 636 return 0;
+69 -9
drivers/fpga/dfl-pci.c
··· 39 39 return pcim_iomap_table(pcidev)[bar]; 40 40 } 41 41 42 + static int cci_pci_alloc_irq(struct pci_dev *pcidev) 43 + { 44 + int ret, nvec = pci_msix_vec_count(pcidev); 45 + 46 + if (nvec <= 0) { 47 + dev_dbg(&pcidev->dev, "fpga interrupt not supported\n"); 48 + return 0; 49 + } 50 + 51 + ret = pci_alloc_irq_vectors(pcidev, nvec, nvec, PCI_IRQ_MSIX); 52 + if (ret < 0) 53 + return ret; 54 + 55 + return nvec; 56 + } 57 + 58 + static void cci_pci_free_irq(struct pci_dev *pcidev) 59 + { 60 + pci_free_irq_vectors(pcidev); 61 + } 62 + 42 63 /* PCI Device ID */ 43 64 #define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD 44 65 #define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 45 66 #define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 67 + #define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 46 68 /* VF Device */ 47 69 #define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF 48 70 #define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 ··· 77 55 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),}, 78 56 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, 79 57 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, 58 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, 80 59 {0,} 81 60 }; 82 61 MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); ··· 101 78 102 79 /* remove all children feature devices */ 103 80 dfl_fpga_feature_devs_remove(drvdata->cdev); 81 + cci_pci_free_irq(pcidev); 82 + } 83 + 84 + static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec) 85 + { 86 + unsigned int i; 87 + int *table; 88 + 89 + table = kcalloc(nvec, sizeof(int), GFP_KERNEL); 90 + if (!table) 91 + return table; 92 + 93 + for (i = 0; i < nvec; i++) 94 + table[i] = pci_irq_vector(pcidev, i); 95 + 96 + return table; 104 97 } 105 98 106 99 /* enumerate feature devices under pci device */ 107 100 static int cci_enumerate_feature_devs(struct pci_dev *pcidev) 108 101 { 109 102 struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); 103 + int port_num, bar, i, nvec, ret = 0; 110 104 struct dfl_fpga_enum_info *info; 111 105 struct dfl_fpga_cdev *cdev; 112 106 resource_size_t start, len; 113 - int port_num, bar, i, ret = 0; 114 107 void __iomem *base; 108 + int *irq_table; 115 109 u32 offset; 116 110 u64 v; 117 111 ··· 137 97 if (!info) 138 98 return -ENOMEM; 139 99 100 + /* add irq info for enumeration if the device support irq */ 101 + nvec = cci_pci_alloc_irq(pcidev); 102 + if (nvec < 0) { 103 + dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec); 104 + ret = nvec; 105 + goto enum_info_free_exit; 106 + } else if (nvec) { 107 + irq_table = cci_pci_create_irq_table(pcidev, nvec); 108 + if (!irq_table) { 109 + ret = -ENOMEM; 110 + goto irq_free_exit; 111 + } 112 + 113 + ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table); 114 + kfree(irq_table); 115 + if (ret) 116 + goto irq_free_exit; 117 + } 118 + 140 119 /* start to find Device Feature List from Bar 0 */ 141 120 base = cci_pci_ioremap_bar(pcidev, 0); 142 121 if (!base) { 143 122 ret = -ENOMEM; 144 - goto enum_info_free_exit; 123 + goto irq_free_exit; 145 124 } 146 125 147 126 /* ··· 213 154 dfl_fpga_enum_info_add_dfl(info, start, len, base); 214 155 } else { 215 156 ret = -ENODEV; 216 - goto enum_info_free_exit; 157 + goto irq_free_exit; 217 158 } 218 159 219 160 /* start enumeration with prepared enumeration information */ ··· 221 162 if (IS_ERR(cdev)) { 222 163 dev_err(&pcidev->dev, "Enumeration failure\n"); 223 164 ret = PTR_ERR(cdev); 224 - goto enum_info_free_exit; 165 + goto irq_free_exit; 225 166 } 226 167 227 168 drvdata->cdev = cdev; 228 169 170 + irq_free_exit: 171 + if (ret) 172 + cci_pci_free_irq(pcidev); 229 173 enum_info_free_exit: 230 174 dfl_fpga_enum_info_free(info); 231 175 ··· 273 211 } 274 212 275 213 ret = cci_enumerate_feature_devs(pcidev); 276 - if (ret) { 277 - dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); 278 - goto disable_error_report_exit; 279 - } 214 + if (!ret) 215 + return ret; 280 216 281 - return ret; 217 + dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); 282 218 283 219 disable_error_report_exit: 284 220 pci_disable_pcie_error_reporting(pcidev);
+311 -2
drivers/fpga/dfl.c
··· 10 10 * Wu Hao <hao.wu@intel.com> 11 11 * Xiao Guangrong <guangrong.xiao@linux.intel.com> 12 12 */ 13 + #include <linux/fpga-dfl.h> 13 14 #include <linux/module.h> 15 + #include <linux/uaccess.h> 14 16 15 17 #include "dfl.h" 16 18 ··· 423 421 * 424 422 * @dev: device to enumerate. 425 423 * @cdev: the container device for all feature devices. 424 + * @nr_irqs: number of irqs for all feature devices. 425 + * @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of 426 + * this device. 426 427 * @feature_dev: current feature device. 427 428 * @ioaddr: header register region address of feature device in enumeration. 428 429 * @sub_features: a sub features linked list for feature device in enumeration. ··· 434 429 struct build_feature_devs_info { 435 430 struct device *dev; 436 431 struct dfl_fpga_cdev *cdev; 432 + unsigned int nr_irqs; 433 + int *irq_table; 434 + 437 435 struct platform_device *feature_dev; 438 436 void __iomem *ioaddr; 439 437 struct list_head sub_features; ··· 450 442 * @mmio_res: mmio resource of this sub feature. 451 443 * @ioaddr: mapped base address of mmio resource. 452 444 * @node: node in sub_features linked list. 445 + * @irq_base: start of irq index in this sub feature. 446 + * @nr_irqs: number of irqs of this sub feature. 453 447 */ 454 448 struct dfl_feature_info { 455 449 u64 fid; 456 450 struct resource mmio_res; 457 451 void __iomem *ioaddr; 458 452 struct list_head node; 453 + unsigned int irq_base; 454 + unsigned int nr_irqs; 459 455 }; 460 456 461 457 static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev, ··· 499 487 * it will be automatically freed by device's release() callback, 500 488 * platform_device_release(). 501 489 */ 502 - pdata = kzalloc(dfl_feature_platform_data_size(binfo->feature_num), 503 - GFP_KERNEL); 490 + pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL); 504 491 if (!pdata) 505 492 return -ENOMEM; 506 493 ··· 531 520 /* fill features and resource information for feature dev */ 532 521 list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) { 533 522 struct dfl_feature *feature = &pdata->features[index]; 523 + struct dfl_feature_irq_ctx *ctx; 524 + unsigned int i; 534 525 535 526 /* save resource information for each feature */ 527 + feature->dev = fdev; 536 528 feature->id = finfo->fid; 537 529 feature->resource_index = index; 538 530 feature->ioaddr = finfo->ioaddr; 539 531 fdev->resource[index++] = finfo->mmio_res; 532 + 533 + if (finfo->nr_irqs) { 534 + ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs, 535 + sizeof(*ctx), GFP_KERNEL); 536 + if (!ctx) 537 + return -ENOMEM; 538 + 539 + for (i = 0; i < finfo->nr_irqs; i++) 540 + ctx[i].irq = 541 + binfo->irq_table[finfo->irq_base + i]; 542 + 543 + feature->irq_ctx = ctx; 544 + feature->nr_irqs = finfo->nr_irqs; 545 + } 540 546 541 547 list_del(&finfo->node); 542 548 kfree(finfo); ··· 666 638 return 0; 667 639 } 668 640 641 + static int parse_feature_irqs(struct build_feature_devs_info *binfo, 642 + resource_size_t ofst, u64 fid, 643 + unsigned int *irq_base, unsigned int *nr_irqs) 644 + { 645 + void __iomem *base = binfo->ioaddr + ofst; 646 + unsigned int i, ibase, inr = 0; 647 + int virq; 648 + u64 v; 649 + 650 + /* 651 + * Ideally DFL framework should only read info from DFL header, but 652 + * current version DFL only provides mmio resources information for 653 + * each feature in DFL Header, no field for interrupt resources. 654 + * Interrupt resource information is provided by specific mmio 655 + * registers of each private feature which supports interrupt. So in 656 + * order to parse and assign irq resources, DFL framework has to look 657 + * into specific capability registers of these private features. 658 + * 659 + * Once future DFL version supports generic interrupt resource 660 + * information in common DFL headers, the generic interrupt parsing 661 + * code will be added. But in order to be compatible to old version 662 + * DFL, the driver may still fall back to these quirks. 663 + */ 664 + switch (fid) { 665 + case PORT_FEATURE_ID_UINT: 666 + v = readq(base + PORT_UINT_CAP); 667 + ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v); 668 + inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v); 669 + break; 670 + case PORT_FEATURE_ID_ERROR: 671 + v = readq(base + PORT_ERROR_CAP); 672 + ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v); 673 + inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v); 674 + break; 675 + case FME_FEATURE_ID_GLOBAL_ERR: 676 + v = readq(base + FME_ERROR_CAP); 677 + ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v); 678 + inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v); 679 + break; 680 + } 681 + 682 + if (!inr) { 683 + *irq_base = 0; 684 + *nr_irqs = 0; 685 + return 0; 686 + } 687 + 688 + dev_dbg(binfo->dev, "feature: 0x%llx, irq_base: %u, nr_irqs: %u\n", 689 + fid, ibase, inr); 690 + 691 + if (ibase + inr > binfo->nr_irqs) { 692 + dev_err(binfo->dev, 693 + "Invalid interrupt number in feature 0x%llx\n", fid); 694 + return -EINVAL; 695 + } 696 + 697 + for (i = 0; i < inr; i++) { 698 + virq = binfo->irq_table[ibase + i]; 699 + if (virq < 0 || virq > NR_IRQS) { 700 + dev_err(binfo->dev, 701 + "Invalid irq table entry for feature 0x%llx\n", 702 + fid); 703 + return -EINVAL; 704 + } 705 + } 706 + 707 + *irq_base = ibase; 708 + *nr_irqs = inr; 709 + 710 + return 0; 711 + } 712 + 669 713 /* 670 714 * when create sub feature instances, for private features, it doesn't need 671 715 * to provide resource size and feature id as they could be read from DFH ··· 750 650 struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst, 751 651 resource_size_t size, u64 fid) 752 652 { 653 + unsigned int irq_base, nr_irqs; 753 654 struct dfl_feature_info *finfo; 655 + int ret; 754 656 755 657 /* read feature size and id if inputs are invalid */ 756 658 size = size ? size : feature_size(dfl->ioaddr + ofst); ··· 760 658 761 659 if (dfl->len - ofst < size) 762 660 return -EINVAL; 661 + 662 + ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs); 663 + if (ret) 664 + return ret; 763 665 764 666 finfo = kzalloc(sizeof(*finfo), GFP_KERNEL); 765 667 if (!finfo) ··· 773 667 finfo->mmio_res.start = dfl->start + ofst; 774 668 finfo->mmio_res.end = finfo->mmio_res.start + size - 1; 775 669 finfo->mmio_res.flags = IORESOURCE_MEM; 670 + finfo->irq_base = irq_base; 671 + finfo->nr_irqs = nr_irqs; 776 672 finfo->ioaddr = dfl->ioaddr + ofst; 777 673 778 674 list_add_tail(&finfo->node, &binfo->sub_features); ··· 961 853 devm_kfree(dev, dfl); 962 854 } 963 855 856 + /* remove irq table */ 857 + if (info->irq_table) 858 + devm_kfree(dev, info->irq_table); 859 + 964 860 devm_kfree(dev, info); 965 861 put_device(dev); 966 862 } ··· 1003 891 return 0; 1004 892 } 1005 893 EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl); 894 + 895 + /** 896 + * dfl_fpga_enum_info_add_irq - add irq table to enum info 897 + * 898 + * @info: ptr to dfl_fpga_enum_info 899 + * @nr_irqs: number of irqs of the DFL fpga device to be enumerated. 900 + * @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of 901 + * this device. 902 + * 903 + * One FPGA device may have several interrupts. This function adds irq 904 + * information of the DFL fpga device to enum info for next step enumeration. 905 + * This function should be called before dfl_fpga_feature_devs_enumerate(). 906 + * As we only support one irq domain for all DFLs in the same enum info, adding 907 + * irq table a second time for the same enum info will return error. 908 + * 909 + * If we need to enumerate DFLs which belong to different irq domains, we 910 + * should fill more enum info and enumerate them one by one. 911 + * 912 + * Return: 0 on success, negative error code otherwise. 913 + */ 914 + int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info, 915 + unsigned int nr_irqs, int *irq_table) 916 + { 917 + if (!nr_irqs || !irq_table) 918 + return -EINVAL; 919 + 920 + if (info->irq_table) 921 + return -EEXIST; 922 + 923 + info->irq_table = devm_kmemdup(info->dev, irq_table, 924 + sizeof(int) * nr_irqs, GFP_KERNEL); 925 + if (!info->irq_table) 926 + return -ENOMEM; 927 + 928 + info->nr_irqs = nr_irqs; 929 + 930 + return 0; 931 + } 932 + EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_irq); 1006 933 1007 934 static int remove_feature_dev(struct device *dev, void *data) 1008 935 { ··· 1109 958 1110 959 binfo->dev = info->dev; 1111 960 binfo->cdev = cdev; 961 + 962 + binfo->nr_irqs = info->nr_irqs; 963 + if (info->nr_irqs) 964 + binfo->irq_table = info->irq_table; 1112 965 1113 966 /* 1114 967 * start enumeration for all feature devices based on Device Feature ··· 1395 1240 return ret; 1396 1241 } 1397 1242 EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf); 1243 + 1244 + static irqreturn_t dfl_irq_handler(int irq, void *arg) 1245 + { 1246 + struct eventfd_ctx *trigger = arg; 1247 + 1248 + eventfd_signal(trigger, 1); 1249 + return IRQ_HANDLED; 1250 + } 1251 + 1252 + static int do_set_irq_trigger(struct dfl_feature *feature, unsigned int idx, 1253 + int fd) 1254 + { 1255 + struct platform_device *pdev = feature->dev; 1256 + struct eventfd_ctx *trigger; 1257 + int irq, ret; 1258 + 1259 + irq = feature->irq_ctx[idx].irq; 1260 + 1261 + if (feature->irq_ctx[idx].trigger) { 1262 + free_irq(irq, feature->irq_ctx[idx].trigger); 1263 + kfree(feature->irq_ctx[idx].name); 1264 + eventfd_ctx_put(feature->irq_ctx[idx].trigger); 1265 + feature->irq_ctx[idx].trigger = NULL; 1266 + } 1267 + 1268 + if (fd < 0) 1269 + return 0; 1270 + 1271 + feature->irq_ctx[idx].name = 1272 + kasprintf(GFP_KERNEL, "fpga-irq[%u](%s-%llx)", idx, 1273 + dev_name(&pdev->dev), feature->id); 1274 + if (!feature->irq_ctx[idx].name) 1275 + return -ENOMEM; 1276 + 1277 + trigger = eventfd_ctx_fdget(fd); 1278 + if (IS_ERR(trigger)) { 1279 + ret = PTR_ERR(trigger); 1280 + goto free_name; 1281 + } 1282 + 1283 + ret = request_irq(irq, dfl_irq_handler, 0, 1284 + feature->irq_ctx[idx].name, trigger); 1285 + if (!ret) { 1286 + feature->irq_ctx[idx].trigger = trigger; 1287 + return ret; 1288 + } 1289 + 1290 + eventfd_ctx_put(trigger); 1291 + free_name: 1292 + kfree(feature->irq_ctx[idx].name); 1293 + 1294 + return ret; 1295 + } 1296 + 1297 + /** 1298 + * dfl_fpga_set_irq_triggers - set eventfd triggers for dfl feature interrupts 1299 + * 1300 + * @feature: dfl sub feature. 1301 + * @start: start of irq index in this dfl sub feature. 1302 + * @count: number of irqs. 1303 + * @fds: eventfds to bind with irqs. unbind related irq if fds[n] is negative. 1304 + * unbind "count" specified number of irqs if fds ptr is NULL. 1305 + * 1306 + * Bind given eventfds with irqs in this dfl sub feature. Unbind related irq if 1307 + * fds[n] is negative. Unbind "count" specified number of irqs if fds ptr is 1308 + * NULL. 1309 + * 1310 + * Return: 0 on success, negative error code otherwise. 1311 + */ 1312 + int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start, 1313 + unsigned int count, int32_t *fds) 1314 + { 1315 + unsigned int i; 1316 + int ret = 0; 1317 + 1318 + /* overflow */ 1319 + if (unlikely(start + count < start)) 1320 + return -EINVAL; 1321 + 1322 + /* exceeds nr_irqs */ 1323 + if (start + count > feature->nr_irqs) 1324 + return -EINVAL; 1325 + 1326 + for (i = 0; i < count; i++) { 1327 + int fd = fds ? fds[i] : -1; 1328 + 1329 + ret = do_set_irq_trigger(feature, start + i, fd); 1330 + if (ret) { 1331 + while (i--) 1332 + do_set_irq_trigger(feature, start + i, -1); 1333 + break; 1334 + } 1335 + } 1336 + 1337 + return ret; 1338 + } 1339 + EXPORT_SYMBOL_GPL(dfl_fpga_set_irq_triggers); 1340 + 1341 + /** 1342 + * dfl_feature_ioctl_get_num_irqs - dfl feature _GET_IRQ_NUM ioctl interface. 1343 + * @pdev: the feature device which has the sub feature 1344 + * @feature: the dfl sub feature 1345 + * @arg: ioctl argument 1346 + * 1347 + * Return: 0 on success, negative error code otherwise. 1348 + */ 1349 + long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev, 1350 + struct dfl_feature *feature, 1351 + unsigned long arg) 1352 + { 1353 + return put_user(feature->nr_irqs, (__u32 __user *)arg); 1354 + } 1355 + EXPORT_SYMBOL_GPL(dfl_feature_ioctl_get_num_irqs); 1356 + 1357 + /** 1358 + * dfl_feature_ioctl_set_irq - dfl feature _SET_IRQ ioctl interface. 1359 + * @pdev: the feature device which has the sub feature 1360 + * @feature: the dfl sub feature 1361 + * @arg: ioctl argument 1362 + * 1363 + * Return: 0 on success, negative error code otherwise. 1364 + */ 1365 + long dfl_feature_ioctl_set_irq(struct platform_device *pdev, 1366 + struct dfl_feature *feature, 1367 + unsigned long arg) 1368 + { 1369 + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 1370 + struct dfl_fpga_irq_set hdr; 1371 + s32 *fds; 1372 + long ret; 1373 + 1374 + if (!feature->nr_irqs) 1375 + return -ENOENT; 1376 + 1377 + if (copy_from_user(&hdr, (void __user *)arg, sizeof(hdr))) 1378 + return -EFAULT; 1379 + 1380 + if (!hdr.count || (hdr.start + hdr.count > feature->nr_irqs) || 1381 + (hdr.start + hdr.count < hdr.start)) 1382 + return -EINVAL; 1383 + 1384 + fds = memdup_user((void __user *)(arg + sizeof(hdr)), 1385 + hdr.count * sizeof(s32)); 1386 + if (IS_ERR(fds)) 1387 + return PTR_ERR(fds); 1388 + 1389 + mutex_lock(&pdata->lock); 1390 + ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds); 1391 + mutex_unlock(&pdata->lock); 1392 + 1393 + kfree(fds); 1394 + return ret; 1395 + } 1396 + EXPORT_SYMBOL_GPL(dfl_feature_ioctl_set_irq); 1398 1397 1399 1398 static void __exit dfl_fpga_exit(void) 1400 1399 {
+57 -6
drivers/fpga/dfl.h
··· 17 17 #include <linux/bitfield.h> 18 18 #include <linux/cdev.h> 19 19 #include <linux/delay.h> 20 + #include <linux/eventfd.h> 20 21 #include <linux/fs.h> 22 + #include <linux/interrupt.h> 21 23 #include <linux/iopoll.h> 22 24 #include <linux/io-64-nonatomic-lo-hi.h> 23 25 #include <linux/platform_device.h> ··· 114 112 #define FME_PORT_OFST_ACC_VF 1 115 113 #define FME_PORT_OFST_IMP BIT_ULL(60) 116 114 115 + /* FME Error Capability Register */ 116 + #define FME_ERROR_CAP 0x70 117 + 118 + /* FME Error Capability Register Bitfield */ 119 + #define FME_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */ 120 + #define FME_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */ 121 + 117 122 /* PORT Header Register Set */ 118 123 #define PORT_HDR_DFH DFH 119 124 #define PORT_HDR_GUID_L GUID_L ··· 153 144 #define PORT_STS_PWR_STATE_AP1 1 /* 50% throttling */ 154 145 #define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */ 155 146 #define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */ 147 + 148 + /* Port Error Capability Register */ 149 + #define PORT_ERROR_CAP 0x38 150 + 151 + /* Port Error Capability Register Bitfield */ 152 + #define PORT_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */ 153 + #define PORT_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */ 154 + 155 + /* Port Uint Capability Register */ 156 + #define PORT_UINT_CAP 0x8 157 + 158 + /* Port Uint Capability Register Bitfield */ 159 + #define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */ 160 + #define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */ 156 161 157 162 /** 158 163 * struct dfl_fpga_port_ops - port ops ··· 212 189 }; 213 190 214 191 /** 192 + * struct dfl_feature_irq_ctx - dfl private feature interrupt context 193 + * 194 + * @irq: Linux IRQ number of this interrupt. 195 + * @trigger: eventfd context to signal when interrupt happens. 196 + * @name: irq name needed when requesting irq. 197 + */ 198 + struct dfl_feature_irq_ctx { 199 + int irq; 200 + struct eventfd_ctx *trigger; 201 + char *name; 202 + }; 203 + 204 + /** 215 205 * struct dfl_feature - sub feature of the feature devices 216 206 * 207 + * @dev: ptr to pdev of the feature device which has the sub feature. 217 208 * @id: sub feature id. 218 209 * @resource_index: each sub feature has one mmio resource for its registers. 219 210 * this index is used to find its mmio resource from the 220 211 * feature dev (platform device)'s reources. 221 212 * @ioaddr: mapped mmio resource address. 213 + * @irq_ctx: interrupt context list. 214 + * @nr_irqs: number of interrupt contexts. 222 215 * @ops: ops of this sub feature. 223 216 * @priv: priv data of this feature. 224 217 */ 225 218 struct dfl_feature { 219 + struct platform_device *dev; 226 220 u64 id; 227 221 int resource_index; 228 222 void __iomem *ioaddr; 223 + struct dfl_feature_irq_ctx *irq_ctx; 224 + unsigned int nr_irqs; 229 225 const struct dfl_feature_ops *ops; 230 226 void *priv; 231 227 }; ··· 341 299 #define DFL_FPGA_FEATURE_DEV_FME "dfl-fme" 342 300 #define DFL_FPGA_FEATURE_DEV_PORT "dfl-port" 343 301 344 - static inline int dfl_feature_platform_data_size(const int num) 345 - { 346 - return sizeof(struct dfl_feature_platform_data) + 347 - num * sizeof(struct dfl_feature); 348 - } 349 - 350 302 void dfl_fpga_dev_feature_uinit(struct platform_device *pdev); 351 303 int dfl_fpga_dev_feature_init(struct platform_device *pdev, 352 304 struct dfl_feature_driver *feature_drvs); ··· 426 390 * 427 391 * @dev: parent device. 428 392 * @dfls: list of device feature lists. 393 + * @nr_irqs: number of irqs for all feature devices. 394 + * @irq_table: Linux IRQ numbers for all irqs, indexed by hw irq numbers. 429 395 */ 430 396 struct dfl_fpga_enum_info { 431 397 struct device *dev; 432 398 struct list_head dfls; 399 + unsigned int nr_irqs; 400 + int *irq_table; 433 401 }; 434 402 435 403 /** ··· 457 417 int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info, 458 418 resource_size_t start, resource_size_t len, 459 419 void __iomem *ioaddr); 420 + int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info, 421 + unsigned int nr_irqs, int *irq_table); 460 422 void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info); 461 423 462 424 /** ··· 510 468 int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id); 511 469 void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev); 512 470 int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf); 471 + int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start, 472 + unsigned int count, int32_t *fds); 473 + long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev, 474 + struct dfl_feature *feature, 475 + unsigned long arg); 476 + long dfl_feature_ioctl_set_irq(struct platform_device *pdev, 477 + struct dfl_feature *feature, 478 + unsigned long arg); 479 + 513 480 #endif /* __FPGA_DFL_H */
+2 -4
drivers/fpga/fpga-bridge.c
··· 328 328 void *priv) 329 329 { 330 330 struct fpga_bridge *bridge; 331 - int id, ret = 0; 331 + int id, ret; 332 332 333 333 if (!name || !strlen(name)) { 334 334 dev_err(dev, "Attempt to register with no name!\n"); ··· 340 340 return NULL; 341 341 342 342 id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL); 343 - if (id < 0) { 344 - ret = id; 343 + if (id < 0) 345 344 goto error_kfree; 346 - } 347 345 348 346 mutex_init(&bridge->mutex); 349 347 INIT_LIST_HEAD(&bridge->node);
+1 -3
drivers/fpga/fpga-mgr.c
··· 581 581 return NULL; 582 582 583 583 id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL); 584 - if (id < 0) { 585 - ret = id; 584 + if (id < 0) 586 585 goto error_kfree; 587 - } 588 586 589 587 mutex_init(&mgr->ref_mutex); 590 588
+56 -5
drivers/fpga/xilinx-spi.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Xilinx Spartan6 Slave Serial SPI Driver 3 + * Xilinx Spartan6 and 7 Series Slave Serial SPI Driver 4 4 * 5 5 * Copyright (C) 2017 DENX Software Engineering 6 6 * ··· 23 23 struct xilinx_spi_conf { 24 24 struct spi_device *spi; 25 25 struct gpio_desc *prog_b; 26 + struct gpio_desc *init_b; 26 27 struct gpio_desc *done; 27 28 }; 28 29 ··· 37 36 return FPGA_MGR_STATE_UNKNOWN; 38 37 } 39 38 39 + /** 40 + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait 41 + * a given delay if the pin is unavailable 42 + * 43 + * @mgr: The FPGA manager object 44 + * @value: Value INIT_B to wait for (1 = asserted = low) 45 + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available 46 + * 47 + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if 48 + * too much time passed waiting for that. If no INIT_B GPIO is available 49 + * then always return 0. 50 + */ 51 + static int wait_for_init_b(struct fpga_manager *mgr, int value, 52 + unsigned long alt_udelay) 53 + { 54 + struct xilinx_spi_conf *conf = mgr->priv; 55 + unsigned long timeout = jiffies + msecs_to_jiffies(1000); 56 + 57 + if (conf->init_b) { 58 + while (time_before(jiffies, timeout)) { 59 + /* dump_state(conf, "wait for init_d .."); */ 60 + if (gpiod_get_value(conf->init_b) == value) 61 + return 0; 62 + usleep_range(100, 400); 63 + } 64 + return -ETIMEDOUT; 65 + } 66 + 67 + udelay(alt_udelay); 68 + 69 + return 0; 70 + } 71 + 40 72 static int xilinx_spi_write_init(struct fpga_manager *mgr, 41 73 struct fpga_image_info *info, 42 74 const char *buf, size_t count) 43 75 { 44 76 struct xilinx_spi_conf *conf = mgr->priv; 45 - const size_t prog_latency_7500us = 7500; 46 - const size_t prog_pulse_1us = 1; 77 + int err; 47 78 48 79 if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { 49 80 dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); ··· 84 51 85 52 gpiod_set_value(conf->prog_b, 1); 86 53 87 - udelay(prog_pulse_1us); /* min is 500 ns */ 54 + err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */ 55 + if (err) { 56 + dev_err(&mgr->dev, "INIT_B pin did not go low\n"); 57 + gpiod_set_value(conf->prog_b, 0); 58 + return err; 59 + } 88 60 89 61 gpiod_set_value(conf->prog_b, 0); 62 + 63 + err = wait_for_init_b(mgr, 0, 0); 64 + if (err) { 65 + dev_err(&mgr->dev, "INIT_B pin did not go high\n"); 66 + return err; 67 + } 90 68 91 69 if (gpiod_get_value(conf->done)) { 92 70 dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); ··· 105 61 } 106 62 107 63 /* program latency */ 108 - usleep_range(prog_latency_7500us, prog_latency_7500us + 100); 64 + usleep_range(7500, 7600); 109 65 return 0; 110 66 } 111 67 ··· 198 154 dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", 199 155 PTR_ERR(conf->prog_b)); 200 156 return PTR_ERR(conf->prog_b); 157 + } 158 + 159 + conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN); 160 + if (IS_ERR(conf->init_b)) { 161 + dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n", 162 + PTR_ERR(conf->init_b)); 163 + return PTR_ERR(conf->init_b); 201 164 } 202 165 203 166 conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
+82
include/uapi/linux/fpga-dfl.h
··· 151 151 152 152 #define DFL_FPGA_PORT_DMA_UNMAP _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 4) 153 153 154 + /** 155 + * struct dfl_fpga_irq_set - the argument for DFL_FPGA_XXX_SET_IRQ ioctl. 156 + * 157 + * @start: Index of the first irq. 158 + * @count: The number of eventfd handler. 159 + * @evtfds: Eventfd handlers. 160 + */ 161 + struct dfl_fpga_irq_set { 162 + __u32 start; 163 + __u32 count; 164 + __s32 evtfds[]; 165 + }; 166 + 167 + /** 168 + * DFL_FPGA_PORT_ERR_GET_IRQ_NUM - _IOR(DFL_FPGA_MAGIC, DFL_PORT_BASE + 5, 169 + * __u32 num_irqs) 170 + * 171 + * Get the number of irqs supported by the fpga port error reporting private 172 + * feature. Currently hardware supports up to 1 irq. 173 + * Return: 0 on success, -errno on failure. 174 + */ 175 + #define DFL_FPGA_PORT_ERR_GET_IRQ_NUM _IOR(DFL_FPGA_MAGIC, \ 176 + DFL_PORT_BASE + 5, __u32) 177 + 178 + /** 179 + * DFL_FPGA_PORT_ERR_SET_IRQ - _IOW(DFL_FPGA_MAGIC, DFL_PORT_BASE + 6, 180 + * struct dfl_fpga_irq_set) 181 + * 182 + * Set fpga port error reporting interrupt trigger if evtfds[n] is valid. 183 + * Unset related interrupt trigger if evtfds[n] is a negative value. 184 + * Return: 0 on success, -errno on failure. 185 + */ 186 + #define DFL_FPGA_PORT_ERR_SET_IRQ _IOW(DFL_FPGA_MAGIC, \ 187 + DFL_PORT_BASE + 6, \ 188 + struct dfl_fpga_irq_set) 189 + 190 + /** 191 + * DFL_FPGA_PORT_UINT_GET_IRQ_NUM - _IOR(DFL_FPGA_MAGIC, DFL_PORT_BASE + 7, 192 + * __u32 num_irqs) 193 + * 194 + * Get the number of irqs supported by the fpga AFU interrupt private 195 + * feature. 196 + * Return: 0 on success, -errno on failure. 197 + */ 198 + #define DFL_FPGA_PORT_UINT_GET_IRQ_NUM _IOR(DFL_FPGA_MAGIC, \ 199 + DFL_PORT_BASE + 7, __u32) 200 + 201 + /** 202 + * DFL_FPGA_PORT_UINT_SET_IRQ - _IOW(DFL_FPGA_MAGIC, DFL_PORT_BASE + 8, 203 + * struct dfl_fpga_irq_set) 204 + * 205 + * Set fpga AFU interrupt trigger if evtfds[n] is valid. 206 + * Unset related interrupt trigger if evtfds[n] is a negative value. 207 + * Return: 0 on success, -errno on failure. 208 + */ 209 + #define DFL_FPGA_PORT_UINT_SET_IRQ _IOW(DFL_FPGA_MAGIC, \ 210 + DFL_PORT_BASE + 8, \ 211 + struct dfl_fpga_irq_set) 212 + 154 213 /* IOCTLs for FME file descriptor */ 155 214 156 215 /** ··· 252 193 * Return: 0 on success, -errno on failure. 253 194 */ 254 195 #define DFL_FPGA_FME_PORT_ASSIGN _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 2, int) 196 + 197 + /** 198 + * DFL_FPGA_FME_ERR_GET_IRQ_NUM - _IOR(DFL_FPGA_MAGIC, DFL_FME_BASE + 3, 199 + * __u32 num_irqs) 200 + * 201 + * Get the number of irqs supported by the fpga fme error reporting private 202 + * feature. Currently hardware supports up to 1 irq. 203 + * Return: 0 on success, -errno on failure. 204 + */ 205 + #define DFL_FPGA_FME_ERR_GET_IRQ_NUM _IOR(DFL_FPGA_MAGIC, \ 206 + DFL_FME_BASE + 3, __u32) 207 + 208 + /** 209 + * DFL_FPGA_FME_ERR_SET_IRQ - _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 4, 210 + * struct dfl_fpga_irq_set) 211 + * 212 + * Set fpga fme error reporting interrupt trigger if evtfds[n] is valid. 213 + * Unset related interrupt trigger if evtfds[n] is a negative value. 214 + * Return: 0 on success, -errno on failure. 215 + */ 216 + #define DFL_FPGA_FME_ERR_SET_IRQ _IOW(DFL_FPGA_MAGIC, \ 217 + DFL_FME_BASE + 4, \ 218 + struct dfl_fpga_irq_set) 255 219 256 220 #endif /* _UAPI_LINUX_FPGA_DFL_H */