xref: /linux/drivers/net/can/ctucanfd/ctucanfd_pci.c (revision 792a5b678e81080313beb3bee19db189aaa2cf8c)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*******************************************************************************
3  *
4  * CTU CAN FD IP Core
5  *
6  * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
7  * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
8  * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
9  * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
10  *
11  * Project advisors:
12  *     Jiri Novak <jnovak@fel.cvut.cz>
13  *     Pavel Pisa <pisa@cmp.felk.cvut.cz>
14  *
15  * Department of Measurement         (http://meas.fel.cvut.cz/)
16  * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
17  * Czech Technical University        (http://www.cvut.cz/)
18  ******************************************************************************/
19 
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 
23 #include "ctucanfd.h"
24 
25 #ifndef PCI_DEVICE_DATA
26 #define PCI_DEVICE_DATA(vend, dev, data) \
27 .vendor = PCI_VENDOR_ID_##vend, \
28 .device = PCI_DEVICE_ID_##vend##_##dev, \
29 .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \
30 .driver_data = (kernel_ulong_t)(data)
31 #endif
32 
33 #ifndef PCI_VENDOR_ID_TEDIA
34 #define PCI_VENDOR_ID_TEDIA 0x1760
35 #endif
36 
37 #ifndef PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
38 #define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
39 #endif
40 
41 #define CTUCAN_BAR0_CTUCAN_ID 0x0000
42 #define CTUCAN_BAR0_CRA_BASE  0x4000
43 #define CYCLONE_IV_CRA_A2P_IE (0x0050)
44 
45 #define CTUCAN_WITHOUT_CTUCAN_ID  0
46 #define CTUCAN_WITH_CTUCAN_ID     1
47 
48 static bool use_msi = true;
49 module_param(use_msi, bool, 0444);
50 MODULE_PARM_DESC(use_msi, "PCIe implementation use MSI interrupts. Default: 1 (yes)");
51 
52 static bool pci_use_second = true;
53 module_param(pci_use_second, bool, 0444);
54 MODULE_PARM_DESC(pci_use_second, "Use the second CAN core on PCIe card. Default: 1 (yes)");
55 
56 struct ctucan_pci_board_data {
57 	void __iomem *bar0_base;
58 	void __iomem *cra_base;
59 	void __iomem *bar1_base;
60 	struct list_head ndev_list_head;
61 	int use_msi;
62 };
63 
64 static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev)
65 {
66 	return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev);
67 }
68 
69 static void ctucan_pci_set_drvdata(struct device *dev,
70 				   struct net_device *ndev)
71 {
72 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
73 	struct ctucan_priv *priv = netdev_priv(ndev);
74 	struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
75 
76 	list_add(&priv->peers_on_pdev, &bdata->ndev_list_head);
77 	priv->irq_flags = IRQF_SHARED;
78 }
79 
80 /**
81  * ctucan_pci_probe - PCI registration call
82  * @pdev:	Handle to the pci device structure
83  * @ent:	Pointer to the entry from ctucan_pci_tbl
84  *
85  * This function does all the memory allocation and registration for the CAN
86  * device.
87  *
88  * Return: 0 on success and failure value on error
89  */
90 static int ctucan_pci_probe(struct pci_dev *pdev,
91 			    const struct pci_device_id *ent)
92 {
93 	struct device	*dev = &pdev->dev;
94 	unsigned long driver_data = ent->driver_data;
95 	struct ctucan_pci_board_data *bdata;
96 	void __iomem *addr;
97 	void __iomem *cra_addr;
98 	void __iomem *bar0_base;
99 	u32 cra_a2p_ie;
100 	u32 ctucan_id = 0;
101 	int ret;
102 	unsigned int ntxbufs;
103 	unsigned int num_cores = 1;
104 	unsigned int core_i = 0;
105 	int irq;
106 	int msi_ok = 0;
107 
108 	ret = pci_enable_device(pdev);
109 	if (ret) {
110 		dev_err(dev, "pci_enable_device FAILED\n");
111 		goto err;
112 	}
113 
114 	ret = pci_request_regions(pdev, KBUILD_MODNAME);
115 	if (ret) {
116 		dev_err(dev, "pci_request_regions FAILED\n");
117 		goto err_disable_device;
118 	}
119 
120 	if (use_msi) {
121 		ret = pci_enable_msi(pdev);
122 		if (!ret) {
123 			dev_info(dev, "MSI enabled\n");
124 			pci_set_master(pdev);
125 			msi_ok = 1;
126 		}
127 	}
128 
129 	dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n",
130 		 (long long)pci_resource_start(pdev, 0),
131 		 (long long)pci_resource_len(pdev, 0));
132 
133 	dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n",
134 		 (long long)pci_resource_start(pdev, 1),
135 		 (long long)pci_resource_len(pdev, 1));
136 
137 	addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
138 	if (!addr) {
139 		dev_err(dev, "PCI BAR 1 cannot be mapped\n");
140 		ret = -ENOMEM;
141 		goto err_release_regions;
142 	}
143 
144 	/* Cyclone IV PCI Express Control Registers Area */
145 	bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
146 	if (!bar0_base) {
147 		dev_err(dev, "PCI BAR 0 cannot be mapped\n");
148 		ret = -EIO;
149 		goto err_pci_iounmap_bar1;
150 	}
151 
152 	if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) {
153 		cra_addr = bar0_base;
154 		num_cores = 2;
155 	} else {
156 		cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE;
157 		ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID);
158 		dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id);
159 		num_cores = ctucan_id & 0xf;
160 	}
161 
162 	irq = pdev->irq;
163 
164 	ntxbufs = 4;
165 
166 	bdata = kzalloc(sizeof(*bdata), GFP_KERNEL);
167 	if (!bdata) {
168 		ret = -ENOMEM;
169 		goto err_pci_iounmap_bar0;
170 	}
171 
172 	INIT_LIST_HEAD(&bdata->ndev_list_head);
173 	bdata->bar0_base = bar0_base;
174 	bdata->cra_base = cra_addr;
175 	bdata->bar1_base = addr;
176 	bdata->use_msi = msi_ok;
177 
178 	pci_set_drvdata(pdev, bdata);
179 
180 	ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
181 				  0, ctucan_pci_set_drvdata);
182 	if (ret < 0)
183 		goto err_free_board;
184 
185 	core_i++;
186 
187 	while (pci_use_second && (core_i < num_cores)) {
188 		addr += 0x4000;
189 		ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
190 					  0, ctucan_pci_set_drvdata);
191 		if (ret < 0) {
192 			dev_info(dev, "CTU CAN FD core %d initialization failed\n",
193 				 core_i);
194 			break;
195 		}
196 		core_i++;
197 	}
198 
199 	/* enable interrupt in
200 	 * Avalon-MM to PCI Express Interrupt Enable Register
201 	 */
202 	cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
203 	dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
204 	cra_a2p_ie |= 1;
205 	iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE);
206 	cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
207 	dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
208 
209 	return 0;
210 
211 err_free_board:
212 	pci_set_drvdata(pdev, NULL);
213 	kfree(bdata);
214 err_pci_iounmap_bar0:
215 	pci_iounmap(pdev, cra_addr);
216 err_pci_iounmap_bar1:
217 	pci_iounmap(pdev, addr);
218 err_release_regions:
219 	if (msi_ok) {
220 		pci_disable_msi(pdev);
221 		pci_clear_master(pdev);
222 	}
223 	pci_release_regions(pdev);
224 err_disable_device:
225 	pci_disable_device(pdev);
226 err:
227 	return ret;
228 }
229 
230 /**
231  * ctucan_pci_remove - Unregister the device after releasing the resources
232  * @pdev:	Handle to the pci device structure
233  *
234  * This function frees all the resources allocated to the device.
235  * Return: 0 always
236  */
237 static void ctucan_pci_remove(struct pci_dev *pdev)
238 {
239 	struct net_device *ndev;
240 	struct ctucan_priv *priv = NULL;
241 	struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
242 
243 	dev_dbg(&pdev->dev, "ctucan_remove");
244 
245 	if (!bdata) {
246 		dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
247 		return;
248 	}
249 
250 	/* disable interrupt in
251 	 * Avalon-MM to PCI Express Interrupt Enable Register
252 	 */
253 	if (bdata->cra_base)
254 		iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
255 
256 	while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
257 						peers_on_pdev)) != NULL) {
258 		ndev = priv->can.dev;
259 
260 		unregister_candev(ndev);
261 
262 		netif_napi_del(&priv->napi);
263 
264 		list_del_init(&priv->peers_on_pdev);
265 		free_candev(ndev);
266 	}
267 
268 	pci_iounmap(pdev, bdata->bar1_base);
269 
270 	if (bdata->use_msi) {
271 		pci_disable_msi(pdev);
272 		pci_clear_master(pdev);
273 	}
274 
275 	pci_release_regions(pdev);
276 	pci_disable_device(pdev);
277 
278 	pci_iounmap(pdev, bdata->bar0_base);
279 
280 	pci_set_drvdata(pdev, NULL);
281 	kfree(bdata);
282 }
283 
284 static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
285 
286 static const struct pci_device_id ctucan_pci_tbl[] = {
287 	{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
288 		CTUCAN_WITH_CTUCAN_ID)},
289 	{},
290 };
291 
292 static struct pci_driver ctucan_pci_driver = {
293 	.name = KBUILD_MODNAME,
294 	.id_table = ctucan_pci_tbl,
295 	.probe = ctucan_pci_probe,
296 	.remove = ctucan_pci_remove,
297 	.driver.pm = &ctucan_pci_pm_ops,
298 };
299 
300 module_pci_driver(ctucan_pci_driver);
301 
302 MODULE_LICENSE("GPL");
303 MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
304 MODULE_DESCRIPTION("CTU CAN FD for PCI bus");
305