Author: anish
Date: Fri Feb 16 05:17:00 2018
New Revision: 329360
URL: https://svnweb.freebsd.org/changeset/base/329360

Log:
  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

Modified:
  head/sys/amd64/vmm/amd/amdvi_hw.c
  head/sys/amd64/vmm/amd/amdvi_priv.h
  head/sys/amd64/vmm/amd/ivrs_drv.c
  head/sys/contrib/dev/acpica/include/actbl2.h

Modified: head/sys/amd64/vmm/amd/amdvi_hw.c
==============================================================================
--- head/sys/amd64/vmm/amd/amdvi_hw.c   Fri Feb 16 04:59:21 2018        
(r329359)
+++ head/sys/amd64/vmm/amd/amdvi_hw.c   Fri Feb 16 05:17:00 2018        
(r329360)
@@ -745,23 +745,8 @@ 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");
+           "\20\1IOTLB\2HT\3NPCache\4EFR\5CapExt");
 
-       /* 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);
-       }
-
        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

Modified: head/sys/amd64/vmm/amd/amdvi_priv.h
==============================================================================
--- head/sys/amd64/vmm/amd/amdvi_priv.h Fri Feb 16 04:59:21 2018        
(r329359)
+++ head/sys/amd64/vmm/amd/amdvi_priv.h Fri Feb 16 05:17:00 2018        
(r329360)
@@ -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. */

Modified: head/sys/amd64/vmm/amd/ivrs_drv.c
==============================================================================
--- head/sys/amd64/vmm/amd/ivrs_drv.c   Fri Feb 16 04:59:21 2018        
(r329359)
+++ head/sys/amd64/vmm/amd/ivrs_drv.c   Fri Feb 16 05:17:00 2018        
(r329360)
@@ -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
  * 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->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
        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,25 +345,41 @@ 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;
 
-       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;
+               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_hdrs[i];
+               KASSERT(ivhd, ("ivhd%d is NULL\n", i));
+
                /*
                 * Use a high order to ensure that this driver is probed after
                 * the Host-PCI bridge and the root PCI bus.
@@ -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_HA
        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,25 +605,32 @@ 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.
         */
        softc->cap_off = ivhd->CapabilityOffset;
@@ -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) {

Modified: head/sys/contrib/dev/acpica/include/actbl2.h
==============================================================================
--- head/sys/contrib/dev/acpica/include/actbl2.h        Fri Feb 16 04:59:21 
2018        (r329359)
+++ head/sys/contrib/dev/acpica/include/actbl2.h        Fri Feb 16 05:17:00 
2018        (r329360)
@@ -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
@@ -481,6 +483,21 @@ typedef struct acpi_ivrs_hardware
     UINT32                  Reserved;
 
 } 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 */
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to