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

amd_bus.c (9776B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/init.h>
      3#include <linux/pci.h>
      4#include <linux/topology.h>
      5#include <linux/cpu.h>
      6#include <linux/range.h>
      7
      8#include <asm/amd_nb.h>
      9#include <asm/pci_x86.h>
     10
     11#include <asm/pci-direct.h>
     12
     13#include "bus_numa.h"
     14
     15#define AMD_NB_F0_NODE_ID			0x60
     16#define AMD_NB_F0_UNIT_ID			0x64
     17#define AMD_NB_F1_CONFIG_MAP_REG		0xe0
     18
     19#define RANGE_NUM				16
     20#define AMD_NB_F1_CONFIG_MAP_RANGES		4
     21
     22struct amd_hostbridge {
     23	u32 bus;
     24	u32 slot;
     25	u32 device;
     26};
     27
     28/*
     29 * IMPORTANT NOTE:
     30 * hb_probes[] and early_root_info_init() is in maintenance mode.
     31 * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh .
     32 * Future processor will rely on information in ACPI.
     33 */
     34static struct amd_hostbridge hb_probes[] __initdata = {
     35	{ 0, 0x18, 0x1100 }, /* K8 */
     36	{ 0, 0x18, 0x1200 }, /* Family10h */
     37	{ 0xff, 0, 0x1200 }, /* Family10h */
     38	{ 0, 0x18, 0x1300 }, /* Family11h */
     39	{ 0, 0x18, 0x1600 }, /* Family15h */
     40};
     41
     42static struct pci_root_info __init *find_pci_root_info(int node, int link)
     43{
     44	struct pci_root_info *info;
     45
     46	/* find the position */
     47	list_for_each_entry(info, &pci_root_infos, list)
     48		if (info->node == node && info->link == link)
     49			return info;
     50
     51	return NULL;
     52}
     53
     54/**
     55 * early_root_info_init()
     56 * called before pcibios_scan_root and pci_scan_bus
     57 * fills the mp_bus_to_cpumask array based according
     58 * to the LDT Bus Number Registers found in the northbridge.
     59 */
     60static int __init early_root_info_init(void)
     61{
     62	int i;
     63	unsigned bus;
     64	unsigned slot;
     65	int node;
     66	int link;
     67	int def_node;
     68	int def_link;
     69	struct pci_root_info *info;
     70	u32 reg;
     71	u64 start;
     72	u64 end;
     73	struct range range[RANGE_NUM];
     74	u64 val;
     75	u32 address;
     76	bool found;
     77	struct resource fam10h_mmconf_res, *fam10h_mmconf;
     78	u64 fam10h_mmconf_start;
     79	u64 fam10h_mmconf_end;
     80
     81	if (!early_pci_allowed())
     82		return -1;
     83
     84	found = false;
     85	for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {
     86		u32 id;
     87		u16 device;
     88		u16 vendor;
     89
     90		bus = hb_probes[i].bus;
     91		slot = hb_probes[i].slot;
     92		id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
     93		vendor = id & 0xffff;
     94		device = (id>>16) & 0xffff;
     95
     96		if (vendor != PCI_VENDOR_ID_AMD &&
     97		    vendor != PCI_VENDOR_ID_HYGON)
     98			continue;
     99
    100		if (hb_probes[i].device == device) {
    101			found = true;
    102			break;
    103		}
    104	}
    105
    106	if (!found)
    107		return 0;
    108
    109	/*
    110	 * We should learn topology and routing information from _PXM and
    111	 * _CRS methods in the ACPI namespace.  We extract node numbers
    112	 * here to work around BIOSes that don't supply _PXM.
    113	 */
    114	for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) {
    115		int min_bus;
    116		int max_bus;
    117		reg = read_pci_config(bus, slot, 1,
    118				AMD_NB_F1_CONFIG_MAP_REG + (i << 2));
    119
    120		/* Check if that register is enabled for bus range */
    121		if ((reg & 7) != 3)
    122			continue;
    123
    124		min_bus = (reg >> 16) & 0xff;
    125		max_bus = (reg >> 24) & 0xff;
    126		node = (reg >> 4) & 0x07;
    127		link = (reg >> 8) & 0x03;
    128
    129		alloc_pci_root_info(min_bus, max_bus, node, link);
    130	}
    131
    132	/*
    133	 * The following code extracts routing information for use on old
    134	 * systems where Linux doesn't automatically use host bridge _CRS
    135	 * methods (or when the user specifies "pci=nocrs").
    136	 *
    137	 * We only do this through Fam11h, because _CRS should be enough on
    138	 * newer systems.
    139	 */
    140	if (boot_cpu_data.x86 > 0x11)
    141		return 0;
    142
    143	/* get the default node and link for left over res */
    144	reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID);
    145	def_node = (reg >> 8) & 0x07;
    146	reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID);
    147	def_link = (reg >> 8) & 0x03;
    148
    149	memset(range, 0, sizeof(range));
    150	add_range(range, RANGE_NUM, 0, 0, 0xffff + 1);
    151	/* io port resource */
    152	for (i = 0; i < 4; i++) {
    153		reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
    154		if (!(reg & 3))
    155			continue;
    156
    157		start = reg & 0xfff000;
    158		reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
    159		node = reg & 0x07;
    160		link = (reg >> 4) & 0x03;
    161		end = (reg & 0xfff000) | 0xfff;
    162
    163		info = find_pci_root_info(node, link);
    164		if (!info)
    165			continue; /* not found */
    166
    167		printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
    168		       node, link, start, end);
    169
    170		/* kernel only handle 16 bit only */
    171		if (end > 0xffff)
    172			end = 0xffff;
    173		update_res(info, start, end, IORESOURCE_IO, 1);
    174		subtract_range(range, RANGE_NUM, start, end + 1);
    175	}
    176	/* add left over io port range to def node/link, [0, 0xffff] */
    177	/* find the position */
    178	info = find_pci_root_info(def_node, def_link);
    179	if (info) {
    180		for (i = 0; i < RANGE_NUM; i++) {
    181			if (!range[i].end)
    182				continue;
    183
    184			update_res(info, range[i].start, range[i].end - 1,
    185				   IORESOURCE_IO, 1);
    186		}
    187	}
    188
    189	memset(range, 0, sizeof(range));
    190	/* 0xfd00000000-0xffffffffff for HT */
    191	end = cap_resource((0xfdULL<<32) - 1);
    192	end++;
    193	add_range(range, RANGE_NUM, 0, 0, end);
    194
    195	/* need to take out [0, TOM) for RAM*/
    196	address = MSR_K8_TOP_MEM1;
    197	rdmsrl(address, val);
    198	end = (val & 0xffffff800000ULL);
    199	printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20);
    200	if (end < (1ULL<<32))
    201		subtract_range(range, RANGE_NUM, 0, end);
    202
    203	/* get mmconfig */
    204	fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res);
    205	/* need to take out mmconf range */
    206	if (fam10h_mmconf) {
    207		printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
    208		fam10h_mmconf_start = fam10h_mmconf->start;
    209		fam10h_mmconf_end = fam10h_mmconf->end;
    210		subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
    211				 fam10h_mmconf_end + 1);
    212	} else {
    213		fam10h_mmconf_start = 0;
    214		fam10h_mmconf_end = 0;
    215	}
    216
    217	/* mmio resource */
    218	for (i = 0; i < 8; i++) {
    219		reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
    220		if (!(reg & 3))
    221			continue;
    222
    223		start = reg & 0xffffff00; /* 39:16 on 31:8*/
    224		start <<= 8;
    225		reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
    226		node = reg & 0x07;
    227		link = (reg >> 4) & 0x03;
    228		end = (reg & 0xffffff00);
    229		end <<= 8;
    230		end |= 0xffff;
    231
    232		info = find_pci_root_info(node, link);
    233
    234		if (!info)
    235			continue;
    236
    237		printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
    238		       node, link, start, end);
    239		/*
    240		 * some sick allocation would have range overlap with fam10h
    241		 * mmconf range, so need to update start and end.
    242		 */
    243		if (fam10h_mmconf_end) {
    244			int changed = 0;
    245			u64 endx = 0;
    246			if (start >= fam10h_mmconf_start &&
    247			    start <= fam10h_mmconf_end) {
    248				start = fam10h_mmconf_end + 1;
    249				changed = 1;
    250			}
    251
    252			if (end >= fam10h_mmconf_start &&
    253			    end <= fam10h_mmconf_end) {
    254				end = fam10h_mmconf_start - 1;
    255				changed = 1;
    256			}
    257
    258			if (start < fam10h_mmconf_start &&
    259			    end > fam10h_mmconf_end) {
    260				/* we got a hole */
    261				endx = fam10h_mmconf_start - 1;
    262				update_res(info, start, endx, IORESOURCE_MEM, 0);
    263				subtract_range(range, RANGE_NUM, start,
    264						 endx + 1);
    265				printk(KERN_CONT " ==> [%llx, %llx]", start, endx);
    266				start = fam10h_mmconf_end + 1;
    267				changed = 1;
    268			}
    269			if (changed) {
    270				if (start <= end) {
    271					printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end);
    272				} else {
    273					printk(KERN_CONT "%s\n", endx?"":" ==> none");
    274					continue;
    275				}
    276			}
    277		}
    278
    279		update_res(info, cap_resource(start), cap_resource(end),
    280				 IORESOURCE_MEM, 1);
    281		subtract_range(range, RANGE_NUM, start, end + 1);
    282		printk(KERN_CONT "\n");
    283	}
    284
    285	/* need to take out [4G, TOM2) for RAM*/
    286	/* SYS_CFG */
    287	address = MSR_AMD64_SYSCFG;
    288	rdmsrl(address, val);
    289	/* TOP_MEM2 is enabled? */
    290	if (val & (1<<21)) {
    291		/* TOP_MEM2 */
    292		address = MSR_K8_TOP_MEM2;
    293		rdmsrl(address, val);
    294		end = (val & 0xffffff800000ULL);
    295		printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20);
    296		subtract_range(range, RANGE_NUM, 1ULL<<32, end);
    297	}
    298
    299	/*
    300	 * add left over mmio range to def node/link ?
    301	 * that is tricky, just record range in from start_min to 4G
    302	 */
    303	info = find_pci_root_info(def_node, def_link);
    304	if (info) {
    305		for (i = 0; i < RANGE_NUM; i++) {
    306			if (!range[i].end)
    307				continue;
    308
    309			update_res(info, cap_resource(range[i].start),
    310				   cap_resource(range[i].end - 1),
    311				   IORESOURCE_MEM, 1);
    312		}
    313	}
    314
    315	list_for_each_entry(info, &pci_root_infos, list) {
    316		int busnum;
    317		struct pci_root_res *root_res;
    318
    319		busnum = info->busn.start;
    320		printk(KERN_DEBUG "bus: %pR on node %x link %x\n",
    321		       &info->busn, info->node, info->link);
    322		list_for_each_entry(root_res, &info->resources, list)
    323			printk(KERN_DEBUG "bus: %02x %pR\n",
    324				       busnum, &root_res->res);
    325	}
    326
    327	return 0;
    328}
    329
    330#define ENABLE_CF8_EXT_CFG      (1ULL << 46)
    331
    332static int amd_bus_cpu_online(unsigned int cpu)
    333{
    334	u64 reg;
    335
    336	rdmsrl(MSR_AMD64_NB_CFG, reg);
    337	if (!(reg & ENABLE_CF8_EXT_CFG)) {
    338		reg |= ENABLE_CF8_EXT_CFG;
    339		wrmsrl(MSR_AMD64_NB_CFG, reg);
    340	}
    341	return 0;
    342}
    343
    344static void __init pci_enable_pci_io_ecs(void)
    345{
    346#ifdef CONFIG_AMD_NB
    347	unsigned int i, n;
    348
    349	for (n = i = 0; !n && amd_nb_bus_dev_ranges[i].dev_limit; ++i) {
    350		u8 bus = amd_nb_bus_dev_ranges[i].bus;
    351		u8 slot = amd_nb_bus_dev_ranges[i].dev_base;
    352		u8 limit = amd_nb_bus_dev_ranges[i].dev_limit;
    353
    354		for (; slot < limit; ++slot) {
    355			u32 val = read_pci_config(bus, slot, 3, 0);
    356
    357			if (!early_is_amd_nb(val))
    358				continue;
    359
    360			val = read_pci_config(bus, slot, 3, 0x8c);
    361			if (!(val & (ENABLE_CF8_EXT_CFG >> 32))) {
    362				val |= ENABLE_CF8_EXT_CFG >> 32;
    363				write_pci_config(bus, slot, 3, 0x8c, val);
    364			}
    365			++n;
    366		}
    367	}
    368#endif
    369}
    370
    371static int __init pci_io_ecs_init(void)
    372{
    373	int ret;
    374
    375	/* assume all cpus from fam10h have IO ECS */
    376	if (boot_cpu_data.x86 < 0x10)
    377		return 0;
    378
    379	/* Try the PCI method first. */
    380	if (early_pci_allowed())
    381		pci_enable_pci_io_ecs();
    382
    383	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "pci/amd_bus:online",
    384				amd_bus_cpu_online, NULL);
    385	WARN_ON(ret < 0);
    386
    387	pci_probe |= PCI_HAS_IO_ECS;
    388
    389	return 0;
    390}
    391
    392static int __init amd_postcore_init(void)
    393{
    394	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
    395	    boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
    396		return 0;
    397
    398	early_root_info_init();
    399	pci_io_ecs_init();
    400
    401	return 0;
    402}
    403
    404postcore_initcall(amd_postcore_init);