mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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:
1 parent
d2c78b31b5
commit
3b35911d70
22 files changed
+988
-73
No files matched your search
@@ -937,6 +937,8 @@ int __init acpi_boot_init(void)
|
||||
|
||||
acpi_dmar_init();
|
||||
|
||||
acpi_mmcfg_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 <<
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||