This change fixes duplicate detection of same IOMMU/AMD-Vi device for Ryzen with EFR support.
IVRS can have entry of type legacy and non-legacy present at same time for same AMD-Vi device. ivhd driver will ignore legacy if new IVHD type is present as specified in AMD-Vi specification. Earlier both of IVHD entries used and two ivhd devices were created. Add support for new IVHD type 0x11 and 0x40 in ACPI. Create new struct of type acpi_ivrs_hardware_new for these new type of IVHDs. Legacy type 0x10 will continue to use acpi_ivrs_hardware. Reviewed by: avg Approved by: grehan Differential Revision:https://reviews.freebsd.org/D13160
This commit is contained in:
parent
39006570a4
commit
0b37d3d90e
@ -745,22 +745,7 @@ amdvi_print_pci_cap(device_t dev)
|
||||
softc->pci_cap = cap >> 24;
|
||||
device_printf(softc->dev, "PCI cap 0x%x@0x%x feature:%b\n",
|
||||
cap, off, softc->pci_cap,
|
||||
"\020\001IOTLB\002HT\003NPCache\004EFR");
|
||||
|
||||
/* IOMMU spec Rev 2.0, section 3.7.2.1 */
|
||||
softc->pci_efr = softc->ctrl->ex_feature;
|
||||
if (softc->pci_efr) {
|
||||
device_printf(softc->dev, "PCI extended Feature:%b\n",
|
||||
(int)softc->pci_efr,
|
||||
"\020\001PreFSup\002PPRSup\003XTSup\004NXSup\006IASup"
|
||||
"\007GASup\008HESup\009PCSup");
|
||||
device_printf(softc->dev,
|
||||
"PCI HATS = %d GATS = %d GLXSup = %d, max PASID: 0x%x ",
|
||||
(int)((softc->pci_efr >> 10) & 0x3),
|
||||
(int)((softc->pci_efr >> 12) & 0x3),
|
||||
(int)((softc->pci_efr >> 14) & 0x3),
|
||||
(int)((softc->pci_efr >> 32) & 0x1F) + 1);
|
||||
}
|
||||
"\20\1IOTLB\2HT\3NPCache\4EFR\5CapExt");
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1040,7 +1025,7 @@ amdvi_init(void)
|
||||
}
|
||||
if (!amdvi_enable_user && ivhd_count) {
|
||||
printf("bhyve: Found %d AMD-Vi/IOMMU device(s), "
|
||||
"use hw.vmm.amdvi_enable=1 to enable pass-through.\n",
|
||||
"use hw.vmm.amdvi.enable=1 to enable pass-through.\n",
|
||||
ivhd_count);
|
||||
return (EINVAL);
|
||||
}
|
||||
@ -1315,40 +1300,41 @@ static void
|
||||
amdvi_set_dte(struct amdvi_domain *domain, uint16_t devid, bool enable)
|
||||
{
|
||||
struct amdvi_softc *softc;
|
||||
struct amdvi_dte temp;
|
||||
struct amdvi_dte* temp;
|
||||
|
||||
KASSERT(domain, ("domain is NULL for pci_rid:0x%x\n", devid));
|
||||
|
||||
softc = amdvi_find_iommu(devid);
|
||||
KASSERT(softc, ("softc is NULL for pci_rid:0x%x\n", devid));
|
||||
|
||||
memset(&temp, 0, sizeof(struct amdvi_dte));
|
||||
temp = &amdvi_dte[devid];
|
||||
|
||||
#ifdef AMDVI_ATS_ENABLE
|
||||
/* If IOMMU and device support IOTLB, enable it. */
|
||||
if (amdvi_dev_support_iotlb(softc, devid) && softc->iotlb)
|
||||
temp.iotlb_enable = 1;
|
||||
temp->iotlb_enable = 1;
|
||||
#endif
|
||||
|
||||
/* Avoid duplicate I/O faults. */
|
||||
temp.sup_second_io_fault = 1;
|
||||
temp.sup_all_io_fault = amdvi_disable_io_fault;
|
||||
temp->sup_second_io_fault = 1;
|
||||
temp->sup_all_io_fault = amdvi_disable_io_fault;
|
||||
|
||||
temp.dt_valid = 1;
|
||||
temp.domain_id = domain->id;
|
||||
temp->dt_valid = 1;
|
||||
temp->domain_id = domain->id;
|
||||
|
||||
if (enable) {
|
||||
if (domain->ptp) {
|
||||
temp.pt_base = vtophys(domain->ptp) >> 12;
|
||||
temp.pt_level = amdvi_ptp_level;
|
||||
temp->pt_base = vtophys(domain->ptp) >> 12;
|
||||
temp->pt_level = amdvi_ptp_level;
|
||||
}
|
||||
/*
|
||||
* XXX: Page table valid[TV] bit must be set even if host domain
|
||||
* page tables are not enabled.
|
||||
*/
|
||||
temp.pt_valid = 1;
|
||||
temp.read_allow = 1;
|
||||
temp.write_allow = 1;
|
||||
temp->pt_valid = 1;
|
||||
temp->read_allow = 1;
|
||||
temp->write_allow = 1;
|
||||
}
|
||||
amdvi_dte[devid] = temp;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -29,6 +29,8 @@
|
||||
#ifndef _AMDVI_PRIV_H_
|
||||
#define _AMDVI_PRIV_H_
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
|
||||
#define BIT(n) (1ULL << (n))
|
||||
/* Return value of bits[n:m] where n and (n >= ) m are bit positions. */
|
||||
#define REG_BITS(x, n, m) (((x) >> (m)) & \
|
||||
@ -358,6 +360,7 @@ struct amdvi_domain {
|
||||
struct amdvi_softc {
|
||||
struct amdvi_ctrl *ctrl; /* Control area. */
|
||||
device_t dev; /* IOMMU device. */
|
||||
enum AcpiIvrsType ivhd_type; /* IOMMU IVHD type 0x10/0x11 or 0x40 */
|
||||
bool iotlb; /* IOTLB supported by IOMMU */
|
||||
struct amdvi_cmd *cmd; /* Command descriptor area. */
|
||||
int cmd_max; /* Max number of commands. */
|
||||
@ -370,11 +373,11 @@ struct amdvi_softc {
|
||||
int event_rid;
|
||||
/* ACPI various flags. */
|
||||
uint32_t ivhd_flag; /* ACPI IVHD flag. */
|
||||
uint32_t ivhd_efr; /* ACPI v1 Reserved or v2 EFR . */
|
||||
uint32_t ivhd_feature; /* ACPI v1 Reserved or v2 attribute. */
|
||||
uint64_t ext_feature; /* IVHD EFR */
|
||||
/* PCI related. */
|
||||
uint16_t cap_off; /* PCI Capability offset. */
|
||||
uint8_t pci_cap; /* PCI capability. */
|
||||
uint64_t pci_efr; /* PCI EFR for rev2.0 */
|
||||
uint16_t pci_seg; /* IOMMU PCI domain/segment. */
|
||||
uint16_t pci_rid; /* PCI BDF of IOMMU */
|
||||
/* Device range under this IOMMU. */
|
||||
|
@ -47,12 +47,16 @@ __FBSDID("$FreeBSD$");
|
||||
#include "amdvi_priv.h"
|
||||
|
||||
device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */
|
||||
int ivhd_count; /* Number of IVHD or AMD-Vi devices. */
|
||||
int ivhd_count; /* Number of IVHD header. */
|
||||
/*
|
||||
* Cached IVHD header list.
|
||||
* Single entry for each IVHD, filtered the legacy one.
|
||||
*/
|
||||
ACPI_IVRS_HARDWARE *ivhd_hdrs[10];
|
||||
|
||||
extern int amdvi_ptp_level; /* Page table levels. */
|
||||
|
||||
typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER * ptr, void *arg);
|
||||
|
||||
typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg);
|
||||
/*
|
||||
* Iterate IVRS table for IVHD and IVMD device type.
|
||||
*/
|
||||
@ -107,14 +111,19 @@ ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static bool
|
||||
ivrs_is_ivhd(UINT8 type)
|
||||
{
|
||||
|
||||
if ((type == ACPI_IVRS_TYPE_HARDWARE) || (type == 0x11) || (type == 0x40))
|
||||
return (1);
|
||||
switch(type) {
|
||||
case ACPI_IVRS_TYPE_HARDWARE:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT1:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT2:
|
||||
return (true);
|
||||
|
||||
return (0);
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Count the number of AMD-Vi devices in the system. */
|
||||
@ -184,7 +193,7 @@ ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id,
|
||||
* Record device attributes as suggested by BIOS.
|
||||
*/
|
||||
static int
|
||||
ivhd_dev_parse(ACPI_IVRS_HARDWARE * ivhd, struct amdvi_softc *softc)
|
||||
ivhd_dev_parse(ACPI_IVRS_HARDWARE* ivhd, struct amdvi_softc *softc)
|
||||
{
|
||||
ACPI_IVRS_DE_HEADER *de;
|
||||
uint8_t *p, *end;
|
||||
@ -196,11 +205,26 @@ ivhd_dev_parse(ACPI_IVRS_HARDWARE * ivhd, struct amdvi_softc *softc)
|
||||
softc->start_dev_rid = ~0;
|
||||
softc->end_dev_rid = 0;
|
||||
|
||||
/*
|
||||
* XXX The following actually depends on Header.Type and
|
||||
* is only true for 0x10.
|
||||
*/
|
||||
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE);
|
||||
switch (ivhd->Header.Type) {
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT1:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT2:
|
||||
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE_NEW);
|
||||
de = (ACPI_IVRS_DE_HEADER *) ((uint8_t *)ivhd +
|
||||
sizeof(ACPI_IVRS_HARDWARE_NEW));
|
||||
break;
|
||||
|
||||
case ACPI_IVRS_TYPE_HARDWARE:
|
||||
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE);
|
||||
de = (ACPI_IVRS_DE_HEADER *) ((uint8_t *)ivhd +
|
||||
sizeof(ACPI_IVRS_HARDWARE));
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(softc->dev,
|
||||
"unknown type: 0x%x\n", ivhd->Header.Type);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
end = (uint8_t *)ivhd + ivhd->Header.Length;
|
||||
|
||||
while (p < end) {
|
||||
@ -285,14 +309,30 @@ ivhd_dev_parse(ACPI_IVRS_HARDWARE * ivhd, struct amdvi_softc *softc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static bool
|
||||
ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new)
|
||||
{
|
||||
/*
|
||||
* Newer IVRS header type take precedence.
|
||||
*/
|
||||
if ((old->DeviceId == new->DeviceId) &&
|
||||
(old->Type == ACPI_IVRS_TYPE_HARDWARE) &&
|
||||
((new->Type == ACPI_IVRS_TYPE_HARDWARE_EXT1) ||
|
||||
(new->Type == ACPI_IVRS_TYPE_HARDWARE_EXT1))) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
ivhd_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
ACPI_TABLE_IVRS *ivrs;
|
||||
ACPI_IVRS_HARDWARE *ivhd;
|
||||
ACPI_STATUS status;
|
||||
uint32_t info;
|
||||
int i, count = 0;
|
||||
uint32_t ivrs_ivinfo;
|
||||
|
||||
if (acpi_disabled("ivhd"))
|
||||
return;
|
||||
@ -305,24 +345,40 @@ ivhd_identify(driver_t *driver, device_t parent)
|
||||
return;
|
||||
}
|
||||
|
||||
info = ivrs->Info;
|
||||
printf("AMD-Vi IVRS VAsize = %d PAsize = %d GVAsize = %d flags:%b\n",
|
||||
REG_BITS(info, 21, 15), REG_BITS(info, 14, 8),
|
||||
REG_BITS(info, 7, 5), REG_BITS(info, 22, 22),
|
||||
"\020\001HtAtsResv");
|
||||
ivrs_ivinfo = ivrs->Info;
|
||||
printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d"
|
||||
" flags:%b\n",
|
||||
REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8),
|
||||
REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
|
||||
"\020\001EFRSup");
|
||||
|
||||
ivrs_hdr_iterate_tbl(ivhd_count_iter, NULL);
|
||||
if (!ivhd_count)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ivhd_count; i++) {
|
||||
ivhd = ivhd_find_by_index(i);
|
||||
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
|
||||
ivhd_hdrs[i] = ivhd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for presence of legacy and non-legacy device type
|
||||
* for same AMD-Vi device and override the old one.
|
||||
*/
|
||||
for (i = ivhd_count - 1 ; i > 0 ; i--){
|
||||
if (ivhd_is_newer(&ivhd_hdrs[i-1]->Header,
|
||||
&ivhd_hdrs[i]->Header)) {
|
||||
ivhd_hdrs[i-1] = ivhd_hdrs[i];
|
||||
ivhd_count--;
|
||||
}
|
||||
}
|
||||
|
||||
ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF,
|
||||
M_WAITOK | M_ZERO);
|
||||
for (i = 0; i < ivhd_count; i++) {
|
||||
ivhd = ivhd_find_by_index(i);
|
||||
if (ivhd == NULL) {
|
||||
printf("Can't find IVHD entry%d\n", i);
|
||||
continue;
|
||||
}
|
||||
ivhd = ivhd_hdrs[i];
|
||||
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
|
||||
|
||||
/*
|
||||
* Use a high order to ensure that this driver is probed after
|
||||
@ -338,7 +394,7 @@ ivhd_identify(driver_t *driver, device_t parent)
|
||||
if (ivhd_devs[i] == NULL) {
|
||||
ivhd_devs[i] = device_find_child(parent, "ivhd", i);
|
||||
if (ivhd_devs[i] == NULL) {
|
||||
printf("AMD-Vi: cant find AMD-Vi dev%d\n", i);
|
||||
printf("AMD-Vi: cant find ivhd%d\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -354,14 +410,169 @@ ivhd_identify(driver_t *driver, device_t parent)
|
||||
static int
|
||||
ivhd_probe(device_t dev)
|
||||
{
|
||||
ACPI_IVRS_HARDWARE *ivhd;
|
||||
int unit;
|
||||
|
||||
if (acpi_get_handle(dev) != NULL)
|
||||
return (ENXIO);
|
||||
device_set_desc(dev, "AMD-Vi/IOMMU or ivhd");
|
||||
|
||||
unit = device_get_unit(dev);
|
||||
KASSERT((unit < ivhd_count),
|
||||
("ivhd unit %d > count %d", unit, ivhd_count));
|
||||
ivhd = ivhd_hdrs[unit];
|
||||
KASSERT(ivhd, ("ivhd is NULL"));
|
||||
|
||||
if (ivhd->Header.Type == ACPI_IVRS_TYPE_HARDWARE)
|
||||
device_set_desc(dev, "AMD-Vi/IOMMU ivhd");
|
||||
else
|
||||
device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR");
|
||||
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
static void
|
||||
ivhd_print_flag(device_t dev, enum AcpiIvrsType ivhd_type, uint8_t flag)
|
||||
{
|
||||
/*
|
||||
* IVHD lgeacy type has two extra high bits in flag which has
|
||||
* been moved to EFR for non-legacy device.
|
||||
*/
|
||||
switch (ivhd_type) {
|
||||
case ACPI_IVRS_TYPE_HARDWARE:
|
||||
device_printf(dev, "Flag:%b\n", flag,
|
||||
"\020"
|
||||
"\001HtTunEn"
|
||||
"\002PassPW"
|
||||
"\003ResPassPW"
|
||||
"\004Isoc"
|
||||
"\005IotlbSup"
|
||||
"\006Coherent"
|
||||
"\007PreFSup"
|
||||
"\008PPRSup");
|
||||
break;
|
||||
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT1:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT2:
|
||||
device_printf(dev, "Flag:%b\n", flag,
|
||||
"\020"
|
||||
"\001HtTunEn"
|
||||
"\002PassPW"
|
||||
"\003ResPassPW"
|
||||
"\004Isoc"
|
||||
"\005IotlbSup"
|
||||
"\006Coherent");
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(dev, "Can't decode flag of ivhd type :0x%x\n",
|
||||
ivhd_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40).
|
||||
*/
|
||||
static void
|
||||
ivhd_print_feature(device_t dev, enum AcpiIvrsType ivhd_type, uint32_t feature)
|
||||
{
|
||||
switch (ivhd_type) {
|
||||
case ACPI_IVRS_TYPE_HARDWARE:
|
||||
device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d"
|
||||
" MsiNumPPR = %d PNBanks= %d PNCounters= %d\n",
|
||||
ivhd_type,
|
||||
REG_BITS(feature, 31, 30),
|
||||
REG_BITS(feature, 29, 28),
|
||||
REG_BITS(feature, 27, 23),
|
||||
REG_BITS(feature, 22, 17),
|
||||
REG_BITS(feature, 16, 13));
|
||||
device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n",
|
||||
REG_BITS(feature, 12, 8),
|
||||
REG_BITS(feature, 4, 3),
|
||||
feature,
|
||||
"\020"
|
||||
"\002NXSup"
|
||||
"\003GTSup"
|
||||
"\004<b4>"
|
||||
"\005IASup"
|
||||
"\006GASup"
|
||||
"\007HESup");
|
||||
break;
|
||||
|
||||
/* Fewer features or attributes are reported in non-legacy type. */
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT1:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT2:
|
||||
device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d"
|
||||
" PNBanks= %d PNCounters= %d\n",
|
||||
ivhd_type,
|
||||
REG_BITS(feature, 27, 23),
|
||||
REG_BITS(feature, 22, 17),
|
||||
REG_BITS(feature, 16, 13));
|
||||
break;
|
||||
|
||||
default: /* Other ivhd type features are not decoded. */
|
||||
device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print extended features of IOMMU. */
|
||||
static void
|
||||
ivhd_print_ext_feature(device_t dev, uint64_t ext_feature)
|
||||
{
|
||||
uint32_t ext_low, ext_high;
|
||||
|
||||
if (!ext_feature)
|
||||
return;
|
||||
|
||||
ext_low = ext_feature;
|
||||
device_printf(dev, "Extended features[31:0]:%b "
|
||||
"HATS = 0x%x GATS = 0x%x "
|
||||
"GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x "
|
||||
"GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n",
|
||||
(int)ext_low,
|
||||
"\020"
|
||||
"\001PreFSup"
|
||||
"\002PPRSup"
|
||||
"\003<b2>"
|
||||
"\004NXSup"
|
||||
"\005GTSup"
|
||||
"\006<b5>"
|
||||
"\007IASup"
|
||||
"\008GASup"
|
||||
"\009HESup"
|
||||
"\010PCSup",
|
||||
REG_BITS(ext_low, 11, 10),
|
||||
REG_BITS(ext_low, 13, 12),
|
||||
REG_BITS(ext_low, 15, 14),
|
||||
REG_BITS(ext_low, 17, 16),
|
||||
REG_BITS(ext_low, 20, 18),
|
||||
REG_BITS(ext_low, 23, 21),
|
||||
REG_BITS(ext_low, 25, 24),
|
||||
REG_BITS(ext_low, 29, 28));
|
||||
|
||||
ext_high = ext_feature >> 32;
|
||||
device_printf(dev, "Extended features[62:32]:%b "
|
||||
"Max PASID: 0x%x DevTblSegSup = 0x%x "
|
||||
"MarcSup = 0x%x\n",
|
||||
(int)(ext_high),
|
||||
"\020"
|
||||
"\006USSup"
|
||||
"\009PprOvrflwEarlySup"
|
||||
"\010PPRAutoRspSup"
|
||||
"\013BlKStopMrkSup"
|
||||
"\014PerfOptSup"
|
||||
"\015MsiCapMmioSup"
|
||||
"\017GIOSup"
|
||||
"\018HASup"
|
||||
"\019EPHSup"
|
||||
"\020AttrFWSup"
|
||||
"\021HDSup"
|
||||
"\023InvIotlbSup",
|
||||
REG_BITS(ext_high, 5, 0),
|
||||
REG_BITS(ext_high, 8, 7),
|
||||
REG_BITS(ext_high, 11, 10));
|
||||
}
|
||||
|
||||
static int
|
||||
ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE * ivhd)
|
||||
{
|
||||
@ -369,41 +580,23 @@ ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE * ivhd)
|
||||
int max_ptp_level;
|
||||
|
||||
dev = softc->dev;
|
||||
device_printf(dev, "Flag:%b\n", softc->ivhd_flag,
|
||||
"\020\001HtTunEn\002PassPW\003ResPassPW\004Isoc\005IotlbSup"
|
||||
"\006Coherent\007PreFSup\008PPRSup");
|
||||
/*
|
||||
* If no extended feature[EFR], its rev1 with maximum paging level as 7.
|
||||
*/
|
||||
|
||||
ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag);
|
||||
ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature);
|
||||
ivhd_print_ext_feature(dev, softc->ext_feature);
|
||||
max_ptp_level = 7;
|
||||
if (softc->ivhd_efr) {
|
||||
device_printf(dev, "EFR HATS = %d GATS = %d GLXSup = %d "
|
||||
"MsiNumPr = %d PNBanks= %d PNCounters= %d\n"
|
||||
"max PASID = %d EFR: %b \n",
|
||||
REG_BITS(softc->ivhd_efr, 31, 30),
|
||||
REG_BITS(softc->ivhd_efr, 29, 28),
|
||||
REG_BITS(softc->ivhd_efr, 4, 3),
|
||||
REG_BITS(softc->ivhd_efr, 27, 23),
|
||||
REG_BITS(softc->ivhd_efr, 22, 17),
|
||||
REG_BITS(softc->ivhd_efr, 16, 13),
|
||||
REG_BITS(softc->ivhd_efr, 12, 8),
|
||||
softc->ivhd_efr, "\020\001XTSup\002NXSup\003GTSup\005IASup"
|
||||
"\006GASup\007HESup\008PPRSup");
|
||||
|
||||
max_ptp_level = REG_BITS(softc->ivhd_efr, 31, 30) + 4;
|
||||
}
|
||||
|
||||
/* Make sure device support minimum page level as requested by user. */
|
||||
if (max_ptp_level < amdvi_ptp_level) {
|
||||
device_printf(dev, "Insufficient PTP level:%d\n",
|
||||
max_ptp_level);
|
||||
device_printf(dev, "insufficient PTP level:%d\n",
|
||||
max_ptp_level);
|
||||
return (EINVAL);
|
||||
} else {
|
||||
device_printf(softc->dev, "supported paging level:%d, will use only: %d\n",
|
||||
max_ptp_level, amdvi_ptp_level);
|
||||
}
|
||||
|
||||
device_printf(softc->dev, "max supported paging level:%d restricting to: %d\n",
|
||||
max_ptp_level, amdvi_ptp_level);
|
||||
device_printf(softc->dev, "device supported range "
|
||||
"[0x%x - 0x%x]\n", softc->start_dev_rid, softc->end_dev_rid);
|
||||
device_printf(softc->dev, "device range: 0x%x - 0x%x\n",
|
||||
softc->start_dev_rid, softc->end_dev_rid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -412,24 +605,31 @@ static int
|
||||
ivhd_attach(device_t dev)
|
||||
{
|
||||
ACPI_IVRS_HARDWARE *ivhd;
|
||||
ACPI_IVRS_HARDWARE_NEW *ivhd1;
|
||||
struct amdvi_softc *softc;
|
||||
int status, unit;
|
||||
|
||||
unit = device_get_unit(dev);
|
||||
KASSERT((unit < ivhd_count),
|
||||
("ivhd unit %d > count %d", unit, ivhd_count));
|
||||
/* Make sure its same device for which attach is called. */
|
||||
if (ivhd_devs[unit] != dev)
|
||||
panic("Not same device old %p new %p", ivhd_devs[unit], dev);
|
||||
KASSERT((ivhd_devs[unit] == dev),
|
||||
("Not same device old %p new %p", ivhd_devs[unit], dev));
|
||||
|
||||
softc = device_get_softc(dev);
|
||||
softc->dev = dev;
|
||||
ivhd = ivhd_find_by_index(unit);
|
||||
if (ivhd == NULL)
|
||||
return (EINVAL);
|
||||
ivhd = ivhd_hdrs[unit];
|
||||
KASSERT(ivhd, ("ivhd is NULL"));
|
||||
|
||||
softc->ivhd_type = ivhd->Header.Type;
|
||||
softc->pci_seg = ivhd->PciSegmentGroup;
|
||||
softc->pci_rid = ivhd->Header.DeviceId;
|
||||
softc->ivhd_flag = ivhd->Header.Flags;
|
||||
softc->ivhd_efr = ivhd->Reserved;
|
||||
/*
|
||||
* On lgeacy IVHD type(0x10), it is documented as feature
|
||||
* but in newer type it is attribute.
|
||||
*/
|
||||
softc->ivhd_feature = ivhd->Reserved;
|
||||
/*
|
||||
* PCI capability has more capabilities that are not part of IVRS.
|
||||
*/
|
||||
@ -439,6 +639,15 @@ ivhd_attach(device_t dev)
|
||||
/* IVHD Info bit[4:0] is event MSI/X number. */
|
||||
softc->event_msix = ivhd->Info & 0x1F;
|
||||
#endif
|
||||
switch (ivhd->Header.Type) {
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT1:
|
||||
case ACPI_IVRS_TYPE_HARDWARE_EXT2:
|
||||
ivhd1 = (ACPI_IVRS_HARDWARE_NEW *)ivhd;
|
||||
softc->ext_feature = ivhd1->ExtFR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress);
|
||||
status = ivhd_dev_parse(ivhd, softc);
|
||||
if (status != 0) {
|
||||
|
@ -444,6 +444,8 @@ typedef struct acpi_ivrs_header
|
||||
enum AcpiIvrsType
|
||||
{
|
||||
ACPI_IVRS_TYPE_HARDWARE = 0x10,
|
||||
ACPI_IVRS_TYPE_HARDWARE_EXT1 = 0x11,
|
||||
ACPI_IVRS_TYPE_HARDWARE_EXT2 = 0x40,
|
||||
ACPI_IVRS_TYPE_MEMORY1 = 0x20,
|
||||
ACPI_IVRS_TYPE_MEMORY2 = 0x21,
|
||||
ACPI_IVRS_TYPE_MEMORY3 = 0x22
|
||||
@ -482,6 +484,21 @@ typedef struct acpi_ivrs_hardware
|
||||
|
||||
} ACPI_IVRS_HARDWARE;
|
||||
|
||||
/* 0x11 and 0x40: I/O Virtualization Hardware Definition Block (IVHD) */
|
||||
|
||||
typedef struct acpi_ivrs_hardware_new
|
||||
{
|
||||
ACPI_IVRS_HEADER Header;
|
||||
UINT16 CapabilityOffset; /* Offset for IOMMU control fields */
|
||||
UINT64 BaseAddress; /* IOMMU control registers */
|
||||
UINT16 PciSegmentGroup;
|
||||
UINT16 Info; /* MSI number and unit ID */
|
||||
UINT32 Attr; /* IOMMU Feature */
|
||||
UINT64 ExtFR; /* IOMMU Extended Feature */
|
||||
UINT64 Reserved; /* v1 feature or v2 attribute */
|
||||
|
||||
} ACPI_IVRS_HARDWARE_NEW;
|
||||
|
||||
/* Masks for Info field above */
|
||||
|
||||
#define ACPI_IVHD_MSI_NUMBER_MASK 0x001F /* 5 bits, MSI message number */
|
||||
|
Loading…
x
Reference in New Issue
Block a user