]> Git Repo - linux.git/blob - drivers/net/can/ctucanfd/ctucanfd_pci.c
drm/amd/display: Adjust the MST resume flow
[linux.git] / drivers / net / can / ctucanfd / ctucanfd_pci.c
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 <[email protected]> FEE CTU
7  * Copyright (C) 2018-2021 Ondrej Ille <[email protected]> self-funded
8  * Copyright (C) 2018-2019 Martin Jerabek <[email protected]> FEE CTU
9  * Copyright (C) 2018-2022 Pavel Pisa <[email protected]> FEE CTU/self-funded
10  *
11  * Project advisors:
12  *     Jiri Novak <[email protected]>
13  *     Pavel Pisa <[email protected]>
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 <[email protected]>");
290 MODULE_DESCRIPTION("CTU CAN FD for PCI bus");
This page took 0.051324 seconds and 4 git commands to generate.