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

mmconfig_32.c (3450B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
      4 * Copyright (C) 2004 Intel Corp.
      5 */
      6
      7/*
      8 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
      9 */
     10
     11#include <linux/pci.h>
     12#include <linux/init.h>
     13#include <linux/rcupdate.h>
     14#include <asm/e820/api.h>
     15#include <asm/pci_x86.h>
     16
     17/* Assume systems with more busses have correct MCFG */
     18#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
     19
     20/* The base address of the last MMCONFIG device accessed */
     21static u32 mmcfg_last_accessed_device;
     22static int mmcfg_last_accessed_cpu;
     23
     24/*
     25 * Functions for accessing PCI configuration space with MMCONFIG accesses
     26 */
     27static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
     28{
     29	struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
     30
     31	if (cfg)
     32		return cfg->address;
     33	return 0;
     34}
     35
     36/*
     37 * This is always called under pci_config_lock
     38 */
     39static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
     40{
     41	u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12);
     42	int cpu = smp_processor_id();
     43	if (dev_base != mmcfg_last_accessed_device ||
     44	    cpu != mmcfg_last_accessed_cpu) {
     45		mmcfg_last_accessed_device = dev_base;
     46		mmcfg_last_accessed_cpu = cpu;
     47		set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
     48	}
     49}
     50
     51static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
     52			  unsigned int devfn, int reg, int len, u32 *value)
     53{
     54	unsigned long flags;
     55	u32 base;
     56
     57	if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
     58err:		*value = -1;
     59		return -EINVAL;
     60	}
     61
     62	rcu_read_lock();
     63	base = get_base_addr(seg, bus, devfn);
     64	if (!base) {
     65		rcu_read_unlock();
     66		goto err;
     67	}
     68
     69	raw_spin_lock_irqsave(&pci_config_lock, flags);
     70
     71	pci_exp_set_dev_base(base, bus, devfn);
     72
     73	switch (len) {
     74	case 1:
     75		*value = mmio_config_readb(mmcfg_virt_addr + reg);
     76		break;
     77	case 2:
     78		*value = mmio_config_readw(mmcfg_virt_addr + reg);
     79		break;
     80	case 4:
     81		*value = mmio_config_readl(mmcfg_virt_addr + reg);
     82		break;
     83	}
     84	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
     85	rcu_read_unlock();
     86
     87	return 0;
     88}
     89
     90static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
     91			   unsigned int devfn, int reg, int len, u32 value)
     92{
     93	unsigned long flags;
     94	u32 base;
     95
     96	if ((bus > 255) || (devfn > 255) || (reg > 4095))
     97		return -EINVAL;
     98
     99	rcu_read_lock();
    100	base = get_base_addr(seg, bus, devfn);
    101	if (!base) {
    102		rcu_read_unlock();
    103		return -EINVAL;
    104	}
    105
    106	raw_spin_lock_irqsave(&pci_config_lock, flags);
    107
    108	pci_exp_set_dev_base(base, bus, devfn);
    109
    110	switch (len) {
    111	case 1:
    112		mmio_config_writeb(mmcfg_virt_addr + reg, value);
    113		break;
    114	case 2:
    115		mmio_config_writew(mmcfg_virt_addr + reg, value);
    116		break;
    117	case 4:
    118		mmio_config_writel(mmcfg_virt_addr + reg, value);
    119		break;
    120	}
    121	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
    122	rcu_read_unlock();
    123
    124	return 0;
    125}
    126
    127const struct pci_raw_ops pci_mmcfg = {
    128	.read =		pci_mmcfg_read,
    129	.write =	pci_mmcfg_write,
    130};
    131
    132int __init pci_mmcfg_arch_init(void)
    133{
    134	printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
    135	raw_pci_ext_ops = &pci_mmcfg;
    136	return 1;
    137}
    138
    139void __init pci_mmcfg_arch_free(void)
    140{
    141}
    142
    143int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
    144{
    145	return 0;
    146}
    147
    148void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
    149{
    150	unsigned long flags;
    151
    152	/* Invalidate the cached mmcfg map entry. */
    153	raw_spin_lock_irqsave(&pci_config_lock, flags);
    154	mmcfg_last_accessed_device = 0;
    155	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
    156}