xref: /linux/drivers/net/can/ctucanfd/ctucanfd_pci.c (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
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 struct ctucan_pci_board_data {
49 	void __iomem *bar0_base;
50 	void __iomem *cra_base;
51 	void __iomem *bar1_base;
52 	struct list_head ndev_list_head;
53 	int use_msi;
54 };
55 
56 static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev)
57 {
58 	return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev);
59 }
60 
61 static void ctucan_pci_set_drvdata(struct device *dev,
62 				   struct net_device *ndev)
63 {
64 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
65 	struct ctucan_priv *priv = netdev_priv(ndev);
66 	struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
67 
68 	list_add(&priv->peers_on_pdev, &bdata->ndev_list_head);
69 	priv->irq_flags = IRQF_SHARED;
70 }
71 
72 /**
73  * ctucan_pci_probe - PCI registration call
74  * @pdev:	Handle to the pci device structure
75  * @ent:	Pointer to the entry from ctucan_pci_tbl
76  *
77  * This function does all the memory allocation and registration for the CAN
78  * device.
79  *
80  * Return: 0 on success and failure value on error
81  */
82 static int ctucan_pci_probe(struct pci_dev *pdev,
83 			    const struct pci_device_id *ent)
84 {
85 	struct device	*dev = &pdev->dev;
86 	unsigned long driver_data = ent->driver_data;
87 	struct ctucan_pci_board_data *bdata;
88 	void __iomem *addr;
89 	void __iomem *cra_addr;
90 	void __iomem *bar0_base;
91 	u32 cra_a2p_ie;
92 	u32 ctucan_id = 0;
93 	int ret;
94 	unsigned int ntxbufs;
95 	unsigned int num_cores = 1;
96 	unsigned int core_i = 0;
97 	int irq;
98 	int msi_ok = 0;
99 
100 	ret = pci_enable_device(pdev);
101 	if (ret) {
102 		dev_err(dev, "pci_enable_device FAILED\n");
103 		goto err;
104 	}
105 
106 	ret = pci_request_regions(pdev, KBUILD_MODNAME);
107 	if (ret) {
108 		dev_err(dev, "pci_request_regions FAILED\n");
109 		goto err_disable_device;
110 	}
111 
112 	ret = pci_enable_msi(pdev);
113 	if (!ret) {
114 		dev_info(dev, "MSI enabled\n");
115 		pci_set_master(pdev);
116 		msi_ok = 1;
117 	}
118 
119 	dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n",
120 		 (long long)pci_resource_start(pdev, 0),
121 		 (long long)pci_resource_len(pdev, 0));
122 
123 	dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n",
124 		 (long long)pci_resource_start(pdev, 1),
125 		 (long long)pci_resource_len(pdev, 1));
126 
127 	addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
128 	if (!addr) {
129 		dev_err(dev, "PCI BAR 1 cannot be mapped\n");
130 		ret = -ENOMEM;
131 		goto err_release_regions;
132 	}
133 
134 	/* Cyclone IV PCI Express Control Registers Area */
135 	bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
136 	if (!bar0_base) {
137 		dev_err(dev, "PCI BAR 0 cannot be mapped\n");
138 		ret = -EIO;
139 		goto err_pci_iounmap_bar1;
140 	}
141 
142 	if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) {
143 		cra_addr = bar0_base;
144 		num_cores = 2;
145 	} else {
146 		cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE;
147 		ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID);
148 		dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id);
149 		num_cores = ctucan_id & 0xf;
150 	}
151 
152 	irq = pdev->irq;
153 
154 	ntxbufs = 4;
155 
156 	bdata = kzalloc(sizeof(*bdata), GFP_KERNEL);
157 	if (!bdata) {
158 		ret = -ENOMEM;
159 		goto err_pci_iounmap_bar0;
160 	}
161 
162 	INIT_LIST_HEAD(&bdata->ndev_list_head);
163 	bdata->bar0_base = bar0_base;
164 	bdata->cra_base = cra_addr;
165 	bdata->bar1_base = addr;
166 	bdata->use_msi = msi_ok;
167 
168 	pci_set_drvdata(pdev, bdata);
169 
170 	ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
171 				  0, ctucan_pci_set_drvdata);
172 	if (ret < 0)
173 		goto err_free_board;
174 
175 	core_i++;
176 
177 	while (core_i < num_cores) {
178 		addr += 0x4000;
179 		ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
180 					  0, ctucan_pci_set_drvdata);
181 		if (ret < 0) {
182 			dev_info(dev, "CTU CAN FD core %d initialization failed\n",
183 				 core_i);
184 			break;
185 		}
186 		core_i++;
187 	}
188 
189 	/* enable interrupt in
190 	 * Avalon-MM to PCI Express Interrupt Enable Register
191 	 */
192 	cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
193 	dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
194 	cra_a2p_ie |= 1;
195 	iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE);
196 	cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
197 	dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
198 
199 	return 0;
200 
201 err_free_board:
202 	pci_set_drvdata(pdev, NULL);
203 	kfree(bdata);
204 err_pci_iounmap_bar0:
205 	pci_iounmap(pdev, cra_addr);
206 err_pci_iounmap_bar1:
207 	pci_iounmap(pdev, addr);
208 err_release_regions:
209 	if (msi_ok)
210 		pci_disable_msi(pdev);
211 	pci_release_regions(pdev);
212 err_disable_device:
213 	pci_disable_device(pdev);
214 err:
215 	return ret;
216 }
217 
218 /**
219  * ctucan_pci_remove - Unregister the device after releasing the resources
220  * @pdev:	Handle to the pci device structure
221  *
222  * This function frees all the resources allocated to the device.
223  * Return: 0 always
224  */
225 static void ctucan_pci_remove(struct pci_dev *pdev)
226 {
227 	struct net_device *ndev;
228 	struct ctucan_priv *priv = NULL;
229 	struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
230 
231 	dev_dbg(&pdev->dev, "ctucan_remove");
232 
233 	if (!bdata) {
234 		dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
235 		return;
236 	}
237 
238 	/* disable interrupt in
239 	 * Avalon-MM to PCI Express Interrupt Enable Register
240 	 */
241 	if (bdata->cra_base)
242 		iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
243 
244 	while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
245 						peers_on_pdev)) != NULL) {
246 		ndev = priv->can.dev;
247 
248 		unregister_candev(ndev);
249 
250 		netif_napi_del(&priv->napi);
251 
252 		list_del_init(&priv->peers_on_pdev);
253 		free_candev(ndev);
254 	}
255 
256 	pci_iounmap(pdev, bdata->bar1_base);
257 
258 	if (bdata->use_msi)
259 		pci_disable_msi(pdev);
260 
261 	pci_release_regions(pdev);
262 	pci_disable_device(pdev);
263 
264 	pci_iounmap(pdev, bdata->bar0_base);
265 
266 	pci_set_drvdata(pdev, NULL);
267 	kfree(bdata);
268 }
269 
270 static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
271 
272 static const struct pci_device_id ctucan_pci_tbl[] = {
273 	{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
274 		CTUCAN_WITH_CTUCAN_ID)},
275 	{},
276 };
277 
278 static struct pci_driver ctucan_pci_driver = {
279 	.name = KBUILD_MODNAME,
280 	.id_table = ctucan_pci_tbl,
281 	.probe = ctucan_pci_probe,
282 	.remove = ctucan_pci_remove,
283 	.driver.pm = &ctucan_pci_pm_ops,
284 };
285 
286 module_pci_driver(ctucan_pci_driver);
287 
288 MODULE_LICENSE("GPL");
289 MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
290 MODULE_DESCRIPTION("CTU CAN FD for PCI bus");
291