Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*******************************************************************************
0003  *
0004  * CTU CAN FD IP Core
0005  *
0006  * Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
0007  * Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
0008  * Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
0009  * Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
0010  *
0011  * Project advisors:
0012  *     Jiri Novak <jnovak@fel.cvut.cz>
0013  *     Pavel Pisa <pisa@cmp.felk.cvut.cz>
0014  *
0015  * Department of Measurement         (http://meas.fel.cvut.cz/)
0016  * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
0017  * Czech Technical University        (http://www.cvut.cz/)
0018  ******************************************************************************/
0019 
0020 #include <linux/module.h>
0021 #include <linux/pci.h>
0022 
0023 #include "ctucanfd.h"
0024 
0025 #ifndef PCI_DEVICE_DATA
0026 #define PCI_DEVICE_DATA(vend, dev, data) \
0027 .vendor = PCI_VENDOR_ID_##vend, \
0028 .device = PCI_DEVICE_ID_##vend##_##dev, \
0029 .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \
0030 .driver_data = (kernel_ulong_t)(data)
0031 #endif
0032 
0033 #ifndef PCI_VENDOR_ID_TEDIA
0034 #define PCI_VENDOR_ID_TEDIA 0x1760
0035 #endif
0036 
0037 #ifndef PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
0038 #define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
0039 #endif
0040 
0041 #define CTUCAN_BAR0_CTUCAN_ID 0x0000
0042 #define CTUCAN_BAR0_CRA_BASE  0x4000
0043 #define CYCLONE_IV_CRA_A2P_IE (0x0050)
0044 
0045 #define CTUCAN_WITHOUT_CTUCAN_ID  0
0046 #define CTUCAN_WITH_CTUCAN_ID     1
0047 
0048 struct ctucan_pci_board_data {
0049     void __iomem *bar0_base;
0050     void __iomem *cra_base;
0051     void __iomem *bar1_base;
0052     struct list_head ndev_list_head;
0053     int use_msi;
0054 };
0055 
0056 static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev)
0057 {
0058     return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev);
0059 }
0060 
0061 static void ctucan_pci_set_drvdata(struct device *dev,
0062                    struct net_device *ndev)
0063 {
0064     struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
0065     struct ctucan_priv *priv = netdev_priv(ndev);
0066     struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
0067 
0068     list_add(&priv->peers_on_pdev, &bdata->ndev_list_head);
0069     priv->irq_flags = IRQF_SHARED;
0070 }
0071 
0072 /**
0073  * ctucan_pci_probe - PCI registration call
0074  * @pdev:   Handle to the pci device structure
0075  * @ent:    Pointer to the entry from ctucan_pci_tbl
0076  *
0077  * This function does all the memory allocation and registration for the CAN
0078  * device.
0079  *
0080  * Return: 0 on success and failure value on error
0081  */
0082 static int ctucan_pci_probe(struct pci_dev *pdev,
0083                 const struct pci_device_id *ent)
0084 {
0085     struct device   *dev = &pdev->dev;
0086     unsigned long driver_data = ent->driver_data;
0087     struct ctucan_pci_board_data *bdata;
0088     void __iomem *addr;
0089     void __iomem *cra_addr;
0090     void __iomem *bar0_base;
0091     u32 cra_a2p_ie;
0092     u32 ctucan_id = 0;
0093     int ret;
0094     unsigned int ntxbufs;
0095     unsigned int num_cores = 1;
0096     unsigned int core_i = 0;
0097     int irq;
0098     int msi_ok = 0;
0099 
0100     ret = pci_enable_device(pdev);
0101     if (ret) {
0102         dev_err(dev, "pci_enable_device FAILED\n");
0103         goto err;
0104     }
0105 
0106     ret = pci_request_regions(pdev, KBUILD_MODNAME);
0107     if (ret) {
0108         dev_err(dev, "pci_request_regions FAILED\n");
0109         goto err_disable_device;
0110     }
0111 
0112     ret = pci_enable_msi(pdev);
0113     if (!ret) {
0114         dev_info(dev, "MSI enabled\n");
0115         pci_set_master(pdev);
0116         msi_ok = 1;
0117     }
0118 
0119     dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n",
0120          (long long)pci_resource_start(pdev, 0),
0121          (long long)pci_resource_len(pdev, 0));
0122 
0123     dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n",
0124          (long long)pci_resource_start(pdev, 1),
0125          (long long)pci_resource_len(pdev, 1));
0126 
0127     addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
0128     if (!addr) {
0129         dev_err(dev, "PCI BAR 1 cannot be mapped\n");
0130         ret = -ENOMEM;
0131         goto err_release_regions;
0132     }
0133 
0134     /* Cyclone IV PCI Express Control Registers Area */
0135     bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
0136     if (!bar0_base) {
0137         dev_err(dev, "PCI BAR 0 cannot be mapped\n");
0138         ret = -EIO;
0139         goto err_pci_iounmap_bar1;
0140     }
0141 
0142     if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) {
0143         cra_addr = bar0_base;
0144         num_cores = 2;
0145     } else {
0146         cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE;
0147         ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID);
0148         dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id);
0149         num_cores = ctucan_id & 0xf;
0150     }
0151 
0152     irq = pdev->irq;
0153 
0154     ntxbufs = 4;
0155 
0156     bdata = kzalloc(sizeof(*bdata), GFP_KERNEL);
0157     if (!bdata) {
0158         ret = -ENOMEM;
0159         goto err_pci_iounmap_bar0;
0160     }
0161 
0162     INIT_LIST_HEAD(&bdata->ndev_list_head);
0163     bdata->bar0_base = bar0_base;
0164     bdata->cra_base = cra_addr;
0165     bdata->bar1_base = addr;
0166     bdata->use_msi = msi_ok;
0167 
0168     pci_set_drvdata(pdev, bdata);
0169 
0170     ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
0171                   0, ctucan_pci_set_drvdata);
0172     if (ret < 0)
0173         goto err_free_board;
0174 
0175     core_i++;
0176 
0177     while (core_i < num_cores) {
0178         addr += 0x4000;
0179         ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
0180                       0, ctucan_pci_set_drvdata);
0181         if (ret < 0) {
0182             dev_info(dev, "CTU CAN FD core %d initialization failed\n",
0183                  core_i);
0184             break;
0185         }
0186         core_i++;
0187     }
0188 
0189     /* enable interrupt in
0190      * Avalon-MM to PCI Express Interrupt Enable Register
0191      */
0192     cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
0193     dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
0194     cra_a2p_ie |= 1;
0195     iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE);
0196     cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
0197     dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
0198 
0199     return 0;
0200 
0201 err_free_board:
0202     pci_set_drvdata(pdev, NULL);
0203     kfree(bdata);
0204 err_pci_iounmap_bar0:
0205     pci_iounmap(pdev, cra_addr);
0206 err_pci_iounmap_bar1:
0207     pci_iounmap(pdev, addr);
0208 err_release_regions:
0209     if (msi_ok) {
0210         pci_disable_msi(pdev);
0211         pci_clear_master(pdev);
0212     }
0213     pci_release_regions(pdev);
0214 err_disable_device:
0215     pci_disable_device(pdev);
0216 err:
0217     return ret;
0218 }
0219 
0220 /**
0221  * ctucan_pci_remove - Unregister the device after releasing the resources
0222  * @pdev:   Handle to the pci device structure
0223  *
0224  * This function frees all the resources allocated to the device.
0225  * Return: 0 always
0226  */
0227 static void ctucan_pci_remove(struct pci_dev *pdev)
0228 {
0229     struct net_device *ndev;
0230     struct ctucan_priv *priv = NULL;
0231     struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
0232 
0233     dev_dbg(&pdev->dev, "ctucan_remove");
0234 
0235     if (!bdata) {
0236         dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
0237         return;
0238     }
0239 
0240     /* disable interrupt in
0241      * Avalon-MM to PCI Express Interrupt Enable Register
0242      */
0243     if (bdata->cra_base)
0244         iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
0245 
0246     while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
0247                         peers_on_pdev)) != NULL) {
0248         ndev = priv->can.dev;
0249 
0250         unregister_candev(ndev);
0251 
0252         netif_napi_del(&priv->napi);
0253 
0254         list_del_init(&priv->peers_on_pdev);
0255         free_candev(ndev);
0256     }
0257 
0258     pci_iounmap(pdev, bdata->bar1_base);
0259 
0260     if (bdata->use_msi) {
0261         pci_disable_msi(pdev);
0262         pci_clear_master(pdev);
0263     }
0264 
0265     pci_release_regions(pdev);
0266     pci_disable_device(pdev);
0267 
0268     pci_iounmap(pdev, bdata->bar0_base);
0269 
0270     pci_set_drvdata(pdev, NULL);
0271     kfree(bdata);
0272 }
0273 
0274 static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
0275 
0276 static const struct pci_device_id ctucan_pci_tbl[] = {
0277     {PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
0278         CTUCAN_WITH_CTUCAN_ID)},
0279     {},
0280 };
0281 
0282 static struct pci_driver ctucan_pci_driver = {
0283     .name = KBUILD_MODNAME,
0284     .id_table = ctucan_pci_tbl,
0285     .probe = ctucan_pci_probe,
0286     .remove = ctucan_pci_remove,
0287     .driver.pm = &ctucan_pci_pm_ops,
0288 };
0289 
0290 module_pci_driver(ctucan_pci_driver);
0291 
0292 MODULE_LICENSE("GPL");
0293 MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
0294 MODULE_DESCRIPTION("CTU CAN FD for PCI bus");