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

mcb-parse.c (5277B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/types.h>
      3#include <linux/ioport.h>
      4#include <linux/slab.h>
      5#include <linux/export.h>
      6#include <linux/io.h>
      7#include <linux/mcb.h>
      8
      9#include "mcb-internal.h"
     10
     11struct mcb_parse_priv {
     12	phys_addr_t mapbase;
     13	void __iomem *base;
     14};
     15
     16#define for_each_chameleon_cell(dtype, p)	\
     17	for ((dtype) = get_next_dtype((p));	\
     18	     (dtype) != CHAMELEON_DTYPE_END;	\
     19	     (dtype) = get_next_dtype((p)))
     20
     21static inline uint32_t get_next_dtype(void __iomem *p)
     22{
     23	uint32_t dtype;
     24
     25	dtype = readl(p);
     26	return dtype >> 28;
     27}
     28
     29static int chameleon_parse_bdd(struct mcb_bus *bus,
     30			struct chameleon_bar *cb,
     31			void __iomem *base)
     32{
     33	return 0;
     34}
     35
     36static int chameleon_parse_gdd(struct mcb_bus *bus,
     37			struct chameleon_bar *cb,
     38			void __iomem *base, int bar_count)
     39{
     40	struct chameleon_gdd __iomem *gdd =
     41		(struct chameleon_gdd __iomem *) base;
     42	struct mcb_device *mdev;
     43	u32 dev_mapbase;
     44	u32 offset;
     45	u32 size;
     46	int ret;
     47	__le32 reg1;
     48	__le32 reg2;
     49
     50	mdev = mcb_alloc_dev(bus);
     51	if (!mdev)
     52		return -ENOMEM;
     53
     54	reg1 = readl(&gdd->reg1);
     55	reg2 = readl(&gdd->reg2);
     56	offset = readl(&gdd->offset);
     57	size = readl(&gdd->size);
     58
     59	mdev->id = GDD_DEV(reg1);
     60	mdev->rev = GDD_REV(reg1);
     61	mdev->var = GDD_VAR(reg1);
     62	mdev->bar = GDD_BAR(reg2);
     63	mdev->group = GDD_GRP(reg2);
     64	mdev->inst = GDD_INS(reg2);
     65
     66	/*
     67	 * If the BAR is missing, dev_mapbase is zero, or if the
     68	 * device is IO mapped we just print a warning and go on with the
     69	 * next device, instead of completely stop the gdd parser
     70	 */
     71	if (mdev->bar > bar_count - 1) {
     72		pr_info("No BAR for 16z%03d\n", mdev->id);
     73		ret = 0;
     74		goto err;
     75	}
     76
     77	dev_mapbase = cb[mdev->bar].addr;
     78	if (!dev_mapbase) {
     79		pr_info("BAR not assigned for 16z%03d\n", mdev->id);
     80		ret = 0;
     81		goto err;
     82	}
     83
     84	if (dev_mapbase & 0x01) {
     85		pr_info("IO mapped Device (16z%03d) not yet supported\n",
     86			mdev->id);
     87		ret = 0;
     88		goto err;
     89	}
     90
     91	pr_debug("Found a 16z%03d\n", mdev->id);
     92
     93	mdev->irq.start = GDD_IRQ(reg1);
     94	mdev->irq.end = GDD_IRQ(reg1);
     95	mdev->irq.flags = IORESOURCE_IRQ;
     96
     97	mdev->mem.start = dev_mapbase + offset;
     98
     99	mdev->mem.end = mdev->mem.start + size - 1;
    100	mdev->mem.flags = IORESOURCE_MEM;
    101
    102	mdev->is_added = false;
    103
    104	ret = mcb_device_register(bus, mdev);
    105	if (ret < 0)
    106		goto err;
    107
    108	return 0;
    109
    110err:
    111	mcb_free_dev(mdev);
    112
    113	return ret;
    114}
    115
    116static void chameleon_parse_bar(void __iomem *base,
    117				struct chameleon_bar *cb, int bar_count)
    118{
    119	char __iomem *p = base;
    120	int i;
    121
    122	/* skip reg1 */
    123	p += sizeof(__le32);
    124
    125	for (i = 0; i < bar_count; i++) {
    126		cb[i].addr = readl(p);
    127		cb[i].size = readl(p + 4);
    128
    129		p += sizeof(struct chameleon_bar);
    130	}
    131}
    132
    133static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
    134			     struct chameleon_bar **cb)
    135{
    136	struct chameleon_bar *c;
    137	int bar_count;
    138	__le32 reg;
    139	u32 dtype;
    140
    141	/*
    142	 * For those devices which are not connected
    143	 * to the PCI Bus (e.g. LPC) there is a bar
    144	 * descriptor located directly after the
    145	 * chameleon header. This header is comparable
    146	 * to a PCI header.
    147	 */
    148	dtype = get_next_dtype(*base);
    149	if (dtype == CHAMELEON_DTYPE_BAR) {
    150		reg = readl(*base);
    151
    152		bar_count = BAR_CNT(reg);
    153		if (bar_count <= 0 || bar_count > CHAMELEON_BAR_MAX)
    154			return -ENODEV;
    155
    156		c = kcalloc(bar_count, sizeof(struct chameleon_bar),
    157			    GFP_KERNEL);
    158		if (!c)
    159			return -ENOMEM;
    160
    161		chameleon_parse_bar(*base, c, bar_count);
    162		*base += BAR_DESC_SIZE(bar_count);
    163	} else {
    164		c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL);
    165		if (!c)
    166			return -ENOMEM;
    167
    168		bar_count = 1;
    169		c->addr = mapbase;
    170	}
    171
    172	*cb = c;
    173
    174	return bar_count;
    175}
    176
    177int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
    178			void __iomem *base)
    179{
    180	struct chameleon_fpga_header *header;
    181	struct chameleon_bar *cb;
    182	char __iomem *p = base;
    183	int num_cells = 0;
    184	uint32_t dtype;
    185	int bar_count;
    186	int ret;
    187	u32 hsize;
    188
    189	hsize = sizeof(struct chameleon_fpga_header);
    190
    191	header = kzalloc(hsize, GFP_KERNEL);
    192	if (!header)
    193		return -ENOMEM;
    194
    195	/* Extract header information */
    196	memcpy_fromio(header, p, hsize);
    197	/* We only support chameleon v2 at the moment */
    198	header->magic = le16_to_cpu(header->magic);
    199	if (header->magic != CHAMELEONV2_MAGIC) {
    200		pr_err("Unsupported chameleon version 0x%x\n",
    201				header->magic);
    202		ret = -ENODEV;
    203		goto free_header;
    204	}
    205	p += hsize;
    206
    207	bus->revision = header->revision;
    208	bus->model = header->model;
    209	bus->minor = header->minor;
    210	snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s",
    211		 header->filename);
    212
    213	bar_count = chameleon_get_bar(&p, mapbase, &cb);
    214	if (bar_count < 0) {
    215		ret = bar_count;
    216		goto free_header;
    217	}
    218
    219	for_each_chameleon_cell(dtype, p) {
    220		switch (dtype) {
    221		case CHAMELEON_DTYPE_GENERAL:
    222			ret = chameleon_parse_gdd(bus, cb, p, bar_count);
    223			if (ret < 0)
    224				goto free_bar;
    225			p += sizeof(struct chameleon_gdd);
    226			break;
    227		case CHAMELEON_DTYPE_BRIDGE:
    228			chameleon_parse_bdd(bus, cb, p);
    229			p += sizeof(struct chameleon_bdd);
    230			break;
    231		case CHAMELEON_DTYPE_END:
    232			break;
    233		default:
    234			pr_err("Invalid chameleon descriptor type 0x%x\n",
    235				dtype);
    236			ret = -EINVAL;
    237			goto free_bar;
    238		}
    239		num_cells++;
    240	}
    241
    242	if (num_cells == 0)
    243		num_cells = -EINVAL;
    244
    245	kfree(cb);
    246	kfree(header);
    247	return num_cells;
    248
    249free_bar:
    250	kfree(cb);
    251free_header:
    252	kfree(header);
    253
    254	return ret;
    255}
    256EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells, MCB);