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

janz-cmodio.c (7185B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Janz CMOD-IO MODULbus Carrier Board PCI Driver
      4 *
      5 * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
      6 *
      7 * Lots of inspiration and code was copied from drivers/mfd/sm501.c
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/pci.h>
     13#include <linux/interrupt.h>
     14#include <linux/delay.h>
     15#include <linux/platform_device.h>
     16#include <linux/slab.h>
     17#include <linux/mfd/core.h>
     18
     19#include <linux/mfd/janz.h>
     20
     21#define DRV_NAME "janz-cmodio"
     22
     23/* Size of each MODULbus module in PCI BAR4 */
     24#define CMODIO_MODULBUS_SIZE	0x200
     25
     26/* Maximum number of MODULbus modules on a CMOD-IO carrier board */
     27#define CMODIO_MAX_MODULES	4
     28
     29/* Module Parameters */
     30static unsigned int num_modules = CMODIO_MAX_MODULES;
     31static char *modules[CMODIO_MAX_MODULES] = {
     32	"empty", "empty", "empty", "empty",
     33};
     34
     35module_param_array(modules, charp, &num_modules, S_IRUGO);
     36MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
     37
     38/* Unique Device Id */
     39static unsigned int cmodio_id;
     40
     41struct cmodio_device {
     42	/* Parent PCI device */
     43	struct pci_dev *pdev;
     44
     45	/* PLX control registers */
     46	struct janz_cmodio_onboard_regs __iomem *ctrl;
     47
     48	/* hex switch position */
     49	u8 hex;
     50
     51	/* mfd-core API */
     52	struct mfd_cell cells[CMODIO_MAX_MODULES];
     53	struct resource resources[3 * CMODIO_MAX_MODULES];
     54	struct janz_platform_data pdata[CMODIO_MAX_MODULES];
     55};
     56
     57/*
     58 * Subdevices using the mfd-core API
     59 */
     60
     61static int cmodio_setup_subdevice(struct cmodio_device *priv,
     62					    char *name, unsigned int devno,
     63					    unsigned int modno)
     64{
     65	struct janz_platform_data *pdata;
     66	struct mfd_cell *cell;
     67	struct resource *res;
     68	struct pci_dev *pci;
     69
     70	pci = priv->pdev;
     71	cell = &priv->cells[devno];
     72	res = &priv->resources[devno * 3];
     73	pdata = &priv->pdata[devno];
     74
     75	cell->name = name;
     76	cell->resources = res;
     77	cell->num_resources = 3;
     78
     79	/* Setup the subdevice ID -- must be unique */
     80	cell->id = cmodio_id++;
     81
     82	/* Add platform data */
     83	pdata->modno = modno;
     84	cell->platform_data = pdata;
     85	cell->pdata_size = sizeof(*pdata);
     86
     87	/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
     88	res->flags = IORESOURCE_MEM;
     89	res->parent = &pci->resource[3];
     90	res->start = pci->resource[3].start + (CMODIO_MODULBUS_SIZE * modno);
     91	res->end = res->start + CMODIO_MODULBUS_SIZE - 1;
     92	res++;
     93
     94	/* PLX Control Registers -- PCI BAR4 is interrupt and other registers */
     95	res->flags = IORESOURCE_MEM;
     96	res->parent = &pci->resource[4];
     97	res->start = pci->resource[4].start;
     98	res->end = pci->resource[4].end;
     99	res++;
    100
    101	/*
    102	 * IRQ
    103	 *
    104	 * The start and end fields are used as an offset to the irq_base
    105	 * parameter passed into the mfd_add_devices() function call. All
    106	 * devices share the same IRQ.
    107	 */
    108	res->flags = IORESOURCE_IRQ;
    109	res->parent = NULL;
    110	res->start = 0;
    111	res->end = 0;
    112	res++;
    113
    114	return 0;
    115}
    116
    117/* Probe each submodule using kernel parameters */
    118static int cmodio_probe_submodules(struct cmodio_device *priv)
    119{
    120	struct pci_dev *pdev = priv->pdev;
    121	unsigned int num_probed = 0;
    122	char *name;
    123	int i;
    124
    125	for (i = 0; i < num_modules; i++) {
    126		name = modules[i];
    127		if (!strcmp(name, "") || !strcmp(name, "empty"))
    128			continue;
    129
    130		dev_dbg(&priv->pdev->dev, "MODULbus %d: name %s\n", i, name);
    131		cmodio_setup_subdevice(priv, name, num_probed, i);
    132		num_probed++;
    133	}
    134
    135	/* print an error message if no modules were probed */
    136	if (num_probed == 0) {
    137		dev_err(&priv->pdev->dev, "no MODULbus modules specified, "
    138					  "please set the ``modules'' kernel "
    139					  "parameter according to your "
    140					  "hardware configuration\n");
    141		return -ENODEV;
    142	}
    143
    144	return mfd_add_devices(&pdev->dev, 0, priv->cells,
    145			       num_probed, NULL, pdev->irq, NULL);
    146}
    147
    148/*
    149 * SYSFS Attributes
    150 */
    151
    152static ssize_t modulbus_number_show(struct device *dev,
    153				    struct device_attribute *attr, char *buf)
    154{
    155	struct cmodio_device *priv = dev_get_drvdata(dev);
    156
    157	return sysfs_emit(buf, "%x\n", priv->hex);
    158}
    159
    160static DEVICE_ATTR_RO(modulbus_number);
    161
    162static struct attribute *cmodio_sysfs_attrs[] = {
    163	&dev_attr_modulbus_number.attr,
    164	NULL,
    165};
    166
    167static const struct attribute_group cmodio_sysfs_attr_group = {
    168	.attrs = cmodio_sysfs_attrs,
    169};
    170
    171/*
    172 * PCI Driver
    173 */
    174
    175static int cmodio_pci_probe(struct pci_dev *dev,
    176				      const struct pci_device_id *id)
    177{
    178	struct cmodio_device *priv;
    179	int ret;
    180
    181	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
    182	if (!priv)
    183		return -ENOMEM;
    184
    185	pci_set_drvdata(dev, priv);
    186	priv->pdev = dev;
    187
    188	/* Hardware Initialization */
    189	ret = pci_enable_device(dev);
    190	if (ret) {
    191		dev_err(&dev->dev, "unable to enable device\n");
    192		return ret;
    193	}
    194
    195	pci_set_master(dev);
    196	ret = pci_request_regions(dev, DRV_NAME);
    197	if (ret) {
    198		dev_err(&dev->dev, "unable to request regions\n");
    199		goto out_pci_disable_device;
    200	}
    201
    202	/* Onboard configuration registers */
    203	priv->ctrl = pci_ioremap_bar(dev, 4);
    204	if (!priv->ctrl) {
    205		dev_err(&dev->dev, "unable to remap onboard regs\n");
    206		ret = -ENOMEM;
    207		goto out_pci_release_regions;
    208	}
    209
    210	/* Read the hex switch on the carrier board */
    211	priv->hex = ioread8(&priv->ctrl->int_enable);
    212
    213	/* Add the MODULbus number (hex switch value) to the device's sysfs */
    214	ret = sysfs_create_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
    215	if (ret) {
    216		dev_err(&dev->dev, "unable to create sysfs attributes\n");
    217		goto out_unmap_ctrl;
    218	}
    219
    220	/*
    221	 * Disable all interrupt lines, each submodule will enable its
    222	 * own interrupt line if needed
    223	 */
    224	iowrite8(0xf, &priv->ctrl->int_disable);
    225
    226	/* Register drivers for all submodules */
    227	ret = cmodio_probe_submodules(priv);
    228	if (ret) {
    229		dev_err(&dev->dev, "unable to probe submodules\n");
    230		goto out_sysfs_remove_group;
    231	}
    232
    233	return 0;
    234
    235out_sysfs_remove_group:
    236	sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
    237out_unmap_ctrl:
    238	iounmap(priv->ctrl);
    239out_pci_release_regions:
    240	pci_release_regions(dev);
    241out_pci_disable_device:
    242	pci_disable_device(dev);
    243
    244	return ret;
    245}
    246
    247static void cmodio_pci_remove(struct pci_dev *dev)
    248{
    249	struct cmodio_device *priv = pci_get_drvdata(dev);
    250
    251	mfd_remove_devices(&dev->dev);
    252	sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
    253	iounmap(priv->ctrl);
    254	pci_release_regions(dev);
    255	pci_disable_device(dev);
    256}
    257
    258#define PCI_VENDOR_ID_JANZ		0x13c3
    259
    260/* The list of devices that this module will support */
    261static const struct pci_device_id cmodio_pci_ids[] = {
    262	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
    263	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
    264	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0201 },
    265	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0202 },
    266	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0201 },
    267	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0202 },
    268	{ 0, }
    269};
    270MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
    271
    272static struct pci_driver cmodio_pci_driver = {
    273	.name     = DRV_NAME,
    274	.id_table = cmodio_pci_ids,
    275	.probe    = cmodio_pci_probe,
    276	.remove   = cmodio_pci_remove,
    277};
    278
    279module_pci_driver(cmodio_pci_driver);
    280
    281MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
    282MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
    283MODULE_LICENSE("GPL");