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

m_can_pci.c (4678B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PCI Specific M_CAN Glue
      4 *
      5 * Copyright (C) 2018-2020 Intel Corporation
      6 * Author: Felipe Balbi (Intel)
      7 * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
      8 * Author: Raymond Tan <raymond.tan@intel.com>
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/netdevice.h>
     14#include <linux/pci.h>
     15#include <linux/pm_runtime.h>
     16
     17#include "m_can.h"
     18
     19#define M_CAN_PCI_MMIO_BAR		0
     20
     21#define M_CAN_CLOCK_FREQ_EHL		200000000
     22#define CTL_CSR_INT_CTL_OFFSET		0x508
     23
     24struct m_can_pci_priv {
     25	struct m_can_classdev cdev;
     26
     27	void __iomem *base;
     28};
     29
     30static inline struct m_can_pci_priv *cdev_to_priv(struct m_can_classdev *cdev)
     31{
     32	return container_of(cdev, struct m_can_pci_priv, cdev);
     33}
     34
     35static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
     36{
     37	struct m_can_pci_priv *priv = cdev_to_priv(cdev);
     38
     39	return readl(priv->base + reg);
     40}
     41
     42static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
     43{
     44	struct m_can_pci_priv *priv = cdev_to_priv(cdev);
     45	void __iomem *src = priv->base + offset;
     46
     47	while (val_count--) {
     48		*(unsigned int *)val = ioread32(src);
     49		val += 4;
     50		src += 4;
     51	}
     52
     53	return 0;
     54}
     55
     56static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
     57{
     58	struct m_can_pci_priv *priv = cdev_to_priv(cdev);
     59
     60	writel(val, priv->base + reg);
     61
     62	return 0;
     63}
     64
     65static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
     66			    const void *val, size_t val_count)
     67{
     68	struct m_can_pci_priv *priv = cdev_to_priv(cdev);
     69	void __iomem *dst = priv->base + offset;
     70
     71	while (val_count--) {
     72		iowrite32(*(unsigned int *)val, dst);
     73		val += 4;
     74		dst += 4;
     75	}
     76
     77	return 0;
     78}
     79
     80static struct m_can_ops m_can_pci_ops = {
     81	.read_reg = iomap_read_reg,
     82	.write_reg = iomap_write_reg,
     83	.write_fifo = iomap_write_fifo,
     84	.read_fifo = iomap_read_fifo,
     85};
     86
     87static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
     88{
     89	struct device *dev = &pci->dev;
     90	struct m_can_classdev *mcan_class;
     91	struct m_can_pci_priv *priv;
     92	void __iomem *base;
     93	int ret;
     94
     95	ret = pcim_enable_device(pci);
     96	if (ret)
     97		return ret;
     98
     99	pci_set_master(pci);
    100
    101	ret = pcim_iomap_regions(pci, BIT(M_CAN_PCI_MMIO_BAR), pci_name(pci));
    102	if (ret)
    103		return ret;
    104
    105	base = pcim_iomap_table(pci)[M_CAN_PCI_MMIO_BAR];
    106
    107	if (!base) {
    108		dev_err(dev, "failed to map BARs\n");
    109		return -ENOMEM;
    110	}
    111
    112	mcan_class = m_can_class_allocate_dev(&pci->dev,
    113					      sizeof(struct m_can_pci_priv));
    114	if (!mcan_class)
    115		return -ENOMEM;
    116
    117	priv = cdev_to_priv(mcan_class);
    118
    119	priv->base = base;
    120
    121	ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_ALL_TYPES);
    122	if (ret < 0)
    123		return ret;
    124
    125	mcan_class->dev = &pci->dev;
    126	mcan_class->net->irq = pci_irq_vector(pci, 0);
    127	mcan_class->pm_clock_support = 1;
    128	mcan_class->can.clock.freq = id->driver_data;
    129	mcan_class->ops = &m_can_pci_ops;
    130
    131	pci_set_drvdata(pci, mcan_class);
    132
    133	ret = m_can_class_register(mcan_class);
    134	if (ret)
    135		goto err;
    136
    137	/* Enable interrupt control at CAN wrapper IP */
    138	writel(0x1, base + CTL_CSR_INT_CTL_OFFSET);
    139
    140	pm_runtime_set_autosuspend_delay(dev, 1000);
    141	pm_runtime_use_autosuspend(dev);
    142	pm_runtime_put_noidle(dev);
    143	pm_runtime_allow(dev);
    144
    145	return 0;
    146
    147err:
    148	pci_free_irq_vectors(pci);
    149	return ret;
    150}
    151
    152static void m_can_pci_remove(struct pci_dev *pci)
    153{
    154	struct m_can_classdev *mcan_class = pci_get_drvdata(pci);
    155	struct m_can_pci_priv *priv = cdev_to_priv(mcan_class);
    156
    157	pm_runtime_forbid(&pci->dev);
    158	pm_runtime_get_noresume(&pci->dev);
    159
    160	/* Disable interrupt control at CAN wrapper IP */
    161	writel(0x0, priv->base + CTL_CSR_INT_CTL_OFFSET);
    162
    163	m_can_class_unregister(mcan_class);
    164	pci_free_irq_vectors(pci);
    165}
    166
    167static __maybe_unused int m_can_pci_suspend(struct device *dev)
    168{
    169	return m_can_class_suspend(dev);
    170}
    171
    172static __maybe_unused int m_can_pci_resume(struct device *dev)
    173{
    174	return m_can_class_resume(dev);
    175}
    176
    177static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
    178			 m_can_pci_suspend, m_can_pci_resume);
    179
    180static const struct pci_device_id m_can_pci_id_table[] = {
    181	{ PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, },
    182	{ PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, },
    183	{  }	/* Terminating Entry */
    184};
    185MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);
    186
    187static struct pci_driver m_can_pci_driver = {
    188	.name = "m_can_pci",
    189	.probe = m_can_pci_probe,
    190	.remove = m_can_pci_remove,
    191	.id_table = m_can_pci_id_table,
    192	.driver = {
    193		.pm = &m_can_pci_pm_ops,
    194	},
    195};
    196
    197module_pci_driver(m_can_pci_driver);
    198
    199MODULE_AUTHOR("Felipe Balbi (Intel)");
    200MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
    201MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
    202MODULE_LICENSE("GPL");
    203MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller on PCI bus");