Extract the location of the remapping hardware units from the ACPI DMAR table.

Submitted by:	Gopakumar T (gopakumar_thekkedath@yahoo.co.in)
This commit is contained in:
Neel Natu 2013-08-20 06:20:05 +00:00
parent 15e683837c
commit f77e982952

View File

@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
#include <machine/pmap.h> #include <machine/pmap.h>
#include <machine/vmparam.h> #include <machine/vmparam.h>
#include <machine/pci_cfgreg.h> #include <contrib/dev/acpica/include/acpi.h>
#include "io/iommu.h" #include "io/iommu.h"
@ -123,60 +123,6 @@ static uint64_t ctx_tables[256][PAGE_SIZE / sizeof(uint64_t)] __aligned(4096);
static MALLOC_DEFINE(M_VTD, "vtd", "vtd"); static MALLOC_DEFINE(M_VTD, "vtd", "vtd");
/*
* Config space register definitions from the "Intel 5520 and 5500" datasheet.
*/
static int
tylersburg_vtd_ident(void)
{
int units, nlbus;
uint16_t did, vid;
uint32_t miscsts, vtbar;
const int bus = 0;
const int slot = 20;
const int func = 0;
units = 0;
vid = pci_cfgregread(bus, slot, func, PCIR_VENDOR, 2);
did = pci_cfgregread(bus, slot, func, PCIR_DEVICE, 2);
if (vid != 0x8086 || did != 0x342E)
goto done;
/*
* Check if this is a dual IOH configuration.
*/
miscsts = pci_cfgregread(bus, slot, func, 0x9C, 4);
if (miscsts & (1 << 25))
nlbus = pci_cfgregread(bus, slot, func, 0x160, 1);
else
nlbus = -1;
vtbar = pci_cfgregread(bus, slot, func, 0x180, 4);
if (vtbar & 0x1) {
vtdmaps[units++] = (struct vtdmap *)
PHYS_TO_DMAP(vtbar & 0xffffe000);
} else if (bootverbose)
printf("VT-d unit in legacy IOH is disabled!\n");
if (nlbus != -1) {
vtbar = pci_cfgregread(nlbus, slot, func, 0x180, 4);
if (vtbar & 0x1) {
vtdmaps[units++] = (struct vtdmap *)
PHYS_TO_DMAP(vtbar & 0xffffe000);
} else if (bootverbose)
printf("VT-d unit in non-legacy IOH is disabled!\n");
}
done:
return (units);
}
static drhd_ident_func_t drhd_ident_funcs[] = {
tylersburg_vtd_ident,
NULL
};
static int static int
vtd_max_domains(struct vtdmap *vtdmap) vtd_max_domains(struct vtdmap *vtdmap)
{ {
@ -291,19 +237,67 @@ vtd_translation_disable(struct vtdmap *vtdmap)
static int static int
vtd_init(void) vtd_init(void)
{ {
int i, units; int i, units, remaining;
struct vtdmap *vtdmap; struct vtdmap *vtdmap;
vm_paddr_t ctx_paddr; vm_paddr_t ctx_paddr;
char *end, envname[32];
for (i = 0; drhd_ident_funcs[i] != NULL; i++) { unsigned long mapaddr;
units = (*drhd_ident_funcs[i])(); ACPI_STATUS status;
if (units > 0) ACPI_TABLE_DMAR *dmar;
ACPI_DMAR_HEADER *hdr;
ACPI_DMAR_HARDWARE_UNIT *drhd;
/*
* Allow the user to override the ACPI DMAR table by specifying the
* physical address of each remapping unit.
*
* The following example specifies two remapping units at
* physical addresses 0xfed90000 and 0xfeda0000 respectively.
* set vtd.regmap.0.addr=0xfed90000
* set vtd.regmap.1.addr=0xfeda0000
*/
for (units = 0; units < DRHD_MAX_UNITS; units++) {
snprintf(envname, sizeof(envname), "vtd.regmap.%d.addr", units);
if (getenv_ulong(envname, &mapaddr) == 0)
break; break;
vtdmaps[units] = (struct vtdmap *)PHYS_TO_DMAP(mapaddr);
}
if (units > 0)
goto skip_dmar;
/* Search for DMAR table. */
status = AcpiGetTable(ACPI_SIG_DMAR, 0, (ACPI_TABLE_HEADER **)&dmar);
if (ACPI_FAILURE(status))
return (ENXIO);
end = (char *)dmar + dmar->Header.Length;
remaining = dmar->Header.Length - sizeof(ACPI_TABLE_DMAR);
while (remaining > sizeof(ACPI_DMAR_HEADER)) {
hdr = (ACPI_DMAR_HEADER *)(end - remaining);
if (hdr->Length > remaining)
break;
/*
* From Intel VT-d arch spec, version 1.3:
* BIOS implementations must report mapping structures
* in numerical order, i.e. All remapping structures of
* type 0 (DRHD) enumerated before remapping structures of
* type 1 (RMRR) and so forth.
*/
if (hdr->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT)
break;
drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr;
vtdmaps[units++] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address);
if (units >= DRHD_MAX_UNITS)
break;
remaining -= hdr->Length;
} }
if (units <= 0) if (units <= 0)
return (ENXIO); return (ENXIO);
skip_dmar:
drhd_num = units; drhd_num = units;
vtdmap = vtdmaps[0]; vtdmap = vtdmaps[0];