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

ip22-gio.c (9732B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/export.h>
      3#include <linux/kernel.h>
      4#include <linux/init.h>
      5#include <linux/slab.h>
      6
      7#include <asm/addrspace.h>
      8#include <asm/paccess.h>
      9#include <asm/gio_device.h>
     10#include <asm/sgi/gio.h>
     11#include <asm/sgi/hpc3.h>
     12#include <asm/sgi/mc.h>
     13#include <asm/sgi/ip22.h>
     14
     15static struct bus_type gio_bus_type;
     16
     17static struct {
     18	const char *name;
     19	__u8	   id;
     20} gio_name_table[] = {
     21	{ .name = "SGI Impact", .id = 0x10 },
     22	{ .name = "Phobos G160", .id = 0x35 },
     23	{ .name = "Phobos G130", .id = 0x36 },
     24	{ .name = "Phobos G100", .id = 0x37 },
     25	{ .name = "Set Engineering GFE", .id = 0x38 },
     26	/* fake IDs */
     27	{ .name = "SGI Newport", .id = 0x7e },
     28	{ .name = "SGI GR2/GR3", .id = 0x7f },
     29};
     30
     31static void gio_bus_release(struct device *dev)
     32{
     33	kfree(dev);
     34}
     35
     36static struct device gio_bus = {
     37	.init_name = "gio",
     38	.release = &gio_bus_release,
     39};
     40
     41/**
     42 * gio_match_device - Tell if an of_device structure has a matching
     43 * gio_match structure
     44 * @ids: array of of device match structures to search in
     45 * @dev: the of device structure to match against
     46 *
     47 * Used by a driver to check whether an of_device present in the
     48 * system is in its list of supported devices.
     49 */
     50static const struct gio_device_id *
     51gio_match_device(const struct gio_device_id *match,
     52		 const struct gio_device *dev)
     53{
     54	const struct gio_device_id *ids;
     55
     56	for (ids = match; ids->id != 0xff; ids++)
     57		if (ids->id == dev->id.id)
     58			return ids;
     59
     60	return NULL;
     61}
     62
     63struct gio_device *gio_dev_get(struct gio_device *dev)
     64{
     65	struct device *tmp;
     66
     67	if (!dev)
     68		return NULL;
     69	tmp = get_device(&dev->dev);
     70	if (tmp)
     71		return to_gio_device(tmp);
     72	else
     73		return NULL;
     74}
     75EXPORT_SYMBOL_GPL(gio_dev_get);
     76
     77void gio_dev_put(struct gio_device *dev)
     78{
     79	if (dev)
     80		put_device(&dev->dev);
     81}
     82EXPORT_SYMBOL_GPL(gio_dev_put);
     83
     84/**
     85 * gio_release_dev - free an gio device structure when all users of it are finished.
     86 * @dev: device that's been disconnected
     87 *
     88 * Will be called only by the device core when all users of this gio device are
     89 * done.
     90 */
     91void gio_release_dev(struct device *dev)
     92{
     93	struct gio_device *giodev;
     94
     95	giodev = to_gio_device(dev);
     96	kfree(giodev);
     97}
     98EXPORT_SYMBOL_GPL(gio_release_dev);
     99
    100int gio_device_register(struct gio_device *giodev)
    101{
    102	giodev->dev.bus = &gio_bus_type;
    103	giodev->dev.parent = &gio_bus;
    104	return device_register(&giodev->dev);
    105}
    106EXPORT_SYMBOL_GPL(gio_device_register);
    107
    108void gio_device_unregister(struct gio_device *giodev)
    109{
    110	device_unregister(&giodev->dev);
    111}
    112EXPORT_SYMBOL_GPL(gio_device_unregister);
    113
    114static int gio_bus_match(struct device *dev, struct device_driver *drv)
    115{
    116	struct gio_device *gio_dev = to_gio_device(dev);
    117	struct gio_driver *gio_drv = to_gio_driver(drv);
    118
    119	return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
    120}
    121
    122static int gio_device_probe(struct device *dev)
    123{
    124	int error = -ENODEV;
    125	struct gio_driver *drv;
    126	struct gio_device *gio_dev;
    127	const struct gio_device_id *match;
    128
    129	drv = to_gio_driver(dev->driver);
    130	gio_dev = to_gio_device(dev);
    131
    132	if (!drv->probe)
    133		return error;
    134
    135	gio_dev_get(gio_dev);
    136
    137	match = gio_match_device(drv->id_table, gio_dev);
    138	if (match)
    139		error = drv->probe(gio_dev, match);
    140	if (error)
    141		gio_dev_put(gio_dev);
    142
    143	return error;
    144}
    145
    146static void gio_device_remove(struct device *dev)
    147{
    148	struct gio_device *gio_dev = to_gio_device(dev);
    149	struct gio_driver *drv = to_gio_driver(dev->driver);
    150
    151	if (dev->driver && drv->remove)
    152		drv->remove(gio_dev);
    153}
    154
    155static void gio_device_shutdown(struct device *dev)
    156{
    157	struct gio_device *gio_dev = to_gio_device(dev);
    158	struct gio_driver *drv = to_gio_driver(dev->driver);
    159
    160	if (dev->driver && drv->shutdown)
    161		drv->shutdown(gio_dev);
    162}
    163
    164static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
    165			     char *buf)
    166{
    167	struct gio_device *gio_dev = to_gio_device(dev);
    168	int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
    169
    170	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
    171}
    172static DEVICE_ATTR_RO(modalias);
    173
    174static ssize_t name_show(struct device *dev,
    175			 struct device_attribute *attr, char *buf)
    176{
    177	struct gio_device *giodev;
    178
    179	giodev = to_gio_device(dev);
    180	return sprintf(buf, "%s", giodev->name);
    181}
    182static DEVICE_ATTR_RO(name);
    183
    184static ssize_t id_show(struct device *dev,
    185		       struct device_attribute *attr, char *buf)
    186{
    187	struct gio_device *giodev;
    188
    189	giodev = to_gio_device(dev);
    190	return sprintf(buf, "%x", giodev->id.id);
    191}
    192static DEVICE_ATTR_RO(id);
    193
    194static struct attribute *gio_dev_attrs[] = {
    195	&dev_attr_modalias.attr,
    196	&dev_attr_name.attr,
    197	&dev_attr_id.attr,
    198	NULL,
    199};
    200ATTRIBUTE_GROUPS(gio_dev);
    201
    202static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
    203{
    204	struct gio_device *gio_dev = to_gio_device(dev);
    205
    206	add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
    207	return 0;
    208}
    209
    210int gio_register_driver(struct gio_driver *drv)
    211{
    212	/* initialize common driver fields */
    213	if (!drv->driver.name)
    214		drv->driver.name = drv->name;
    215	if (!drv->driver.owner)
    216		drv->driver.owner = drv->owner;
    217	drv->driver.bus = &gio_bus_type;
    218
    219	/* register with core */
    220	return driver_register(&drv->driver);
    221}
    222EXPORT_SYMBOL_GPL(gio_register_driver);
    223
    224void gio_unregister_driver(struct gio_driver *drv)
    225{
    226	driver_unregister(&drv->driver);
    227}
    228EXPORT_SYMBOL_GPL(gio_unregister_driver);
    229
    230void gio_set_master(struct gio_device *dev)
    231{
    232	u32 tmp = sgimc->giopar;
    233
    234	switch (dev->slotno) {
    235	case 0:
    236		tmp |= SGIMC_GIOPAR_MASTERGFX;
    237		break;
    238	case 1:
    239		tmp |= SGIMC_GIOPAR_MASTEREXP0;
    240		break;
    241	case 2:
    242		tmp |= SGIMC_GIOPAR_MASTEREXP1;
    243		break;
    244	}
    245	sgimc->giopar = tmp;
    246}
    247EXPORT_SYMBOL_GPL(gio_set_master);
    248
    249void ip22_gio_set_64bit(int slotno)
    250{
    251	u32 tmp = sgimc->giopar;
    252
    253	switch (slotno) {
    254	case 0:
    255		tmp |= SGIMC_GIOPAR_GFX64;
    256		break;
    257	case 1:
    258		tmp |= SGIMC_GIOPAR_EXP064;
    259		break;
    260	case 2:
    261		tmp |= SGIMC_GIOPAR_EXP164;
    262		break;
    263	}
    264	sgimc->giopar = tmp;
    265}
    266
    267static int ip22_gio_id(unsigned long addr, u32 *res)
    268{
    269	u8 tmp8;
    270	u8 tmp16;
    271	u32 tmp32;
    272	u8 *ptr8;
    273	u16 *ptr16;
    274	u32 *ptr32;
    275
    276	ptr32 = (void *)CKSEG1ADDR(addr);
    277	if (!get_dbe(tmp32, ptr32)) {
    278		/*
    279		 * We got no DBE, but this doesn't mean anything.
    280		 * If GIO is pipelined (which can't be disabled
    281		 * for GFX slot) we don't get a DBE, but we see
    282		 * the transfer size as data. So we do an 8bit
    283		 * and a 16bit access and check whether the common
    284		 * data matches
    285		 */
    286		ptr8 = (void *)CKSEG1ADDR(addr + 3);
    287		if (get_dbe(tmp8, ptr8)) {
    288			/*
    289			 * 32bit access worked, but 8bit doesn't
    290			 * so we don't see phantom reads on
    291			 * a pipelined bus, but a real card which
    292			 * doesn't support 8 bit reads
    293			 */
    294			*res = tmp32;
    295			return 1;
    296		}
    297		ptr16 = (void *)CKSEG1ADDR(addr + 2);
    298		get_dbe(tmp16, ptr16);
    299		if (tmp8 == (tmp16 & 0xff) &&
    300		    tmp8 == (tmp32 & 0xff) &&
    301		    tmp16 == (tmp32 & 0xffff)) {
    302			*res = tmp32;
    303			return 1;
    304		}
    305	}
    306	return 0; /* nothing here */
    307}
    308
    309#define HQ2_MYSTERY_OFFS       0x6A07C
    310#define NEWPORT_USTATUS_OFFS   0xF133C
    311
    312static int ip22_is_gr2(unsigned long addr)
    313{
    314	u32 tmp;
    315	u32 *ptr;
    316
    317	/* HQ2 only allows 32bit accesses */
    318	ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
    319	if (!get_dbe(tmp, ptr)) {
    320		if (tmp == 0xdeadbeef)
    321			return 1;
    322	}
    323	return 0;
    324}
    325
    326
    327static void ip22_check_gio(int slotno, unsigned long addr, int irq)
    328{
    329	const char *name = "Unknown";
    330	struct gio_device *gio_dev;
    331	u32 tmp;
    332	__u8 id;
    333	int i;
    334
    335	/* first look for GR2/GR3 by checking mystery register */
    336	if (ip22_is_gr2(addr))
    337		tmp = 0x7f;
    338	else {
    339		if (!ip22_gio_id(addr, &tmp)) {
    340			/*
    341			 * no GIO signature at start address of slot
    342			 * since Newport doesn't have one, we check if
    343			 * user status register is readable
    344			 */
    345			if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
    346				tmp = 0x7e;
    347			else
    348				tmp = 0;
    349		}
    350	}
    351	if (tmp) {
    352		id = GIO_ID(tmp);
    353		if (tmp & GIO_32BIT_ID) {
    354			if (tmp & GIO_64BIT_IFACE)
    355				ip22_gio_set_64bit(slotno);
    356		}
    357		for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
    358			if (id == gio_name_table[i].id) {
    359				name = gio_name_table[i].name;
    360				break;
    361			}
    362		}
    363		printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
    364		       slotno, name, id);
    365		gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
    366		if (!gio_dev)
    367			return;
    368		gio_dev->name = name;
    369		gio_dev->slotno = slotno;
    370		gio_dev->id.id = id;
    371		gio_dev->resource.start = addr;
    372		gio_dev->resource.end = addr + 0x3fffff;
    373		gio_dev->resource.flags = IORESOURCE_MEM;
    374		gio_dev->irq = irq;
    375		dev_set_name(&gio_dev->dev, "%d", slotno);
    376		gio_device_register(gio_dev);
    377	} else
    378		printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
    379}
    380
    381static struct bus_type gio_bus_type = {
    382	.name	   = "gio",
    383	.dev_groups = gio_dev_groups,
    384	.match	   = gio_bus_match,
    385	.probe	   = gio_device_probe,
    386	.remove	   = gio_device_remove,
    387	.shutdown  = gio_device_shutdown,
    388	.uevent	   = gio_device_uevent,
    389};
    390
    391static struct resource gio_bus_resource = {
    392	.start = GIO_SLOT_GFX_BASE,
    393	.end   = GIO_SLOT_GFX_BASE + 0x9fffff,
    394	.name  = "GIO Bus",
    395	.flags = IORESOURCE_MEM,
    396};
    397
    398int __init ip22_gio_init(void)
    399{
    400	unsigned int pbdma __maybe_unused;
    401	int ret;
    402
    403	ret = device_register(&gio_bus);
    404	if (ret) {
    405		put_device(&gio_bus);
    406		return ret;
    407	}
    408
    409	ret = bus_register(&gio_bus_type);
    410	if (!ret) {
    411		request_resource(&iomem_resource, &gio_bus_resource);
    412		printk(KERN_INFO "GIO: Probing bus...\n");
    413
    414		if (ip22_is_fullhouse()) {
    415			/* Indigo2 */
    416			ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ);
    417			ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ);
    418		} else {
    419			/* Indy/Challenge S */
    420			if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
    421				ip22_check_gio(0, GIO_SLOT_GFX_BASE,
    422					       SGI_GIO_0_IRQ);
    423			ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ);
    424			ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ);
    425		}
    426	} else
    427		device_unregister(&gio_bus);
    428
    429	return ret;
    430}
    431
    432subsys_initcall(ip22_gio_init);