1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/drivers/misc/xillybus_pcie.c 4 * 5 * Copyright 2011 Xillybus Ltd, http://xillybus.com 6 * 7 * Driver for the Xillybus FPGA/host framework using PCI Express. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/pci.h> 12 #include <linux/slab.h> 13 #include "xillybus.h" 14 15 MODULE_DESCRIPTION("Xillybus driver for PCIe"); 16 MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 17 MODULE_ALIAS("xillybus_pcie"); 18 MODULE_LICENSE("GPL v2"); 19 20 #define PCI_DEVICE_ID_XILLYBUS 0xebeb 21 22 #define PCI_VENDOR_ID_ACTEL 0x11aa 23 #define PCI_VENDOR_ID_LATTICE 0x1204 24 25 static const char xillyname[] = "xillybus_pcie"; 26 27 static const struct pci_device_id xillyids[] = { 28 {PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)}, 29 {PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)}, 30 {PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)}, 31 {PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)}, 32 { /* End: all zeroes */ } 33 }; 34 35 static int xilly_probe(struct pci_dev *pdev, 36 const struct pci_device_id *ent) 37 { 38 struct xilly_endpoint *endpoint; 39 int rc; 40 41 endpoint = xillybus_init_endpoint(&pdev->dev); 42 43 if (!endpoint) 44 return -ENOMEM; 45 46 pci_set_drvdata(pdev, endpoint); 47 48 endpoint->owner = THIS_MODULE; 49 50 rc = pcim_enable_device(pdev); 51 if (rc) { 52 dev_err(endpoint->dev, 53 "pcim_enable_device() failed. Aborting.\n"); 54 return rc; 55 } 56 57 /* L0s has caused packet drops. No power saving, thank you. */ 58 59 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); 60 61 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 62 dev_err(endpoint->dev, 63 "Incorrect BAR configuration. Aborting.\n"); 64 return -ENODEV; 65 } 66 67 rc = pcim_iomap_regions(pdev, 0x01, xillyname); 68 if (rc) { 69 dev_err(endpoint->dev, 70 "pcim_iomap_regions() failed. Aborting.\n"); 71 return rc; 72 } 73 74 endpoint->registers = pcim_iomap_table(pdev)[0]; 75 76 pci_set_master(pdev); 77 78 /* Set up a single MSI interrupt */ 79 if (pci_enable_msi(pdev)) { 80 dev_err(endpoint->dev, 81 "Failed to enable MSI interrupts. Aborting.\n"); 82 return -ENODEV; 83 } 84 rc = devm_request_irq(&pdev->dev, pdev->irq, xillybus_isr, 0, 85 xillyname, endpoint); 86 if (rc) { 87 dev_err(endpoint->dev, 88 "Failed to register MSI handler. Aborting.\n"); 89 return -ENODEV; 90 } 91 92 /* 93 * Some (old and buggy?) hardware drops 64-bit addressed PCIe packets, 94 * even when the PCIe driver claims that a 64-bit mask is OK. On the 95 * other hand, on some architectures, 64-bit addressing is mandatory. 96 * So go for the 64-bit mask only when failing is the other option. 97 */ 98 99 if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 100 endpoint->dma_using_dac = 0; 101 } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { 102 endpoint->dma_using_dac = 1; 103 } else { 104 dev_err(endpoint->dev, "Failed to set DMA mask. Aborting.\n"); 105 return -ENODEV; 106 } 107 108 return xillybus_endpoint_discovery(endpoint); 109 } 110 111 static void xilly_remove(struct pci_dev *pdev) 112 { 113 struct xilly_endpoint *endpoint = pci_get_drvdata(pdev); 114 115 xillybus_endpoint_remove(endpoint); 116 } 117 118 MODULE_DEVICE_TABLE(pci, xillyids); 119 120 static struct pci_driver xillybus_driver = { 121 .name = xillyname, 122 .id_table = xillyids, 123 .probe = xilly_probe, 124 .remove = xilly_remove, 125 }; 126 127 module_pci_driver(xillybus_driver); 128