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