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/pci-aspm.h> 13 #include <linux/slab.h> 14 #include "xillybus.h" 15 16 MODULE_DESCRIPTION("Xillybus driver for PCIe"); 17 MODULE_AUTHOR("Eli Billauer, Xillybus Ltd."); 18 MODULE_VERSION("1.06"); 19 MODULE_ALIAS("xillybus_pcie"); 20 MODULE_LICENSE("GPL v2"); 21 22 #define PCI_DEVICE_ID_XILLYBUS 0xebeb 23 24 #define PCI_VENDOR_ID_ACTEL 0x11aa 25 #define PCI_VENDOR_ID_LATTICE 0x1204 26 27 static const char xillyname[] = "xillybus_pcie"; 28 29 static const struct pci_device_id xillyids[] = { 30 {PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)}, 31 {PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)}, 32 {PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)}, 33 {PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)}, 34 { /* End: all zeroes */ } 35 }; 36 37 static int xilly_pci_direction(int direction) 38 { 39 switch (direction) { 40 case DMA_TO_DEVICE: 41 return PCI_DMA_TODEVICE; 42 case DMA_FROM_DEVICE: 43 return PCI_DMA_FROMDEVICE; 44 default: 45 return PCI_DMA_BIDIRECTIONAL; 46 } 47 } 48 49 static void xilly_dma_sync_single_for_cpu_pci(struct xilly_endpoint *ep, 50 dma_addr_t dma_handle, 51 size_t size, 52 int direction) 53 { 54 pci_dma_sync_single_for_cpu(ep->pdev, 55 dma_handle, 56 size, 57 xilly_pci_direction(direction)); 58 } 59 60 static void xilly_dma_sync_single_for_device_pci(struct xilly_endpoint *ep, 61 dma_addr_t dma_handle, 62 size_t size, 63 int direction) 64 { 65 pci_dma_sync_single_for_device(ep->pdev, 66 dma_handle, 67 size, 68 xilly_pci_direction(direction)); 69 } 70 71 static void xilly_pci_unmap(void *ptr) 72 { 73 struct xilly_mapping *data = ptr; 74 75 pci_unmap_single(data->device, data->dma_addr, 76 data->size, data->direction); 77 78 kfree(ptr); 79 } 80 81 /* 82 * Map either through the PCI DMA mapper or the non_PCI one. Behind the 83 * scenes exactly the same functions are called with the same parameters, 84 * but that can change. 85 */ 86 87 static int xilly_map_single_pci(struct xilly_endpoint *ep, 88 void *ptr, 89 size_t size, 90 int direction, 91 dma_addr_t *ret_dma_handle 92 ) 93 { 94 int pci_direction; 95 dma_addr_t addr; 96 struct xilly_mapping *this; 97 98 this = kzalloc(sizeof(*this), GFP_KERNEL); 99 if (!this) 100 return -ENOMEM; 101 102 pci_direction = xilly_pci_direction(direction); 103 104 addr = pci_map_single(ep->pdev, ptr, size, pci_direction); 105 106 if (pci_dma_mapping_error(ep->pdev, addr)) { 107 kfree(this); 108 return -ENODEV; 109 } 110 111 this->device = ep->pdev; 112 this->dma_addr = addr; 113 this->size = size; 114 this->direction = pci_direction; 115 116 *ret_dma_handle = addr; 117 118 return devm_add_action_or_reset(ep->dev, xilly_pci_unmap, this); 119 } 120 121 static struct xilly_endpoint_hardware pci_hw = { 122 .owner = THIS_MODULE, 123 .hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_pci, 124 .hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_pci, 125 .map_single = xilly_map_single_pci, 126 }; 127 128 static int xilly_probe(struct pci_dev *pdev, 129 const struct pci_device_id *ent) 130 { 131 struct xilly_endpoint *endpoint; 132 int rc; 133 134 endpoint = xillybus_init_endpoint(pdev, &pdev->dev, &pci_hw); 135 136 if (!endpoint) 137 return -ENOMEM; 138 139 pci_set_drvdata(pdev, endpoint); 140 141 rc = pcim_enable_device(pdev); 142 if (rc) { 143 dev_err(endpoint->dev, 144 "pcim_enable_device() failed. Aborting.\n"); 145 return rc; 146 } 147 148 /* L0s has caused packet drops. No power saving, thank you. */ 149 150 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); 151 152 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 153 dev_err(endpoint->dev, 154 "Incorrect BAR configuration. Aborting.\n"); 155 return -ENODEV; 156 } 157 158 rc = pcim_iomap_regions(pdev, 0x01, xillyname); 159 if (rc) { 160 dev_err(endpoint->dev, 161 "pcim_iomap_regions() failed. Aborting.\n"); 162 return rc; 163 } 164 165 endpoint->registers = pcim_iomap_table(pdev)[0]; 166 167 pci_set_master(pdev); 168 169 /* Set up a single MSI interrupt */ 170 if (pci_enable_msi(pdev)) { 171 dev_err(endpoint->dev, 172 "Failed to enable MSI interrupts. Aborting.\n"); 173 return -ENODEV; 174 } 175 rc = devm_request_irq(&pdev->dev, pdev->irq, xillybus_isr, 0, 176 xillyname, endpoint); 177 if (rc) { 178 dev_err(endpoint->dev, 179 "Failed to register MSI handler. Aborting.\n"); 180 return -ENODEV; 181 } 182 183 /* 184 * Some (old and buggy?) hardware drops 64-bit addressed PCIe packets, 185 * even when the PCIe driver claims that a 64-bit mask is OK. On the 186 * other hand, on some architectures, 64-bit addressing is mandatory. 187 * So go for the 64-bit mask only when failing is the other option. 188 */ 189 190 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { 191 endpoint->dma_using_dac = 0; 192 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { 193 endpoint->dma_using_dac = 1; 194 } else { 195 dev_err(endpoint->dev, "Failed to set DMA mask. Aborting.\n"); 196 return -ENODEV; 197 } 198 199 return xillybus_endpoint_discovery(endpoint); 200 } 201 202 static void xilly_remove(struct pci_dev *pdev) 203 { 204 struct xilly_endpoint *endpoint = pci_get_drvdata(pdev); 205 206 xillybus_endpoint_remove(endpoint); 207 } 208 209 MODULE_DEVICE_TABLE(pci, xillyids); 210 211 static struct pci_driver xillybus_driver = { 212 .name = xillyname, 213 .id_table = xillyids, 214 .probe = xilly_probe, 215 .remove = xilly_remove, 216 }; 217 218 module_pci_driver(xillybus_driver); 219