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

cs5535-mfgpt.c (10288B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Driver for the CS5535/CS5536 Multi-Function General Purpose Timers (MFGPT)
      4 *
      5 * Copyright (C) 2006, Advanced Micro Devices, Inc.
      6 * Copyright (C) 2007  Andres Salomon <dilinger@debian.org>
      7 * Copyright (C) 2009  Andres Salomon <dilinger@collabora.co.uk>
      8 *
      9 * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
     10 */
     11
     12#include <linux/kernel.h>
     13#include <linux/spinlock.h>
     14#include <linux/interrupt.h>
     15#include <linux/module.h>
     16#include <linux/platform_device.h>
     17#include <linux/cs5535.h>
     18#include <linux/slab.h>
     19
     20#define DRV_NAME "cs5535-mfgpt"
     21
     22static int mfgpt_reset_timers;
     23module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
     24MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; "
     25		"required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec "
     26		"(1 = reset the MFGPT using an undocumented bit, "
     27		"2 = perform a soft reset by unconfiguring all timers); "
     28		"use what works best for you.");
     29
     30struct cs5535_mfgpt_timer {
     31	struct cs5535_mfgpt_chip *chip;
     32	int nr;
     33};
     34
     35static struct cs5535_mfgpt_chip {
     36	DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
     37	resource_size_t base;
     38
     39	struct platform_device *pdev;
     40	spinlock_t lock;
     41	int initialized;
     42} cs5535_mfgpt_chip;
     43
     44int cs5535_mfgpt_toggle_event(struct cs5535_mfgpt_timer *timer, int cmp,
     45		int event, int enable)
     46{
     47	uint32_t msr, mask, value, dummy;
     48	int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
     49
     50	if (!timer) {
     51		WARN_ON(1);
     52		return -EIO;
     53	}
     54
     55	/*
     56	 * The register maps for these are described in sections 6.17.1.x of
     57	 * the AMD Geode CS5536 Companion Device Data Book.
     58	 */
     59	switch (event) {
     60	case MFGPT_EVENT_RESET:
     61		/*
     62		 * XXX: According to the docs, we cannot reset timers above
     63		 * 6; that is, resets for 7 and 8 will be ignored.  Is this
     64		 * a problem?   -dilinger
     65		 */
     66		msr = MSR_MFGPT_NR;
     67		mask = 1 << (timer->nr + 24);
     68		break;
     69
     70	case MFGPT_EVENT_NMI:
     71		msr = MSR_MFGPT_NR;
     72		mask = 1 << (timer->nr + shift);
     73		break;
     74
     75	case MFGPT_EVENT_IRQ:
     76		msr = MSR_MFGPT_IRQ;
     77		mask = 1 << (timer->nr + shift);
     78		break;
     79
     80	default:
     81		return -EIO;
     82	}
     83
     84	rdmsr(msr, value, dummy);
     85
     86	if (enable)
     87		value |= mask;
     88	else
     89		value &= ~mask;
     90
     91	wrmsr(msr, value, dummy);
     92	return 0;
     93}
     94EXPORT_SYMBOL_GPL(cs5535_mfgpt_toggle_event);
     95
     96int cs5535_mfgpt_set_irq(struct cs5535_mfgpt_timer *timer, int cmp, int *irq,
     97		int enable)
     98{
     99	uint32_t zsel, lpc, dummy;
    100	int shift;
    101
    102	if (!timer) {
    103		WARN_ON(1);
    104		return -EIO;
    105	}
    106
    107	/*
    108	 * Unfortunately, MFGPTs come in pairs sharing their IRQ lines. If VSA
    109	 * is using the same CMP of the timer's Siamese twin, the IRQ is set to
    110	 * 2, and we mustn't use nor change it.
    111	 * XXX: Likewise, 2 Linux drivers might clash if the 2nd overwrites the
    112	 * IRQ of the 1st. This can only happen if forcing an IRQ, calling this
    113	 * with *irq==0 is safe. Currently there _are_ no 2 drivers.
    114	 */
    115	rdmsr(MSR_PIC_ZSEL_LOW, zsel, dummy);
    116	shift = ((cmp == MFGPT_CMP1 ? 0 : 4) + timer->nr % 4) * 4;
    117	if (((zsel >> shift) & 0xF) == 2)
    118		return -EIO;
    119
    120	/* Choose IRQ: if none supplied, keep IRQ already set or use default */
    121	if (!*irq)
    122		*irq = (zsel >> shift) & 0xF;
    123	if (!*irq)
    124		*irq = CONFIG_CS5535_MFGPT_DEFAULT_IRQ;
    125
    126	/* Can't use IRQ if it's 0 (=disabled), 2, or routed to LPC */
    127	if (*irq < 1 || *irq == 2 || *irq > 15)
    128		return -EIO;
    129	rdmsr(MSR_PIC_IRQM_LPC, lpc, dummy);
    130	if (lpc & (1 << *irq))
    131		return -EIO;
    132
    133	/* All chosen and checked - go for it */
    134	if (cs5535_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
    135		return -EIO;
    136	if (enable) {
    137		zsel = (zsel & ~(0xF << shift)) | (*irq << shift);
    138		wrmsr(MSR_PIC_ZSEL_LOW, zsel, dummy);
    139	}
    140
    141	return 0;
    142}
    143EXPORT_SYMBOL_GPL(cs5535_mfgpt_set_irq);
    144
    145struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain)
    146{
    147	struct cs5535_mfgpt_chip *mfgpt = &cs5535_mfgpt_chip;
    148	struct cs5535_mfgpt_timer *timer = NULL;
    149	unsigned long flags;
    150	int max;
    151
    152	if (!mfgpt->initialized)
    153		goto done;
    154
    155	/* only allocate timers from the working domain if requested */
    156	if (domain == MFGPT_DOMAIN_WORKING)
    157		max = 6;
    158	else
    159		max = MFGPT_MAX_TIMERS;
    160
    161	if (timer_nr >= max) {
    162		/* programmer error.  silly programmers! */
    163		WARN_ON(1);
    164		goto done;
    165	}
    166
    167	spin_lock_irqsave(&mfgpt->lock, flags);
    168	if (timer_nr < 0) {
    169		unsigned long t;
    170
    171		/* try to find any available timer */
    172		t = find_first_bit(mfgpt->avail, max);
    173		/* set timer_nr to -1 if no timers available */
    174		timer_nr = t < max ? (int) t : -1;
    175	} else {
    176		/* check if the requested timer's available */
    177		if (!test_bit(timer_nr, mfgpt->avail))
    178			timer_nr = -1;
    179	}
    180
    181	if (timer_nr >= 0)
    182		/* if timer_nr is not -1, it's an available timer */
    183		__clear_bit(timer_nr, mfgpt->avail);
    184	spin_unlock_irqrestore(&mfgpt->lock, flags);
    185
    186	if (timer_nr < 0)
    187		goto done;
    188
    189	timer = kmalloc(sizeof(*timer), GFP_KERNEL);
    190	if (!timer) {
    191		/* aw hell */
    192		spin_lock_irqsave(&mfgpt->lock, flags);
    193		__set_bit(timer_nr, mfgpt->avail);
    194		spin_unlock_irqrestore(&mfgpt->lock, flags);
    195		goto done;
    196	}
    197	timer->chip = mfgpt;
    198	timer->nr = timer_nr;
    199	dev_info(&mfgpt->pdev->dev, "registered timer %d\n", timer_nr);
    200
    201done:
    202	return timer;
    203}
    204EXPORT_SYMBOL_GPL(cs5535_mfgpt_alloc_timer);
    205
    206/*
    207 * XXX: This frees the timer memory, but never resets the actual hardware
    208 * timer.  The old geode_mfgpt code did this; it would be good to figure
    209 * out a way to actually release the hardware timer.  See comments below.
    210 */
    211void cs5535_mfgpt_free_timer(struct cs5535_mfgpt_timer *timer)
    212{
    213	unsigned long flags;
    214	uint16_t val;
    215
    216	/* timer can be made available again only if never set up */
    217	val = cs5535_mfgpt_read(timer, MFGPT_REG_SETUP);
    218	if (!(val & MFGPT_SETUP_SETUP)) {
    219		spin_lock_irqsave(&timer->chip->lock, flags);
    220		__set_bit(timer->nr, timer->chip->avail);
    221		spin_unlock_irqrestore(&timer->chip->lock, flags);
    222	}
    223
    224	kfree(timer);
    225}
    226EXPORT_SYMBOL_GPL(cs5535_mfgpt_free_timer);
    227
    228uint16_t cs5535_mfgpt_read(struct cs5535_mfgpt_timer *timer, uint16_t reg)
    229{
    230	return inw(timer->chip->base + reg + (timer->nr * 8));
    231}
    232EXPORT_SYMBOL_GPL(cs5535_mfgpt_read);
    233
    234void cs5535_mfgpt_write(struct cs5535_mfgpt_timer *timer, uint16_t reg,
    235		uint16_t value)
    236{
    237	outw(value, timer->chip->base + reg + (timer->nr * 8));
    238}
    239EXPORT_SYMBOL_GPL(cs5535_mfgpt_write);
    240
    241/*
    242 * This is a sledgehammer that resets all MFGPT timers. This is required by
    243 * some broken BIOSes which leave the system in an unstable state
    244 * (TinyBIOS 0.98, for example; fixed in 0.99).  It's uncertain as to
    245 * whether or not this secret MSR can be used to release individual timers.
    246 * Jordan tells me that he and Mitch once played w/ it, but it's unclear
    247 * what the results of that were (and they experienced some instability).
    248 */
    249static void reset_all_timers(void)
    250{
    251	uint32_t val, dummy;
    252
    253	/* The following undocumented bit resets the MFGPT timers */
    254	val = 0xFF; dummy = 0;
    255	wrmsr(MSR_MFGPT_SETUP, val, dummy);
    256}
    257
    258/*
    259 * This is another sledgehammer to reset all MFGPT timers.
    260 * Instead of using the undocumented bit method it clears
    261 * IRQ, NMI and RESET settings.
    262 */
    263static void soft_reset(void)
    264{
    265	int i;
    266	struct cs5535_mfgpt_timer t;
    267
    268	for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
    269		t.nr = i;
    270
    271		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0);
    272		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0);
    273		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0);
    274		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0);
    275		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0);
    276		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0);
    277	}
    278}
    279
    280/*
    281 * Check whether any MFGPTs are available for the kernel to use.  In most
    282 * cases, firmware that uses AMD's VSA code will claim all timers during
    283 * bootup; we certainly don't want to take them if they're already in use.
    284 * In other cases (such as with VSAless OpenFirmware), the system firmware
    285 * leaves timers available for us to use.
    286 */
    287static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)
    288{
    289	struct cs5535_mfgpt_timer timer = { .chip = mfgpt };
    290	unsigned long flags;
    291	int timers = 0;
    292	uint16_t val;
    293	int i;
    294
    295	/* bios workaround */
    296	if (mfgpt_reset_timers == 1)
    297		reset_all_timers();
    298	else if (mfgpt_reset_timers == 2)
    299		soft_reset();
    300
    301	/* just to be safe, protect this section w/ lock */
    302	spin_lock_irqsave(&mfgpt->lock, flags);
    303	for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
    304		timer.nr = i;
    305		val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
    306		if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {
    307			__set_bit(i, mfgpt->avail);
    308			timers++;
    309		}
    310	}
    311	spin_unlock_irqrestore(&mfgpt->lock, flags);
    312
    313	return timers;
    314}
    315
    316static int cs5535_mfgpt_probe(struct platform_device *pdev)
    317{
    318	struct resource *res;
    319	int err = -EIO, t;
    320
    321	if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) {
    322		dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n",
    323			mfgpt_reset_timers);
    324		goto done;
    325	}
    326
    327	/* There are two ways to get the MFGPT base address; one is by
    328	 * fetching it from MSR_LBAR_MFGPT, the other is by reading the
    329	 * PCI BAR info.  The latter method is easier (especially across
    330	 * different architectures), so we'll stick with that for now.  If
    331	 * it turns out to be unreliable in the face of crappy BIOSes, we
    332	 * can always go back to using MSRs.. */
    333
    334	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
    335	if (!res) {
    336		dev_err(&pdev->dev, "can't fetch device resource info\n");
    337		goto done;
    338	}
    339
    340	if (!request_region(res->start, resource_size(res), pdev->name)) {
    341		dev_err(&pdev->dev, "can't request region\n");
    342		goto done;
    343	}
    344
    345	/* set up the driver-specific struct */
    346	cs5535_mfgpt_chip.base = res->start;
    347	cs5535_mfgpt_chip.pdev = pdev;
    348	spin_lock_init(&cs5535_mfgpt_chip.lock);
    349
    350	dev_info(&pdev->dev, "reserved resource region %pR\n", res);
    351
    352	/* detect the available timers */
    353	t = scan_timers(&cs5535_mfgpt_chip);
    354	dev_info(&pdev->dev, "%d MFGPT timers available\n", t);
    355	cs5535_mfgpt_chip.initialized = 1;
    356	return 0;
    357
    358done:
    359	return err;
    360}
    361
    362static struct platform_driver cs5535_mfgpt_driver = {
    363	.driver = {
    364		.name = DRV_NAME,
    365	},
    366	.probe = cs5535_mfgpt_probe,
    367};
    368
    369
    370static int __init cs5535_mfgpt_init(void)
    371{
    372	return platform_driver_register(&cs5535_mfgpt_driver);
    373}
    374
    375module_init(cs5535_mfgpt_init);
    376
    377MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
    378MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
    379MODULE_LICENSE("GPL");
    380MODULE_ALIAS("platform:" DRV_NAME);