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

io_delay.c (3491B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * I/O delay strategies for inb_p/outb_p
      4 *
      5 * Allow for a DMI based override of port 0x80, needed for certain HP laptops
      6 * and possibly other systems. Also allow for the gradual elimination of
      7 * outb_p/inb_p API uses.
      8 */
      9#include <linux/kernel.h>
     10#include <linux/export.h>
     11#include <linux/delay.h>
     12#include <linux/init.h>
     13#include <linux/dmi.h>
     14#include <linux/io.h>
     15
     16#define IO_DELAY_TYPE_0X80	0
     17#define IO_DELAY_TYPE_0XED	1
     18#define IO_DELAY_TYPE_UDELAY	2
     19#define IO_DELAY_TYPE_NONE	3
     20
     21#if defined(CONFIG_IO_DELAY_0X80)
     22#define DEFAULT_IO_DELAY_TYPE	IO_DELAY_TYPE_0X80
     23#elif defined(CONFIG_IO_DELAY_0XED)
     24#define DEFAULT_IO_DELAY_TYPE	IO_DELAY_TYPE_0XED
     25#elif defined(CONFIG_IO_DELAY_UDELAY)
     26#define DEFAULT_IO_DELAY_TYPE	IO_DELAY_TYPE_UDELAY
     27#elif defined(CONFIG_IO_DELAY_NONE)
     28#define DEFAULT_IO_DELAY_TYPE	IO_DELAY_TYPE_NONE
     29#endif
     30
     31int io_delay_type __read_mostly = DEFAULT_IO_DELAY_TYPE;
     32
     33static int __initdata io_delay_override;
     34
     35/*
     36 * Paravirt wants native_io_delay to be a constant.
     37 */
     38void native_io_delay(void)
     39{
     40	switch (io_delay_type) {
     41	default:
     42	case IO_DELAY_TYPE_0X80:
     43		asm volatile ("outb %al, $0x80");
     44		break;
     45	case IO_DELAY_TYPE_0XED:
     46		asm volatile ("outb %al, $0xed");
     47		break;
     48	case IO_DELAY_TYPE_UDELAY:
     49		/*
     50		 * 2 usecs is an upper-bound for the outb delay but
     51		 * note that udelay doesn't have the bus-level
     52		 * side-effects that outb does, nor does udelay() have
     53		 * precise timings during very early bootup (the delays
     54		 * are shorter until calibrated):
     55		 */
     56		udelay(2);
     57		break;
     58	case IO_DELAY_TYPE_NONE:
     59		break;
     60	}
     61}
     62EXPORT_SYMBOL(native_io_delay);
     63
     64static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
     65{
     66	if (io_delay_type == IO_DELAY_TYPE_0X80) {
     67		pr_notice("%s: using 0xed I/O delay port\n", id->ident);
     68		io_delay_type = IO_DELAY_TYPE_0XED;
     69	}
     70
     71	return 0;
     72}
     73
     74/*
     75 * Quirk table for systems that misbehave (lock up, etc.) if port
     76 * 0x80 is used:
     77 */
     78static const struct dmi_system_id io_delay_0xed_port_dmi_table[] __initconst = {
     79	{
     80		.callback	= dmi_io_delay_0xed_port,
     81		.ident		= "Compaq Presario V6000",
     82		.matches	= {
     83			DMI_MATCH(DMI_BOARD_VENDOR,	"Quanta"),
     84			DMI_MATCH(DMI_BOARD_NAME,	"30B7")
     85		}
     86	},
     87	{
     88		.callback	= dmi_io_delay_0xed_port,
     89		.ident		= "HP Pavilion dv9000z",
     90		.matches	= {
     91			DMI_MATCH(DMI_BOARD_VENDOR,	"Quanta"),
     92			DMI_MATCH(DMI_BOARD_NAME,	"30B9")
     93		}
     94	},
     95	{
     96		.callback	= dmi_io_delay_0xed_port,
     97		.ident		= "HP Pavilion dv6000",
     98		.matches	= {
     99			DMI_MATCH(DMI_BOARD_VENDOR,	"Quanta"),
    100			DMI_MATCH(DMI_BOARD_NAME,	"30B8")
    101		}
    102	},
    103	{
    104		.callback	= dmi_io_delay_0xed_port,
    105		.ident		= "HP Pavilion tx1000",
    106		.matches	= {
    107			DMI_MATCH(DMI_BOARD_VENDOR,	"Quanta"),
    108			DMI_MATCH(DMI_BOARD_NAME,	"30BF")
    109		}
    110	},
    111	{
    112		.callback	= dmi_io_delay_0xed_port,
    113		.ident		= "Presario F700",
    114		.matches	= {
    115			DMI_MATCH(DMI_BOARD_VENDOR,	"Quanta"),
    116			DMI_MATCH(DMI_BOARD_NAME,	"30D3")
    117		}
    118	},
    119	{ }
    120};
    121
    122void __init io_delay_init(void)
    123{
    124	if (!io_delay_override)
    125		dmi_check_system(io_delay_0xed_port_dmi_table);
    126}
    127
    128static int __init io_delay_param(char *s)
    129{
    130	if (!s)
    131		return -EINVAL;
    132
    133	if (!strcmp(s, "0x80"))
    134		io_delay_type = IO_DELAY_TYPE_0X80;
    135	else if (!strcmp(s, "0xed"))
    136		io_delay_type = IO_DELAY_TYPE_0XED;
    137	else if (!strcmp(s, "udelay"))
    138		io_delay_type = IO_DELAY_TYPE_UDELAY;
    139	else if (!strcmp(s, "none"))
    140		io_delay_type = IO_DELAY_TYPE_NONE;
    141	else
    142		return -EINVAL;
    143
    144	io_delay_override = 1;
    145	return 0;
    146}
    147
    148early_param("io_delay", io_delay_param);