Enable pci mmcfg and ATS for x86_64

This patch enables PCI MMCONFIG in xen and turns on hooks for ATS.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
This commit is contained in:
Keir Fraser committed 2009-06-02 11:49:34 +01:00
1 parent d2c78b31b5
commit 3b35911d70
22 files changed
+988 -73

No files matched your search

+2
View File
@@ -937,6 +937,8 @@ int __init acpi_boot_init(void)
acpi_dmar_init();
acpi_mmcfg_init();
return 0;
}
+34
View File
@@ -25,6 +25,40 @@ boolean_param("e820-verbose", e820_verbose);
struct e820map e820;
/*
* This function checks if the entire range <start,end> is mapped with type.
*
* Note: this function only works correct if the e820 table is sorted and
* not-overlapping, which is the case
*/
int __init e820_all_mapped(u64 start, u64 end, unsigned type)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
if (type && ei->type != type)
continue;
/* is the region (part) in overlap with the current region ?*/
if (ei->addr >= end || ei->addr + ei->size <= start)
continue;
/* if the region is at the beginning of <start,end> we move
* start to the end of the region since it's ok until there
*/
if (ei->addr <= start)
start = ei->addr + ei->size;
/*
* if start is now at or beyond end, we're done, full
* coverage
*/
if (start >= end)
return 1;
}
return 0;
}
static void __init add_memory_region(unsigned long long start,
unsigned long long size, int type)
{
-49
View File
@@ -7,9 +7,6 @@
#include <xen/spinlock.h>
#include <asm/io.h>
#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
static DEFINE_SPINLOCK(pci_config_lock);
uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes)
@@ -69,49 +66,3 @@ void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data)
spin_unlock_irqrestore(&pci_config_lock, flags);
}
uint8_t pci_conf_read8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
}
uint16_t pci_conf_read16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
}
uint32_t pci_conf_read32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
}
void pci_conf_write8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint8_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
}
void pci_conf_write16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint16_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
}
void pci_conf_write32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint32_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
}
+1 -1
View File
@@ -2186,7 +2186,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
if ( (rdmsr_safe(MSR_FAM10H_MMIO_CONF_BASE, l, h) != 0) ||
(((((u64)h << 32) | l) ^ res) &
~((1 << FAM10H_MMIO_CONF_ENABLE_BIT) |
~( FAM10H_MMIO_CONF_ENABLE |
(FAM10H_MMIO_CONF_BUSRANGE_MASK <<
FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
((u64)FAM10H_MMIO_CONF_BASE_MASK <<
+1
View File
@@ -5,6 +5,7 @@ obj-y += mm.o
obj-y += seg_fixup.o
obj-y += traps.o
obj-y += machine_kexec.o
obj-y += pci.o
obj-$(crash_debug) += gdbstub.o
+70
View File
@@ -0,0 +1,70 @@
/******************************************************************************
* pci.c
*
* Architecture-dependent PCI access functions.
*/
#include <xen/spinlock.h>
#include <xen/pci.h>
#include <asm/io.h>
#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes);
void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data);
uint8_t pci_conf_read8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
}
uint16_t pci_conf_read16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
}
uint32_t pci_conf_read32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
}
void pci_conf_write8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint8_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
}
void pci_conf_write16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint16_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
}
void pci_conf_write32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint32_t data)
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7) || (reg > 255));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
}
int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
{
return 0;
}
void acpi_mmcfg_init(void)
{
return;
}
+4
View File
@@ -5,6 +5,10 @@ obj-y += gpr_switch.o
obj-y += mm.o
obj-y += traps.o
obj-y += machine_kexec.o
obj-y += pci.o
obj-y += acpi_mmcfg.o
obj-y += mmconfig_64.o
obj-y += mmconfig-shared.o
obj-$(crash_debug) += gdbstub.o
obj-$(CONFIG_COMPAT) += compat.o
+98
View File
@@ -0,0 +1,98 @@
/*
* acpi_mmconfig.c - Architecture-Specific Low-Level ACPI Boot Support
*
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* copied from Linux
*/
#include <xen/config.h>
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/acpi.h>
#include <xen/irq.h>
#include <xen/dmi.h>
#include <asm/fixmap.h>
#include <asm/page.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
#include <asm/io.h>
#include <asm/mpspec.h>
#include <asm/processor.h>
#include <mach_apic.h>
#include <mach_mpparse.h>
#include "mmconfig.h"
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
int acpi_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
unsigned long i;
int config_size;
if (!header)
return -EINVAL;
mcfg = (struct acpi_table_mcfg *)header;
/* how many config structures do we have */
pci_mmcfg_config_num = 0;
i = header->length - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_mcfg_allocation)) {
++pci_mmcfg_config_num;
i -= sizeof(struct acpi_mcfg_allocation);
};
if (pci_mmcfg_config_num == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV;
}
config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
pci_mmcfg_config = xmalloc_bytes(config_size);
if (!pci_mmcfg_config) {
printk(KERN_WARNING PREFIX
"No memory for MCFG config tables\n");
return -ENOMEM;
}
memcpy(pci_mmcfg_config, &mcfg[1], config_size);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
!acpi_mcfg_64bit_base_addr) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
xfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
return 0;
}
+382
View File
@@ -0,0 +1,382 @@
/*
* mmconfig-shared.c - Low-level direct PCI config space access via
* MMCONFIG - common code between i386 and x86-64.
*
* This code does:
* - known chipset handling
* - ACPI decoding and validation
*
* Per-architecture code takes care of the mappings and accesses
* themselves.
*
* Author: Allen Kay <allen.m.kay@intel.com> - adapted to xen from Linux
*/
#include <xen/mm.h>
#include <xen/acpi.h>
#include <xen/xmalloc.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/e820.h>
#include <asm/msr.h>
#include <asm/msr-index.h>
#include "mmconfig.h"
static int __initdata known_bridge;
unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;
static const char __init *pci_mmcfg_e7520(void)
{
u32 win;
win = pci_conf_read16(0, 0, 0, 0xce);
win = win & 0xf000;
if(win == 0x0000 || win == 0xf000)
pci_mmcfg_config_num = 0;
else {
pci_mmcfg_config_num = 1;
pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
if (!pci_mmcfg_config)
return NULL;
memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
pci_mmcfg_config[0].address = win << 16;
pci_mmcfg_config[0].pci_segment = 0;
pci_mmcfg_config[0].start_bus_number = 0;
pci_mmcfg_config[0].end_bus_number = 255;
}
return "Intel Corporation E7520 Memory Controller Hub";
}
static const char __init *pci_mmcfg_intel_945(void)
{
u32 pciexbar, mask = 0, len = 0;
pci_mmcfg_config_num = 1;
pciexbar = pci_conf_read32(0, 0, 0, 0x48);
/* Enable bit */
if (!(pciexbar & 1))
pci_mmcfg_config_num = 0;
/* Size bits */
switch ((pciexbar >> 1) & 3) {
case 0:
mask = 0xf0000000U;
len = 0x10000000U;
break;
case 1:
mask = 0xf8000000U;
len = 0x08000000U;
break;
case 2:
mask = 0xfc000000U;
len = 0x04000000U;
break;
default:
pci_mmcfg_config_num = 0;
}
/* Errata #2, things break when not aligned on a 256Mb boundary */
/* Can only happen in 64M/128M mode */
if ((pciexbar & mask) & 0x0fffffffU)
pci_mmcfg_config_num = 0;
/* Don't hit the APIC registers and their friends */
if ((pciexbar & mask) >= 0xf0000000U)
pci_mmcfg_config_num = 0;
if (pci_mmcfg_config_num) {
pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
if (!pci_mmcfg_config)
return NULL;
memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
pci_mmcfg_config[0].address = pciexbar & mask;
pci_mmcfg_config[0].pci_segment = 0;
pci_mmcfg_config[0].start_bus_number = 0;
pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
}
return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
}
static const char __init *pci_mmcfg_amd_fam10h(void)
{
u32 low, high, address;
u64 base, msr;
int i;
unsigned segnbits = 0, busnbits;
if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
return NULL;
address = MSR_FAM10H_MMIO_CONF_BASE;
if (rdmsr_safe(address, low, high))
return NULL;
msr = high;
msr <<= 32;
msr |= low;
/* mmconfig is not enable */
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
return NULL;
base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
FAM10H_MMIO_CONF_BUSRANGE_MASK;
/*
* only handle bus 0 ?
* need to skip it
*/
if (!busnbits)
return NULL;
if (busnbits > 8) {
segnbits = busnbits - 8;
busnbits = 8;
}
pci_mmcfg_config_num = (1 << segnbits);
pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]) *
pci_mmcfg_config_num);
if (!pci_mmcfg_config)
return NULL;
for (i = 0; i < (1 << segnbits); i++) {
pci_mmcfg_config[i].address = base + (1<<28) * i;
pci_mmcfg_config[i].pci_segment = i;
pci_mmcfg_config[i].start_bus_number = 0;
pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
}
return "AMD Family 10h NB";
}
struct pci_mmcfg_hostbridge_probe {
u32 bus;
u32 devfn;
u32 vendor;
u32 device;
const char *(*probe)(void);
};
static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
{ 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
0x1200, pci_mmcfg_amd_fam10h },
{ 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
0x1200, pci_mmcfg_amd_fam10h },
};
static int __init pci_mmcfg_check_hostbridge(void)
{
u32 l;
u32 bus, devfn;
u16 vendor, device;
int i;
const char *name;
pci_mmcfg_config_num = 0;
pci_mmcfg_config = NULL;
name = NULL;
for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
bus = pci_mmcfg_probes[i].bus;
devfn = pci_mmcfg_probes[i].devfn;
l = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
vendor = l & 0xffff;
device = (l >> 16) & 0xffff;
if (pci_mmcfg_probes[i].vendor == vendor &&
pci_mmcfg_probes[i].device == device)
name = pci_mmcfg_probes[i].probe();
}
if (name) {
printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
name, pci_mmcfg_config_num ? "with" : "without");
}
return name != NULL;
}
typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
static int __init is_mmconf_reserved(
check_reserved_t is_reserved,
u64 addr, u64 size, int i,
typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
{
u64 old_size = size;
int valid = 0;
while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
size >>= 1;
if (size < (16UL<<20))
break;
}
if (size >= (16UL<<20) || size == old_size) {
printk(KERN_NOTICE
"PCI: MCFG area at %lx reserved in %s\n",
addr, with_e820?"E820":"ACPI motherboard resources");
valid = 1;
if (old_size != size) {
/* update end_bus_number */
cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
}
}
return valid;
}
static void __init pci_mmcfg_reject_broken(int early)
{
typeof(pci_mmcfg_config[0]) *cfg;
int i;
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].address == 0))
return;
cfg = &pci_mmcfg_config[0];
for (i = 0; i < pci_mmcfg_config_num; i++) {
int valid = 0;
u64 addr, size;
cfg = &pci_mmcfg_config[i];
addr = cfg->start_bus_number;
addr <<= 20;
addr += cfg->address;
size = cfg->end_bus_number + 1 - cfg->start_bus_number;
size <<= 20;
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
if (valid)
continue;
if (!early)
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not"
" reserved in ACPI motherboard resources\n",
cfg->address);
valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
if (!valid)
goto reject;
}
return;
reject:
printk(KERN_INFO "PCI: Not using MMCONFIG.\n");
pci_mmcfg_arch_free();
xfree(pci_mmcfg_config);
pci_mmcfg_config = NULL;
pci_mmcfg_config_num = 0;
}
void __init __pci_mmcfg_init(int early)
{
/* MMCONFIG disabled */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
/* MMCONFIG already enabled */
if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
return;
/* for late to exit */
if (known_bridge)
return;
if (early) {
if (pci_mmcfg_check_hostbridge())
known_bridge = 1;
}
if (!known_bridge) {
acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
pci_mmcfg_reject_broken(early);
}
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].address == 0))
return;
if (pci_mmcfg_arch_init()) {
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
}
}
void acpi_mmcfg_init(void)
{
__pci_mmcfg_init(1);
}
/**
* pci_find_ext_capability - Find an extended capability
* @dev: PCI device to query
* @cap: capability code
*
* Returns the address of the requested extended capability structure
* within the device's PCI configuration space or 0 if the device does
* not support it. Possible values for @cap:
*
* %PCI_EXT_CAP_ID_ERR Advanced Error Reporting
* %PCI_EXT_CAP_ID_VC Virtual Channel
* %PCI_EXT_CAP_ID_DSN Device Serial Number
* %PCI_EXT_CAP_ID_PWR Power Budgeting
*/
int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
{
u32 header;
int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
int pos = 0x100;
header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
/*
* If we have no capabilities, this is indicated by cap ID,
* cap version and next pointer all being 0.
*/
if ( (header == 0) || (header == -1) )
{
dprintk(XENLOG_INFO VTDPREFIX,
"next cap:%x:%x.%x: no extended config\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
return 0;
}
while ( ttl-- > 0 ) {
if ( PCI_EXT_CAP_ID(header) == cap )
return pos;
pos = PCI_EXT_CAP_NEXT(header);
if ( pos < 0x100 )
break;
header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
}
return 0;
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2006, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
* Author: Allen Kay <allen.m.kay@intel.com> - adapted from linux
*/
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770
/* ioport ends */
#define PCI_PROBE_BIOS 0x0001
#define PCI_PROBE_CONF1 0x0002
#define PCI_PROBE_CONF2 0x0004
#define PCI_PROBE_MMCONF 0x0008
#define PCI_PROBE_MASK 0x000f
#define PCI_PROBE_NOEARLY 0x0010
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
/*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space
* on their northbrige except through the * %eax register. As such, you MUST
* NOT use normal IOMEM accesses, you need to only use the magic mmio-config
* accessor functions.
* In fact just use pci_config_*, nothing else please.
*/
static inline unsigned char mmio_config_readb(void __iomem *pos)
{
u8 val;
asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos));
return val;
}
static inline unsigned short mmio_config_readw(void __iomem *pos)
{
u16 val;
asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos));
return val;
}
static inline unsigned int mmio_config_readl(void __iomem *pos)
{
u32 val;
asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos));
return val;
}
static inline void mmio_config_writeb(void __iomem *pos, u8 val)
{
asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory");
}
static inline void mmio_config_writew(void __iomem *pos, u16 val)
{
asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory");
}
static inline void mmio_config_writel(void __iomem *pos, u32 val)
{
asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory");
}
/* external variable defines */
extern int pci_mmcfg_config_num;
extern struct acpi_mcfg_allocation *pci_mmcfg_config;
/* fucntion prototypes */
int __init acpi_parse_mcfg(struct acpi_table_header *header);
int __init pci_mmcfg_arch_init(void);
void __init pci_mmcfg_arch_free(void);
+180
View File
@@ -0,0 +1,180 @@
/*
* mmconfig.c - Low-level direct PCI config space access via MMCONFIG
*
* This is an 64bit optimized version that always keeps the full mmconfig
* space mapped. This allows lockless config space operation.
*
* copied from Linux
*/
#include <xen/mm.h>
#include <xen/acpi.h>
#include <xen/xmalloc.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include "mmconfig.h"
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
struct acpi_mcfg_allocation *cfg;
char __iomem *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
static char __iomem *get_virt(unsigned int seg, unsigned bus)
{
struct acpi_mcfg_allocation *cfg;
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
cfg = pci_mmcfg_virt[cfg_num].cfg;
if (cfg->pci_segment == seg &&
(cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return pci_mmcfg_virt[cfg_num].virt;
}
/* Fall back to type 0 */
return NULL;
}
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
char __iomem *addr;
addr = get_virt(seg, bus);
if (!addr)
return NULL;
return addr + ((bus << 20) | (devfn << 12));
}
int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
char __iomem *addr;
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
err: *value = -1;
return -EINVAL;
}
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
goto err;
switch (len) {
case 1:
*value = mmio_config_readb(addr + reg);
break;
case 2:
*value = mmio_config_readw(addr + reg);
break;
case 4:
*value = mmio_config_readl(addr + reg);
break;
}
return 0;
}
int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
char __iomem *addr;
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
return -EINVAL;
switch (len) {
case 1:
mmio_config_writeb(addr + reg, value);
break;
case 2:
mmio_config_writew(addr + reg, value);
break;
case 4:
mmio_config_writel(addr + reg, value);
break;
}
return 0;
}
static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
{
void __iomem *addr;
unsigned long virt;
unsigned long mfn;
unsigned long size, nr_mfn;
printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n", (u64)PCI_MCFG_VIRT_START);
printk("amk_mcfg_ioremap: start_bus %x end_bus %x\n",
cfg->start_bus_number, cfg->end_bus_number);
virt = PCI_MCFG_VIRT_START + (cfg->pci_segment * (1 << 22)) +
(cfg->start_bus_number * (1 << 20));
mfn = cfg->address >> PAGE_SHIFT;
size = (cfg->end_bus_number - cfg->start_bus_number) << 20;
nr_mfn = size >> PAGE_SHIFT;
printk("amk_mcfg_ioremap: virt %lx mfn = %lx size %lx\n", virt, mfn, size);
map_pages_to_xen(virt, mfn, nr_mfn, PAGE_HYPERVISOR_NOCACHE);
addr = (void __iomem *) virt;
printk("amk_mcfg_ioremap: PCI_MCFG_VIRT_START %lx\n",
(u64)PCI_MCFG_VIRT_START);
printk("amk_mcfg_ioremap: virt %lx size %lx\n", virt, size);
return addr;
}
int __init pci_mmcfg_arch_init(void)
{
int i;
pci_mmcfg_virt = xmalloc_bytes(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
if (pci_mmcfg_virt == NULL) {
printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
return 0;
}
memset(pci_mmcfg_virt, 0, sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]);
if (!pci_mmcfg_virt[i].virt) {
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
"segment %d\n",
pci_mmcfg_config[i].pci_segment);
pci_mmcfg_arch_free();
return 0;
}
}
return 1;
}
void __init pci_mmcfg_arch_free(void)
{
int i;
if (pci_mmcfg_virt == NULL)
return;
for (i = 0; i < pci_mmcfg_config_num; ++i) {
if (pci_mmcfg_virt[i].virt) {
iounmap(pci_mmcfg_virt[i].virt);
pci_mmcfg_virt[i].virt = NULL;
pci_mmcfg_virt[i].cfg = NULL;
}
}
xfree(pci_mmcfg_virt);
pci_mmcfg_virt = NULL;
}
+109
View File
@@ -0,0 +1,109 @@
/******************************************************************************
* pci.c
*
* Architecture-dependent PCI access functions.
*/
#include <xen/spinlock.h>
#include <xen/pci.h>
#include <asm/io.h>
#define PCI_CONF_ADDRESS(bus, dev, func, reg) \
(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3))
int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value);
int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value);
uint32_t pci_conf_read(uint32_t cf8, uint8_t offset, uint8_t bytes);
void pci_conf_write(uint32_t cf8, uint8_t offset, uint8_t bytes, uint32_t data);
uint8_t pci_conf_read8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
u32 value;
if ( reg > 255 )
{
pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 1, &value);
return value;
}
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1);
}
}
uint16_t pci_conf_read16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
u32 value;
if ( reg > 255 )
{
pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 2, &value);
return value;
}
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2);
}
}
uint32_t pci_conf_read32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg)
{
u32 value;
if ( reg > 255 )
{
pci_mmcfg_read(0, bus, PCI_DEVFN(dev, func), reg, 4, &value);
return value;
}
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
return pci_conf_read(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4);
}
}
void pci_conf_write8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint8_t data)
{
if ( reg > 255 )
pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 1, data);
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 3, 1, data);
}
}
void pci_conf_write16(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint16_t data)
{
if ( reg > 255 )
pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 2, data);
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), reg & 2, 2, data);
}
}
void pci_conf_write32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint32_t data)
{
if ( reg > 255 )
pci_mmcfg_write(0, bus, PCI_DEVFN(dev, func), reg, 4, data);
else
{
BUG_ON((bus > 255) || (dev > 31) || (func > 7));
pci_conf_write(PCI_CONF_ADDRESS(bus, dev, func, reg), 0, 4, data);
}
}
+6
View File
@@ -48,8 +48,14 @@ int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx);
struct iommu * ioapic_to_iommu(unsigned int apic_id);
struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id);
void clear_fault_bits(struct iommu *iommu);
int ats_device(int seg, int bus, int devfn);
int enable_ats_device(int seg, int bus, int devfn);
int disable_ats_device(int seg, int bus, int devfn);
int invalidate_ats_tcs(struct iommu *iommu);
int qinval_device_iotlb(struct iommu *iommu,
u32 max_invs_pend, u16 sid, u16 size, u64 addr);
int dev_invalidate_iotlb(struct iommu *iommu, u16 did,
u64 addr, unsigned int size_order, u64 type);
struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu);
#endif // _VTD_EXTERN_H_
-8
View File
@@ -35,14 +35,6 @@ struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
return NULL;
}
/*
* BUGBUG: return 0 until pcimmcfg is checked in.
*/
int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
{
return 0;
}
int ats_device(int seg, int bus, int devfn)
{
return 0;
-2
View File
@@ -1663,10 +1663,8 @@ static void setup_dom0_devices(struct domain *d)
pdev->domain = d;
list_add(&pdev->domain_list, &d->arch.pdev_list);
domain_context_mapping(d, pdev->bus, pdev->devfn);
#if defined(NOT_YET)
if ( ats_device(0, pdev->bus, pdev->devfn) )
enable_ats_device(0, pdev->bus, pdev->devfn);
#endif
}
}
}
-2
View File
@@ -409,10 +409,8 @@ static int flush_iotlb_qi(
ret = queue_invalidate_iotlb(iommu,
(type >> DMA_TLB_FLUSH_GRANU_OFFSET), dr,
dw, did, (u8)size_order, 0, addr);
#if defined(NOT_YET)
if ( flush_dev_iotlb )
ret |= dev_invalidate_iotlb(iommu, did, addr, size_order, type);
#endif
ret |= invalidate_sync(iommu);
}
return ret;
-8
View File
@@ -81,14 +81,6 @@ struct acpi_drhd_unit * find_ats_dev_drhd(struct iommu *iommu)
return NULL;
}
/*
* BUGBUG: return 0 until pcimmcfg is checked in.
*/
int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
{
return 0;
}
int ats_device(int seg, int bus, int devfn)
{
struct acpi_drhd_unit *drhd, *ats_drhd, *new_drhd;
+2 -1
View File
@@ -164,7 +164,8 @@ struct acpi_sleep_info {
extern u8 x86_acpiid_to_apicid[];
#define MAX_LOCAL_APIC 256
extern int acpi_dmar_init(void);
int acpi_dmar_init(void);
void acpi_mmcfg_init(void);
/* Incremented whenever we transition through S3. Value is 1 during boot. */
extern uint32_t system_reset_counter;
+7 -1
View File
@@ -135,7 +135,7 @@ extern unsigned int video_mode, video_flags;
* 0xffff804000000000 - 0xffff807fffffffff [256GB, 2^38 bytes, PML4:256]
* Reserved for future shared info with the guest OS (GUEST ACCESSIBLE).
* 0xffff808000000000 - 0xffff80ffffffffff [512GB, 2^39 bytes, PML4:257]
* Reserved for future use.
* ioremap for PCI mmconfig space
* 0xffff810000000000 - 0xffff817fffffffff [512GB, 2^39 bytes, PML4:258]
* Guest linear page table.
* 0xffff818000000000 - 0xffff81ffffffffff [512GB, 2^39 bytes, PML4:259]
@@ -188,6 +188,12 @@ extern unsigned int video_mode, video_flags;
/* Slot 256: read-only guest-accessible machine-to-phys translation table. */
#define RO_MPT_VIRT_START (PML4_ADDR(256))
#define RO_MPT_VIRT_END (RO_MPT_VIRT_START + PML4_ENTRY_BYTES/2)
/* Slot 257: ioremap for PCI mmconfig space for 2048 segments (512GB)
* - full 16-bit segment support needs 44 bits
* - since PML4 slot has 39 bits, we limit segments to 2048 (11-bits)
*/
#define PCI_MCFG_VIRT_START (PML4_ADDR(257))
#define PCI_MCFG_VIRT_END (RDWR_MPT_VIRT_START + PML4_ENTRY_BYTES)
/* Slot 258: linear page table (guest table). */
#define LINEAR_PT_VIRT_START (PML4_ADDR(258))
#define LINEAR_PT_VIRT_END (LINEAR_PT_VIRT_START + PML4_ENTRY_BYTES)
+1
View File
@@ -23,6 +23,7 @@ struct e820map {
struct e820entry map[E820MAX];
};
extern int e820_all_mapped(u64 start, u64 end, unsigned type);
extern int reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e);
extern int e820_change_range_type(
struct e820map *e820, uint64_t s, uint64_t e,
+1 -1
View File
@@ -231,7 +231,7 @@
/* Other AMD Fam10h MSRs */
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
#define FAM10H_MMIO_CONF_ENABLE_BIT 0
#define FAM10H_MMIO_CONF_ENABLE (1<<0)
#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf
#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff
+5
View File
@@ -93,8 +93,13 @@ void pci_conf_write16(
void pci_conf_write32(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg,
uint32_t data);
int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value);
int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value);
int pci_find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap);
int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap);
int pci_find_ext_capability(int seg, int bus, int devfn, int cap);
int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable);
void msixtbl_pt_unregister(struct domain *d, int pirq);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.