cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ctucanfd_pci.c (7516B)


      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
     48struct 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
     56static 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
     61static 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 */
     82static 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
    201err_free_board:
    202	pci_set_drvdata(pdev, NULL);
    203	kfree(bdata);
    204err_pci_iounmap_bar0:
    205	pci_iounmap(pdev, cra_addr);
    206err_pci_iounmap_bar1:
    207	pci_iounmap(pdev, addr);
    208err_release_regions:
    209	if (msi_ok) {
    210		pci_disable_msi(pdev);
    211		pci_clear_master(pdev);
    212	}
    213	pci_release_regions(pdev);
    214err_disable_device:
    215	pci_disable_device(pdev);
    216err:
    217	return ret;
    218}
    219
    220/**
    221 * ctucan_pci_remove - Unregister the device after releasing the resources
    222 * @pdev:	Handle to the pci device structure
    223 *
    224 * This function frees all the resources allocated to the device.
    225 * Return: 0 always
    226 */
    227static void ctucan_pci_remove(struct pci_dev *pdev)
    228{
    229	struct net_device *ndev;
    230	struct ctucan_priv *priv = NULL;
    231	struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
    232
    233	dev_dbg(&pdev->dev, "ctucan_remove");
    234
    235	if (!bdata) {
    236		dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
    237		return;
    238	}
    239
    240	/* disable interrupt in
    241	 * Avalon-MM to PCI Express Interrupt Enable Register
    242	 */
    243	if (bdata->cra_base)
    244		iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
    245
    246	while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
    247						peers_on_pdev)) != NULL) {
    248		ndev = priv->can.dev;
    249
    250		unregister_candev(ndev);
    251
    252		netif_napi_del(&priv->napi);
    253
    254		list_del_init(&priv->peers_on_pdev);
    255		free_candev(ndev);
    256	}
    257
    258	pci_iounmap(pdev, bdata->bar1_base);
    259
    260	if (bdata->use_msi) {
    261		pci_disable_msi(pdev);
    262		pci_clear_master(pdev);
    263	}
    264
    265	pci_release_regions(pdev);
    266	pci_disable_device(pdev);
    267
    268	pci_iounmap(pdev, bdata->bar0_base);
    269
    270	pci_set_drvdata(pdev, NULL);
    271	kfree(bdata);
    272}
    273
    274static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
    275
    276static const struct pci_device_id ctucan_pci_tbl[] = {
    277	{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
    278		CTUCAN_WITH_CTUCAN_ID)},
    279	{},
    280};
    281
    282static struct pci_driver ctucan_pci_driver = {
    283	.name = KBUILD_MODNAME,
    284	.id_table = ctucan_pci_tbl,
    285	.probe = ctucan_pci_probe,
    286	.remove = ctucan_pci_remove,
    287	.driver.pm = &ctucan_pci_pm_ops,
    288};
    289
    290module_pci_driver(ctucan_pci_driver);
    291
    292MODULE_LICENSE("GPL");
    293MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
    294MODULE_DESCRIPTION("CTU CAN FD for PCI bus");