17c8c0b82SPatrick Mooney /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
37c8c0b82SPatrick Mooney *
47c8c0b82SPatrick Mooney * Copyright (c) 2016, Anish Gupta (anish@freebsd.org)
57c8c0b82SPatrick Mooney * Copyright (c) 2021 The FreeBSD Foundation
67c8c0b82SPatrick Mooney * All rights reserved.
77c8c0b82SPatrick Mooney *
87c8c0b82SPatrick Mooney * Redistribution and use in source and binary forms, with or without
97c8c0b82SPatrick Mooney * modification, are permitted provided that the following conditions
107c8c0b82SPatrick Mooney * are met:
117c8c0b82SPatrick Mooney * 1. Redistributions of source code must retain the above copyright
127c8c0b82SPatrick Mooney * notice unmodified, this list of conditions, and the following
137c8c0b82SPatrick Mooney * disclaimer.
147c8c0b82SPatrick Mooney * 2. Redistributions in binary form must reproduce the above copyright
157c8c0b82SPatrick Mooney * notice, this list of conditions and the following disclaimer in the
167c8c0b82SPatrick Mooney * documentation and/or other materials provided with the distribution.
177c8c0b82SPatrick Mooney *
187c8c0b82SPatrick Mooney * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
197c8c0b82SPatrick Mooney * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
207c8c0b82SPatrick Mooney * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
217c8c0b82SPatrick Mooney * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
227c8c0b82SPatrick Mooney * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
237c8c0b82SPatrick Mooney * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
247c8c0b82SPatrick Mooney * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
257c8c0b82SPatrick Mooney * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
267c8c0b82SPatrick Mooney * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
277c8c0b82SPatrick Mooney * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287c8c0b82SPatrick Mooney */
297c8c0b82SPatrick Mooney
307c8c0b82SPatrick Mooney #include <sys/cdefs.h>
317c8c0b82SPatrick Mooney
327c8c0b82SPatrick Mooney #include "opt_acpi.h"
337c8c0b82SPatrick Mooney #include <sys/param.h>
347c8c0b82SPatrick Mooney #include <sys/bus.h>
357c8c0b82SPatrick Mooney #include <sys/kernel.h>
367c8c0b82SPatrick Mooney #include <sys/module.h>
377c8c0b82SPatrick Mooney #include <sys/malloc.h>
387c8c0b82SPatrick Mooney
397c8c0b82SPatrick Mooney #include <machine/vmparam.h>
407c8c0b82SPatrick Mooney
417c8c0b82SPatrick Mooney #include <contrib/dev/acpica/include/acpi.h>
427c8c0b82SPatrick Mooney #include <contrib/dev/acpica/include/accommon.h>
437c8c0b82SPatrick Mooney #include <dev/acpica/acpivar.h>
447c8c0b82SPatrick Mooney #include <dev/pci/pcireg.h>
457c8c0b82SPatrick Mooney #include <dev/pci/pcivar.h>
467c8c0b82SPatrick Mooney
477c8c0b82SPatrick Mooney #include "io/iommu.h"
487c8c0b82SPatrick Mooney #include "amdvi_priv.h"
497c8c0b82SPatrick Mooney
507c8c0b82SPatrick Mooney device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */
517c8c0b82SPatrick Mooney int ivhd_count; /* Number of IVHD header. */
527c8c0b82SPatrick Mooney /*
537c8c0b82SPatrick Mooney * Cached IVHD header list.
547c8c0b82SPatrick Mooney * Single entry for each IVHD, filtered the legacy one.
557c8c0b82SPatrick Mooney */
567c8c0b82SPatrick Mooney ACPI_IVRS_HARDWARE1 **ivhd_hdrs;
577c8c0b82SPatrick Mooney
587c8c0b82SPatrick Mooney extern int amdvi_ptp_level; /* Page table levels. */
597c8c0b82SPatrick Mooney
607c8c0b82SPatrick Mooney typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg);
617c8c0b82SPatrick Mooney /*
627c8c0b82SPatrick Mooney * Iterate IVRS table for IVHD and IVMD device type.
637c8c0b82SPatrick Mooney */
647c8c0b82SPatrick Mooney static void
ivrs_hdr_iterate_tbl(ivhd_iter_t iter,void * arg)657c8c0b82SPatrick Mooney ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg)
667c8c0b82SPatrick Mooney {
677c8c0b82SPatrick Mooney ACPI_TABLE_IVRS *ivrs;
687c8c0b82SPatrick Mooney ACPI_IVRS_HEADER *ivrs_hdr, *end;
697c8c0b82SPatrick Mooney ACPI_STATUS status;
707c8c0b82SPatrick Mooney
717c8c0b82SPatrick Mooney status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
727c8c0b82SPatrick Mooney if (ACPI_FAILURE(status))
737c8c0b82SPatrick Mooney return;
747c8c0b82SPatrick Mooney
757c8c0b82SPatrick Mooney if (ivrs->Header.Length == 0) {
767c8c0b82SPatrick Mooney return;
777c8c0b82SPatrick Mooney }
787c8c0b82SPatrick Mooney
797c8c0b82SPatrick Mooney ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1);
807c8c0b82SPatrick Mooney end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length);
817c8c0b82SPatrick Mooney
827c8c0b82SPatrick Mooney while (ivrs_hdr < end) {
837c8c0b82SPatrick Mooney if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) {
847c8c0b82SPatrick Mooney printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n",
857c8c0b82SPatrick Mooney ivrs_hdr->Length);
867c8c0b82SPatrick Mooney break;
877c8c0b82SPatrick Mooney }
887c8c0b82SPatrick Mooney
897c8c0b82SPatrick Mooney switch (ivrs_hdr->Type) {
907c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY: /* Legacy */
917c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
927c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
937c8c0b82SPatrick Mooney if (!iter(ivrs_hdr, arg))
947c8c0b82SPatrick Mooney return;
957c8c0b82SPatrick Mooney break;
967c8c0b82SPatrick Mooney
977c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_MEMORY1:
987c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_MEMORY2:
997c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_MEMORY3:
1007c8c0b82SPatrick Mooney if (!iter(ivrs_hdr, arg))
1017c8c0b82SPatrick Mooney return;
1027c8c0b82SPatrick Mooney
1037c8c0b82SPatrick Mooney break;
1047c8c0b82SPatrick Mooney
1057c8c0b82SPatrick Mooney default:
1067c8c0b82SPatrick Mooney printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type);
1077c8c0b82SPatrick Mooney }
1087c8c0b82SPatrick Mooney
1097c8c0b82SPatrick Mooney ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr +
1107c8c0b82SPatrick Mooney ivrs_hdr->Length);
1117c8c0b82SPatrick Mooney }
1127c8c0b82SPatrick Mooney }
1137c8c0b82SPatrick Mooney
1147c8c0b82SPatrick Mooney static bool
ivrs_is_ivhd(UINT8 type)1157c8c0b82SPatrick Mooney ivrs_is_ivhd(UINT8 type)
1167c8c0b82SPatrick Mooney {
1177c8c0b82SPatrick Mooney
1187c8c0b82SPatrick Mooney switch(type) {
1197c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY:
1207c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
1217c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
1227c8c0b82SPatrick Mooney return (true);
1237c8c0b82SPatrick Mooney
1247c8c0b82SPatrick Mooney default:
1257c8c0b82SPatrick Mooney return (false);
1267c8c0b82SPatrick Mooney }
1277c8c0b82SPatrick Mooney }
1287c8c0b82SPatrick Mooney
1297c8c0b82SPatrick Mooney /* Count the number of AMD-Vi devices in the system. */
1307c8c0b82SPatrick Mooney static int
ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he,void * arg)1317c8c0b82SPatrick Mooney ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg)
1327c8c0b82SPatrick Mooney {
1337c8c0b82SPatrick Mooney int *count;
1347c8c0b82SPatrick Mooney
1357c8c0b82SPatrick Mooney count = (int *)arg;
1367c8c0b82SPatrick Mooney if (ivrs_is_ivhd(ivrs_he->Type))
1377c8c0b82SPatrick Mooney (*count)++;
1387c8c0b82SPatrick Mooney
1397c8c0b82SPatrick Mooney return (1);
1407c8c0b82SPatrick Mooney }
1417c8c0b82SPatrick Mooney
1427c8c0b82SPatrick Mooney struct find_ivrs_hdr_args {
1437c8c0b82SPatrick Mooney int i;
1447c8c0b82SPatrick Mooney ACPI_IVRS_HEADER *ptr;
1457c8c0b82SPatrick Mooney };
1467c8c0b82SPatrick Mooney
1477c8c0b82SPatrick Mooney static int
ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr,void * args)1487c8c0b82SPatrick Mooney ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args)
1497c8c0b82SPatrick Mooney {
1507c8c0b82SPatrick Mooney struct find_ivrs_hdr_args *fi;
1517c8c0b82SPatrick Mooney
1527c8c0b82SPatrick Mooney fi = (struct find_ivrs_hdr_args *)args;
1537c8c0b82SPatrick Mooney if (ivrs_is_ivhd(ivrs_hdr->Type)) {
1547c8c0b82SPatrick Mooney if (fi->i == 0) {
1557c8c0b82SPatrick Mooney fi->ptr = ivrs_hdr;
1567c8c0b82SPatrick Mooney return (0);
1577c8c0b82SPatrick Mooney }
1587c8c0b82SPatrick Mooney fi->i--;
1597c8c0b82SPatrick Mooney }
1607c8c0b82SPatrick Mooney
1617c8c0b82SPatrick Mooney return (1);
1627c8c0b82SPatrick Mooney }
1637c8c0b82SPatrick Mooney
1647c8c0b82SPatrick Mooney static ACPI_IVRS_HARDWARE1 *
ivhd_find_by_index(int idx)1657c8c0b82SPatrick Mooney ivhd_find_by_index(int idx)
1667c8c0b82SPatrick Mooney {
1677c8c0b82SPatrick Mooney struct find_ivrs_hdr_args fi;
1687c8c0b82SPatrick Mooney
1697c8c0b82SPatrick Mooney fi.i = idx;
1707c8c0b82SPatrick Mooney fi.ptr = NULL;
1717c8c0b82SPatrick Mooney
1727c8c0b82SPatrick Mooney ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi);
1737c8c0b82SPatrick Mooney
1747c8c0b82SPatrick Mooney return ((ACPI_IVRS_HARDWARE1 *)fi.ptr);
1757c8c0b82SPatrick Mooney }
1767c8c0b82SPatrick Mooney
1777c8c0b82SPatrick Mooney static void
ivhd_dev_add_entry(struct amdvi_softc * softc,uint32_t start_id,uint32_t end_id,uint8_t cfg,bool ats)1787c8c0b82SPatrick Mooney ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id,
1797c8c0b82SPatrick Mooney uint32_t end_id, uint8_t cfg, bool ats)
1807c8c0b82SPatrick Mooney {
1817c8c0b82SPatrick Mooney struct ivhd_dev_cfg *dev_cfg;
1827c8c0b82SPatrick Mooney
1837c8c0b82SPatrick Mooney KASSERT(softc->dev_cfg_cap >= softc->dev_cfg_cnt,
1847c8c0b82SPatrick Mooney ("Impossible case: number of dev_cfg exceeding capacity"));
1857c8c0b82SPatrick Mooney if (softc->dev_cfg_cap == softc->dev_cfg_cnt) {
1867c8c0b82SPatrick Mooney if (softc->dev_cfg_cap == 0)
1877c8c0b82SPatrick Mooney softc->dev_cfg_cap = 1;
1887c8c0b82SPatrick Mooney else
1897c8c0b82SPatrick Mooney softc->dev_cfg_cap <<= 2;
1907c8c0b82SPatrick Mooney softc->dev_cfg = realloc(softc->dev_cfg,
1917c8c0b82SPatrick Mooney sizeof(*softc->dev_cfg) * softc->dev_cfg_cap, M_DEVBUF,
1927c8c0b82SPatrick Mooney M_WAITOK);
1937c8c0b82SPatrick Mooney }
1947c8c0b82SPatrick Mooney
1957c8c0b82SPatrick Mooney dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++];
1967c8c0b82SPatrick Mooney dev_cfg->start_id = start_id;
1977c8c0b82SPatrick Mooney dev_cfg->end_id = end_id;
1987c8c0b82SPatrick Mooney dev_cfg->data = cfg;
1997c8c0b82SPatrick Mooney dev_cfg->enable_ats = ats;
2007c8c0b82SPatrick Mooney }
2017c8c0b82SPatrick Mooney
2027c8c0b82SPatrick Mooney /*
2037c8c0b82SPatrick Mooney * Record device attributes as suggested by BIOS.
2047c8c0b82SPatrick Mooney */
2057c8c0b82SPatrick Mooney static int
ivhd_dev_parse(ACPI_IVRS_HARDWARE1 * ivhd,struct amdvi_softc * softc)2067c8c0b82SPatrick Mooney ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc)
2077c8c0b82SPatrick Mooney {
2087c8c0b82SPatrick Mooney ACPI_IVRS_DE_HEADER *de;
2097c8c0b82SPatrick Mooney uint8_t *p, *end;
2107c8c0b82SPatrick Mooney int range_start_id = -1, range_end_id = -1, i;
2117c8c0b82SPatrick Mooney uint32_t *extended;
2127c8c0b82SPatrick Mooney uint8_t all_data = 0, range_data = 0;
2137c8c0b82SPatrick Mooney bool range_enable_ats = false, enable_ats;
2147c8c0b82SPatrick Mooney
2157c8c0b82SPatrick Mooney switch (ivhd->Header.Type) {
2167c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY:
2177c8c0b82SPatrick Mooney p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1);
2187c8c0b82SPatrick Mooney break;
2197c8c0b82SPatrick Mooney
2207c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
2217c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
2227c8c0b82SPatrick Mooney p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2);
2237c8c0b82SPatrick Mooney break;
2247c8c0b82SPatrick Mooney
2257c8c0b82SPatrick Mooney default:
2267c8c0b82SPatrick Mooney device_printf(softc->dev,
2277c8c0b82SPatrick Mooney "unknown type: 0x%x\n", ivhd->Header.Type);
2287c8c0b82SPatrick Mooney return (-1);
2297c8c0b82SPatrick Mooney }
2307c8c0b82SPatrick Mooney
2317c8c0b82SPatrick Mooney end = (uint8_t *)ivhd + ivhd->Header.Length;
2327c8c0b82SPatrick Mooney
2337c8c0b82SPatrick Mooney while (p < end) {
2347c8c0b82SPatrick Mooney de = (ACPI_IVRS_DE_HEADER *)p;
2357c8c0b82SPatrick Mooney switch (de->Type) {
2367c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_ALL:
2377c8c0b82SPatrick Mooney all_data = de->DataSetting;
2387c8c0b82SPatrick Mooney for (i = 0; i < softc->dev_cfg_cnt; i++)
2397c8c0b82SPatrick Mooney softc->dev_cfg[i].data |= all_data;
2407c8c0b82SPatrick Mooney break;
2417c8c0b82SPatrick Mooney
2427c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_SELECT:
2437c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_ALIAS_SELECT:
2447c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_EXT_SELECT:
2457c8c0b82SPatrick Mooney enable_ats = false;
2467c8c0b82SPatrick Mooney if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
2477c8c0b82SPatrick Mooney extended = (uint32_t *)(de + 1);
2487c8c0b82SPatrick Mooney enable_ats =
2497c8c0b82SPatrick Mooney (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
2507c8c0b82SPatrick Mooney false : true;
2517c8c0b82SPatrick Mooney }
2527c8c0b82SPatrick Mooney ivhd_dev_add_entry(softc, de->Id, de->Id,
2537c8c0b82SPatrick Mooney de->DataSetting | all_data, enable_ats);
2547c8c0b82SPatrick Mooney break;
2557c8c0b82SPatrick Mooney
2567c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_START:
2577c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_ALIAS_START:
2587c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_EXT_START:
2597c8c0b82SPatrick Mooney if (range_start_id != -1) {
2607c8c0b82SPatrick Mooney device_printf(softc->dev,
2617c8c0b82SPatrick Mooney "Unexpected start-of-range device entry\n");
2627c8c0b82SPatrick Mooney return (EINVAL);
2637c8c0b82SPatrick Mooney }
2647c8c0b82SPatrick Mooney range_start_id = de->Id;
2657c8c0b82SPatrick Mooney range_data = de->DataSetting;
2667c8c0b82SPatrick Mooney if (de->Type == ACPI_IVRS_TYPE_EXT_START) {
2677c8c0b82SPatrick Mooney extended = (uint32_t *)(de + 1);
2687c8c0b82SPatrick Mooney range_enable_ats =
2697c8c0b82SPatrick Mooney (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
2707c8c0b82SPatrick Mooney false : true;
2717c8c0b82SPatrick Mooney }
2727c8c0b82SPatrick Mooney break;
2737c8c0b82SPatrick Mooney
2747c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_END:
2757c8c0b82SPatrick Mooney if (range_start_id == -1) {
2767c8c0b82SPatrick Mooney device_printf(softc->dev,
2777c8c0b82SPatrick Mooney "Unexpected end-of-range device entry\n");
2787c8c0b82SPatrick Mooney return (EINVAL);
2797c8c0b82SPatrick Mooney }
2807c8c0b82SPatrick Mooney range_end_id = de->Id;
2817c8c0b82SPatrick Mooney if (range_end_id < range_start_id) {
2827c8c0b82SPatrick Mooney device_printf(softc->dev,
2837c8c0b82SPatrick Mooney "Device entry range going backward\n");
2847c8c0b82SPatrick Mooney return (EINVAL);
2857c8c0b82SPatrick Mooney }
2867c8c0b82SPatrick Mooney ivhd_dev_add_entry(softc, range_start_id, range_end_id,
2877c8c0b82SPatrick Mooney range_data | all_data, range_enable_ats);
2887c8c0b82SPatrick Mooney range_start_id = range_end_id = -1;
2897c8c0b82SPatrick Mooney range_data = 0;
2907c8c0b82SPatrick Mooney all_data = 0;
2917c8c0b82SPatrick Mooney break;
2927c8c0b82SPatrick Mooney
2937c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_PAD4:
2947c8c0b82SPatrick Mooney break;
2957c8c0b82SPatrick Mooney
2967c8c0b82SPatrick Mooney case ACPI_IVRS_TYPE_SPECIAL:
2977c8c0b82SPatrick Mooney /* HPET or IOAPIC */
2987c8c0b82SPatrick Mooney break;
2997c8c0b82SPatrick Mooney default:
3007c8c0b82SPatrick Mooney if ((de->Type < 5) ||
3017c8c0b82SPatrick Mooney (de->Type >= ACPI_IVRS_TYPE_PAD8))
3027c8c0b82SPatrick Mooney device_printf(softc->dev,
3037c8c0b82SPatrick Mooney "Unknown dev entry:0x%x\n", de->Type);
3047c8c0b82SPatrick Mooney }
3057c8c0b82SPatrick Mooney
3067c8c0b82SPatrick Mooney if (de->Type < 0x40)
3077c8c0b82SPatrick Mooney p += sizeof(ACPI_IVRS_DEVICE4);
3087c8c0b82SPatrick Mooney else if (de->Type < 0x80)
3097c8c0b82SPatrick Mooney p += sizeof(ACPI_IVRS_DEVICE8A);
3107c8c0b82SPatrick Mooney else {
3117c8c0b82SPatrick Mooney printf("Variable size IVHD type 0x%x not supported\n",
3127c8c0b82SPatrick Mooney de->Type);
3137c8c0b82SPatrick Mooney break;
3147c8c0b82SPatrick Mooney }
3157c8c0b82SPatrick Mooney }
3167c8c0b82SPatrick Mooney
3177c8c0b82SPatrick Mooney return (0);
3187c8c0b82SPatrick Mooney }
3197c8c0b82SPatrick Mooney
3207c8c0b82SPatrick Mooney static bool
ivhd_is_newer(ACPI_IVRS_HEADER * old,ACPI_IVRS_HEADER * new)3217c8c0b82SPatrick Mooney ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new)
3227c8c0b82SPatrick Mooney {
3237c8c0b82SPatrick Mooney if (old->DeviceId == new->DeviceId) {
3247c8c0b82SPatrick Mooney /*
3257c8c0b82SPatrick Mooney * Newer IVRS header type take precedence.
3267c8c0b82SPatrick Mooney */
3277c8c0b82SPatrick Mooney if (old->Type == IVRS_TYPE_HARDWARE_LEGACY &&
3287c8c0b82SPatrick Mooney ((new->Type == IVRS_TYPE_HARDWARE_EFR) ||
3297c8c0b82SPatrick Mooney (new->Type == IVRS_TYPE_HARDWARE_MIXED)))
3307c8c0b82SPatrick Mooney return (true);
3317c8c0b82SPatrick Mooney
3327c8c0b82SPatrick Mooney /*
3337c8c0b82SPatrick Mooney * Mixed format IVHD header type take precedence
3347c8c0b82SPatrick Mooney * over fixed format IVHD header types.
3357c8c0b82SPatrick Mooney */
3367c8c0b82SPatrick Mooney if (old->Type == IVRS_TYPE_HARDWARE_EFR &&
3377c8c0b82SPatrick Mooney new->Type == IVRS_TYPE_HARDWARE_MIXED)
3387c8c0b82SPatrick Mooney return (true);
3397c8c0b82SPatrick Mooney }
3407c8c0b82SPatrick Mooney
3417c8c0b82SPatrick Mooney return (false);
3427c8c0b82SPatrick Mooney }
3437c8c0b82SPatrick Mooney
3447c8c0b82SPatrick Mooney static void
ivhd_identify(driver_t * driver,device_t parent)3457c8c0b82SPatrick Mooney ivhd_identify(driver_t *driver, device_t parent)
3467c8c0b82SPatrick Mooney {
3477c8c0b82SPatrick Mooney ACPI_TABLE_IVRS *ivrs;
3487c8c0b82SPatrick Mooney ACPI_IVRS_HARDWARE1 *ivhd;
3497c8c0b82SPatrick Mooney ACPI_STATUS status;
3507c8c0b82SPatrick Mooney int i, j, count = 0;
3517c8c0b82SPatrick Mooney uint32_t ivrs_ivinfo;
3527c8c0b82SPatrick Mooney
3537c8c0b82SPatrick Mooney if (acpi_disabled("ivhd"))
3547c8c0b82SPatrick Mooney return;
3557c8c0b82SPatrick Mooney
3567c8c0b82SPatrick Mooney status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
3577c8c0b82SPatrick Mooney if (ACPI_FAILURE(status))
3587c8c0b82SPatrick Mooney return;
3597c8c0b82SPatrick Mooney
3607c8c0b82SPatrick Mooney if (ivrs->Header.Length == 0) {
3617c8c0b82SPatrick Mooney return;
3627c8c0b82SPatrick Mooney }
3637c8c0b82SPatrick Mooney
3647c8c0b82SPatrick Mooney ivrs_ivinfo = ivrs->Info;
3657c8c0b82SPatrick Mooney printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d"
3667c8c0b82SPatrick Mooney " flags:%b\n",
3677c8c0b82SPatrick Mooney REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8),
3687c8c0b82SPatrick Mooney REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
3697c8c0b82SPatrick Mooney "\020\001EFRSup");
3707c8c0b82SPatrick Mooney
3717c8c0b82SPatrick Mooney ivrs_hdr_iterate_tbl(ivhd_count_iter, &count);
3727c8c0b82SPatrick Mooney if (!count)
3737c8c0b82SPatrick Mooney return;
3747c8c0b82SPatrick Mooney
3757c8c0b82SPatrick Mooney ivhd_hdrs = kmem_zalloc(sizeof(void *) * count, KM_SLEEP);
3767c8c0b82SPatrick Mooney for (i = 0; i < count; i++) {
3777c8c0b82SPatrick Mooney ivhd = ivhd_find_by_index(i);
3787c8c0b82SPatrick Mooney KASSERT(ivhd, ("ivhd%d is NULL\n", i));
3797c8c0b82SPatrick Mooney
3807c8c0b82SPatrick Mooney /*
3817c8c0b82SPatrick Mooney * Scan for presence of legacy and non-legacy device type
3827c8c0b82SPatrick Mooney * for same IOMMU device and override the old one.
3837c8c0b82SPatrick Mooney *
3847c8c0b82SPatrick Mooney * If there is no existing IVHD to the same IOMMU device,
3857c8c0b82SPatrick Mooney * the IVHD header pointer is appended.
3867c8c0b82SPatrick Mooney */
3877c8c0b82SPatrick Mooney for (j = 0; j < ivhd_count; j++) {
3887c8c0b82SPatrick Mooney if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header))
3897c8c0b82SPatrick Mooney break;
3907c8c0b82SPatrick Mooney }
3917c8c0b82SPatrick Mooney ivhd_hdrs[j] = ivhd;
3927c8c0b82SPatrick Mooney if (j == ivhd_count)
3937c8c0b82SPatrick Mooney ivhd_count++;
3947c8c0b82SPatrick Mooney }
3957c8c0b82SPatrick Mooney
3967c8c0b82SPatrick Mooney ivhd_devs = kmem_zalloc(sizeof(device_t) * ivhd_count, KM_SLEEP);
3977c8c0b82SPatrick Mooney for (i = 0, j = 0; i < ivhd_count; i++) {
3987c8c0b82SPatrick Mooney ivhd = ivhd_hdrs[i];
3997c8c0b82SPatrick Mooney KASSERT(ivhd, ("ivhd%d is NULL\n", i));
4007c8c0b82SPatrick Mooney
4017c8c0b82SPatrick Mooney /*
4027c8c0b82SPatrick Mooney * Use a high order to ensure that this driver is probed after
4037c8c0b82SPatrick Mooney * the Host-PCI bridge and the root PCI bus.
4047c8c0b82SPatrick Mooney */
4057c8c0b82SPatrick Mooney ivhd_devs[i] = BUS_ADD_CHILD(parent,
4067c8c0b82SPatrick Mooney ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i);
4077c8c0b82SPatrick Mooney
4087c8c0b82SPatrick Mooney /*
4097c8c0b82SPatrick Mooney * XXX: In case device was not destroyed before, add will fail.
4107c8c0b82SPatrick Mooney * locate the old device instance.
4117c8c0b82SPatrick Mooney */
4127c8c0b82SPatrick Mooney if (ivhd_devs[i] == NULL) {
4137c8c0b82SPatrick Mooney ivhd_devs[i] = device_find_child(parent, "ivhd", i);
4147c8c0b82SPatrick Mooney if (ivhd_devs[i] == NULL) {
4157c8c0b82SPatrick Mooney printf("AMD-Vi: cant find ivhd%d\n", i);
4167c8c0b82SPatrick Mooney break;
4177c8c0b82SPatrick Mooney }
4187c8c0b82SPatrick Mooney }
4197c8c0b82SPatrick Mooney j++;
4207c8c0b82SPatrick Mooney }
4217c8c0b82SPatrick Mooney
4227c8c0b82SPatrick Mooney /*
4237c8c0b82SPatrick Mooney * Update device count in case failed to attach.
4247c8c0b82SPatrick Mooney */
4257c8c0b82SPatrick Mooney ivhd_count = j;
4267c8c0b82SPatrick Mooney }
4277c8c0b82SPatrick Mooney
4287c8c0b82SPatrick Mooney static int
ivhd_probe(device_t dev)4297c8c0b82SPatrick Mooney ivhd_probe(device_t dev)
4307c8c0b82SPatrick Mooney {
4317c8c0b82SPatrick Mooney ACPI_IVRS_HARDWARE1 *ivhd;
4327c8c0b82SPatrick Mooney int unit;
4337c8c0b82SPatrick Mooney
4347c8c0b82SPatrick Mooney if (acpi_get_handle(dev) != NULL)
4357c8c0b82SPatrick Mooney return (ENXIO);
4367c8c0b82SPatrick Mooney
4377c8c0b82SPatrick Mooney unit = device_get_unit(dev);
4387c8c0b82SPatrick Mooney KASSERT((unit < ivhd_count),
4397c8c0b82SPatrick Mooney ("ivhd unit %d > count %d", unit, ivhd_count));
4407c8c0b82SPatrick Mooney ivhd = ivhd_hdrs[unit];
4417c8c0b82SPatrick Mooney KASSERT(ivhd, ("ivhd is NULL"));
4427c8c0b82SPatrick Mooney
4437c8c0b82SPatrick Mooney switch (ivhd->Header.Type) {
4447c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
4457c8c0b82SPatrick Mooney device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR");
4467c8c0b82SPatrick Mooney break;
4477c8c0b82SPatrick Mooney
4487c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
4497c8c0b82SPatrick Mooney device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format");
4507c8c0b82SPatrick Mooney break;
4517c8c0b82SPatrick Mooney
4527c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY:
4537c8c0b82SPatrick Mooney default:
4547c8c0b82SPatrick Mooney device_set_desc(dev, "AMD-Vi/IOMMU ivhd");
4557c8c0b82SPatrick Mooney break;
4567c8c0b82SPatrick Mooney }
4577c8c0b82SPatrick Mooney
4587c8c0b82SPatrick Mooney return (BUS_PROBE_NOWILDCARD);
4597c8c0b82SPatrick Mooney }
4607c8c0b82SPatrick Mooney
4617c8c0b82SPatrick Mooney static void
ivhd_print_flag(device_t dev,enum IvrsType ivhd_type,uint8_t flag)4627c8c0b82SPatrick Mooney ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag)
4637c8c0b82SPatrick Mooney {
4647c8c0b82SPatrick Mooney /*
4657c8c0b82SPatrick Mooney * IVHD lgeacy type has two extra high bits in flag which has
4667c8c0b82SPatrick Mooney * been moved to EFR for non-legacy device.
4677c8c0b82SPatrick Mooney */
4687c8c0b82SPatrick Mooney switch (ivhd_type) {
4697c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY:
4707c8c0b82SPatrick Mooney device_printf(dev, "Flag:%b\n", flag,
4717c8c0b82SPatrick Mooney "\020"
4727c8c0b82SPatrick Mooney "\001HtTunEn"
4737c8c0b82SPatrick Mooney "\002PassPW"
4747c8c0b82SPatrick Mooney "\003ResPassPW"
4757c8c0b82SPatrick Mooney "\004Isoc"
4767c8c0b82SPatrick Mooney "\005IotlbSup"
4777c8c0b82SPatrick Mooney "\006Coherent"
4787c8c0b82SPatrick Mooney "\007PreFSup"
4797c8c0b82SPatrick Mooney "\010PPRSup");
4807c8c0b82SPatrick Mooney break;
4817c8c0b82SPatrick Mooney
4827c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
4837c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
4847c8c0b82SPatrick Mooney device_printf(dev, "Flag:%b\n", flag,
4857c8c0b82SPatrick Mooney "\020"
4867c8c0b82SPatrick Mooney "\001HtTunEn"
4877c8c0b82SPatrick Mooney "\002PassPW"
4887c8c0b82SPatrick Mooney "\003ResPassPW"
4897c8c0b82SPatrick Mooney "\004Isoc"
4907c8c0b82SPatrick Mooney "\005IotlbSup"
4917c8c0b82SPatrick Mooney "\006Coherent");
4927c8c0b82SPatrick Mooney break;
4937c8c0b82SPatrick Mooney
4947c8c0b82SPatrick Mooney default:
4957c8c0b82SPatrick Mooney device_printf(dev, "Can't decode flag of ivhd type :0x%x\n",
4967c8c0b82SPatrick Mooney ivhd_type);
4977c8c0b82SPatrick Mooney break;
4987c8c0b82SPatrick Mooney }
4997c8c0b82SPatrick Mooney }
5007c8c0b82SPatrick Mooney
5017c8c0b82SPatrick Mooney /*
5027c8c0b82SPatrick Mooney * Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40).
5037c8c0b82SPatrick Mooney */
5047c8c0b82SPatrick Mooney static void
ivhd_print_feature(device_t dev,enum IvrsType ivhd_type,uint32_t feature)5057c8c0b82SPatrick Mooney ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature)
5067c8c0b82SPatrick Mooney {
5077c8c0b82SPatrick Mooney switch (ivhd_type) {
5087c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_LEGACY:
5097c8c0b82SPatrick Mooney device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d"
5107c8c0b82SPatrick Mooney " MsiNumPPR = %d PNBanks= %d PNCounters= %d\n",
5117c8c0b82SPatrick Mooney ivhd_type,
5127c8c0b82SPatrick Mooney REG_BITS(feature, 31, 30),
5137c8c0b82SPatrick Mooney REG_BITS(feature, 29, 28),
5147c8c0b82SPatrick Mooney REG_BITS(feature, 27, 23),
5157c8c0b82SPatrick Mooney REG_BITS(feature, 22, 17),
5167c8c0b82SPatrick Mooney REG_BITS(feature, 16, 13));
5177c8c0b82SPatrick Mooney device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n",
5187c8c0b82SPatrick Mooney REG_BITS(feature, 12, 8),
5197c8c0b82SPatrick Mooney REG_BITS(feature, 4, 3),
5207c8c0b82SPatrick Mooney feature,
5217c8c0b82SPatrick Mooney "\020"
5227c8c0b82SPatrick Mooney "\002NXSup"
5237c8c0b82SPatrick Mooney "\003GTSup"
5247c8c0b82SPatrick Mooney "\004<b4>"
5257c8c0b82SPatrick Mooney "\005IASup"
5267c8c0b82SPatrick Mooney "\006GASup"
5277c8c0b82SPatrick Mooney "\007HESup");
5287c8c0b82SPatrick Mooney break;
5297c8c0b82SPatrick Mooney
5307c8c0b82SPatrick Mooney /* Fewer features or attributes are reported in non-legacy type. */
5317c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
5327c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
5337c8c0b82SPatrick Mooney device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d"
5347c8c0b82SPatrick Mooney " PNBanks= %d PNCounters= %d\n",
5357c8c0b82SPatrick Mooney ivhd_type,
5367c8c0b82SPatrick Mooney REG_BITS(feature, 27, 23),
5377c8c0b82SPatrick Mooney REG_BITS(feature, 22, 17),
5387c8c0b82SPatrick Mooney REG_BITS(feature, 16, 13));
5397c8c0b82SPatrick Mooney break;
5407c8c0b82SPatrick Mooney
5417c8c0b82SPatrick Mooney default: /* Other ivhd type features are not decoded. */
5427c8c0b82SPatrick Mooney device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type);
5437c8c0b82SPatrick Mooney }
5447c8c0b82SPatrick Mooney }
5457c8c0b82SPatrick Mooney
5467c8c0b82SPatrick Mooney /* Print extended features of IOMMU. */
5477c8c0b82SPatrick Mooney static void
ivhd_print_ext_feature(device_t dev,uint64_t ext_feature)5487c8c0b82SPatrick Mooney ivhd_print_ext_feature(device_t dev, uint64_t ext_feature)
5497c8c0b82SPatrick Mooney {
5507c8c0b82SPatrick Mooney uint32_t ext_low, ext_high;
5517c8c0b82SPatrick Mooney
5527c8c0b82SPatrick Mooney if (!ext_feature)
5537c8c0b82SPatrick Mooney return;
5547c8c0b82SPatrick Mooney
5557c8c0b82SPatrick Mooney ext_low = ext_feature;
5567c8c0b82SPatrick Mooney device_printf(dev, "Extended features[31:0]:%b "
5577c8c0b82SPatrick Mooney "HATS = 0x%x GATS = 0x%x "
5587c8c0b82SPatrick Mooney "GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x "
5597c8c0b82SPatrick Mooney "GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n",
5607c8c0b82SPatrick Mooney (int)ext_low,
5617c8c0b82SPatrick Mooney "\020"
5627c8c0b82SPatrick Mooney "\001PreFSup"
5637c8c0b82SPatrick Mooney "\002PPRSup"
5647c8c0b82SPatrick Mooney "\003<b2>"
5657c8c0b82SPatrick Mooney "\004NXSup"
5667c8c0b82SPatrick Mooney "\005GTSup"
5677c8c0b82SPatrick Mooney "\006<b5>"
5687c8c0b82SPatrick Mooney "\007IASup"
5697c8c0b82SPatrick Mooney "\010GASup"
5707c8c0b82SPatrick Mooney "\011HESup"
5717c8c0b82SPatrick Mooney "\012PCSup",
5727c8c0b82SPatrick Mooney REG_BITS(ext_low, 11, 10),
5737c8c0b82SPatrick Mooney REG_BITS(ext_low, 13, 12),
5747c8c0b82SPatrick Mooney REG_BITS(ext_low, 15, 14),
5757c8c0b82SPatrick Mooney REG_BITS(ext_low, 17, 16),
5767c8c0b82SPatrick Mooney REG_BITS(ext_low, 20, 18),
5777c8c0b82SPatrick Mooney REG_BITS(ext_low, 23, 21),
5787c8c0b82SPatrick Mooney REG_BITS(ext_low, 25, 24),
5797c8c0b82SPatrick Mooney REG_BITS(ext_low, 29, 28));
5807c8c0b82SPatrick Mooney
5817c8c0b82SPatrick Mooney ext_high = ext_feature >> 32;
5827c8c0b82SPatrick Mooney device_printf(dev, "Extended features[62:32]:%b "
5837c8c0b82SPatrick Mooney "Max PASID: 0x%x DevTblSegSup = 0x%x "
5847c8c0b82SPatrick Mooney "MarcSup = 0x%x\n",
5857c8c0b82SPatrick Mooney (int)(ext_high),
5867c8c0b82SPatrick Mooney "\020"
5877c8c0b82SPatrick Mooney "\006USSup"
5887c8c0b82SPatrick Mooney "\011PprOvrflwEarlySup"
5897c8c0b82SPatrick Mooney "\012PPRAutoRspSup"
5907c8c0b82SPatrick Mooney "\015BlKStopMrkSup"
5917c8c0b82SPatrick Mooney "\016PerfOptSup"
5927c8c0b82SPatrick Mooney "\017MsiCapMmioSup"
5937c8c0b82SPatrick Mooney "\021GIOSup"
5947c8c0b82SPatrick Mooney "\022HASup"
5957c8c0b82SPatrick Mooney "\023EPHSup"
5967c8c0b82SPatrick Mooney "\024AttrFWSup"
5977c8c0b82SPatrick Mooney "\025HDSup"
5987c8c0b82SPatrick Mooney "\027InvIotlbSup",
5997c8c0b82SPatrick Mooney REG_BITS(ext_high, 5, 0),
6007c8c0b82SPatrick Mooney REG_BITS(ext_high, 8, 7),
6017c8c0b82SPatrick Mooney REG_BITS(ext_high, 11, 10));
6027c8c0b82SPatrick Mooney }
6037c8c0b82SPatrick Mooney
6047c8c0b82SPatrick Mooney static int
ivhd_print_cap(struct amdvi_softc * softc,ACPI_IVRS_HARDWARE1 * ivhd)6057c8c0b82SPatrick Mooney ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd)
6067c8c0b82SPatrick Mooney {
6077c8c0b82SPatrick Mooney device_t dev;
6087c8c0b82SPatrick Mooney int max_ptp_level;
6097c8c0b82SPatrick Mooney
6107c8c0b82SPatrick Mooney dev = softc->dev;
6117c8c0b82SPatrick Mooney
6127c8c0b82SPatrick Mooney ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag);
6137c8c0b82SPatrick Mooney ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature);
6147c8c0b82SPatrick Mooney ivhd_print_ext_feature(dev, softc->ext_feature);
6157c8c0b82SPatrick Mooney max_ptp_level = 7;
6167c8c0b82SPatrick Mooney /* Make sure device support minimum page level as requested by user. */
6177c8c0b82SPatrick Mooney if (max_ptp_level < amdvi_ptp_level) {
6187c8c0b82SPatrick Mooney device_printf(dev, "insufficient PTP level:%d\n",
6197c8c0b82SPatrick Mooney max_ptp_level);
6207c8c0b82SPatrick Mooney return (EINVAL);
6217c8c0b82SPatrick Mooney } else {
6227c8c0b82SPatrick Mooney device_printf(softc->dev, "supported paging level:%d, will use only: %d\n",
6237c8c0b82SPatrick Mooney max_ptp_level, amdvi_ptp_level);
6247c8c0b82SPatrick Mooney }
6257c8c0b82SPatrick Mooney
6267c8c0b82SPatrick Mooney return (0);
6277c8c0b82SPatrick Mooney }
6287c8c0b82SPatrick Mooney
6297c8c0b82SPatrick Mooney static int
ivhd_attach(device_t dev)6307c8c0b82SPatrick Mooney ivhd_attach(device_t dev)
6317c8c0b82SPatrick Mooney {
6327c8c0b82SPatrick Mooney ACPI_IVRS_HARDWARE1 *ivhd;
6337c8c0b82SPatrick Mooney ACPI_IVRS_HARDWARE2 *ivhd_efr;
6347c8c0b82SPatrick Mooney struct amdvi_softc *softc;
6357c8c0b82SPatrick Mooney int status, unit;
6367c8c0b82SPatrick Mooney
6377c8c0b82SPatrick Mooney unit = device_get_unit(dev);
6387c8c0b82SPatrick Mooney KASSERT((unit < ivhd_count),
6397c8c0b82SPatrick Mooney ("ivhd unit %d > count %d", unit, ivhd_count));
6407c8c0b82SPatrick Mooney /* Make sure its same device for which attach is called. */
6417c8c0b82SPatrick Mooney KASSERT((ivhd_devs[unit] == dev),
6427c8c0b82SPatrick Mooney ("Not same device old %p new %p", ivhd_devs[unit], dev));
6437c8c0b82SPatrick Mooney
6447c8c0b82SPatrick Mooney softc = device_get_softc(dev);
6457c8c0b82SPatrick Mooney softc->dev = dev;
6467c8c0b82SPatrick Mooney ivhd = ivhd_hdrs[unit];
6477c8c0b82SPatrick Mooney KASSERT(ivhd, ("ivhd is NULL"));
6487c8c0b82SPatrick Mooney softc->pci_dev = pci_find_bsf(PCI_RID2BUS(ivhd->Header.DeviceId),
6497c8c0b82SPatrick Mooney PCI_RID2SLOT(ivhd->Header.DeviceId),
6507c8c0b82SPatrick Mooney PCI_RID2FUNC(ivhd->Header.DeviceId));
6517c8c0b82SPatrick Mooney
6527c8c0b82SPatrick Mooney softc->ivhd_type = ivhd->Header.Type;
6537c8c0b82SPatrick Mooney softc->pci_seg = ivhd->PciSegmentGroup;
6547c8c0b82SPatrick Mooney softc->pci_rid = ivhd->Header.DeviceId;
6557c8c0b82SPatrick Mooney softc->ivhd_flag = ivhd->Header.Flags;
6567c8c0b82SPatrick Mooney /*
6577c8c0b82SPatrick Mooney * On lgeacy IVHD type(0x10), it is documented as feature
6587c8c0b82SPatrick Mooney * but in newer type it is attribute.
6597c8c0b82SPatrick Mooney */
6607c8c0b82SPatrick Mooney softc->ivhd_feature = ivhd->FeatureReporting;
6617c8c0b82SPatrick Mooney /*
6627c8c0b82SPatrick Mooney * PCI capability has more capabilities that are not part of IVRS.
6637c8c0b82SPatrick Mooney */
6647c8c0b82SPatrick Mooney softc->cap_off = ivhd->CapabilityOffset;
6657c8c0b82SPatrick Mooney
6667c8c0b82SPatrick Mooney #ifdef notyet
6677c8c0b82SPatrick Mooney /* IVHD Info bit[4:0] is event MSI/X number. */
6687c8c0b82SPatrick Mooney softc->event_msix = ivhd->Info & 0x1F;
6697c8c0b82SPatrick Mooney #endif
6707c8c0b82SPatrick Mooney switch (ivhd->Header.Type) {
6717c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_EFR:
6727c8c0b82SPatrick Mooney case IVRS_TYPE_HARDWARE_MIXED:
6737c8c0b82SPatrick Mooney ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd;
6747c8c0b82SPatrick Mooney softc->ext_feature = ivhd_efr->EfrRegisterImage;
6757c8c0b82SPatrick Mooney break;
6767c8c0b82SPatrick Mooney }
6777c8c0b82SPatrick Mooney
6787c8c0b82SPatrick Mooney softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress);
6797c8c0b82SPatrick Mooney status = ivhd_dev_parse(ivhd, softc);
6807c8c0b82SPatrick Mooney if (status != 0) {
6817c8c0b82SPatrick Mooney device_printf(dev,
6827c8c0b82SPatrick Mooney "endpoint device parsing error=%d\n", status);
6837c8c0b82SPatrick Mooney goto fail;
6847c8c0b82SPatrick Mooney }
6857c8c0b82SPatrick Mooney
6867c8c0b82SPatrick Mooney status = ivhd_print_cap(softc, ivhd);
6877c8c0b82SPatrick Mooney if (status != 0)
6887c8c0b82SPatrick Mooney goto fail;
6897c8c0b82SPatrick Mooney
6907c8c0b82SPatrick Mooney status = amdvi_setup_hw(softc);
6917c8c0b82SPatrick Mooney if (status != 0) {
6927c8c0b82SPatrick Mooney device_printf(dev, "couldn't be initialised, error=%d\n",
6937c8c0b82SPatrick Mooney status);
6947c8c0b82SPatrick Mooney goto fail;
6957c8c0b82SPatrick Mooney }
6967c8c0b82SPatrick Mooney
6977c8c0b82SPatrick Mooney return (0);
6987c8c0b82SPatrick Mooney
6997c8c0b82SPatrick Mooney fail:
7007c8c0b82SPatrick Mooney free(softc->dev_cfg, M_DEVBUF);
7017c8c0b82SPatrick Mooney return (status);
7027c8c0b82SPatrick Mooney }
7037c8c0b82SPatrick Mooney
7047c8c0b82SPatrick Mooney static int
ivhd_detach(device_t dev)7057c8c0b82SPatrick Mooney ivhd_detach(device_t dev)
7067c8c0b82SPatrick Mooney {
7077c8c0b82SPatrick Mooney struct amdvi_softc *softc;
7087c8c0b82SPatrick Mooney
7097c8c0b82SPatrick Mooney softc = device_get_softc(dev);
7107c8c0b82SPatrick Mooney
7117c8c0b82SPatrick Mooney amdvi_teardown_hw(softc);
7127c8c0b82SPatrick Mooney free(softc->dev_cfg, M_DEVBUF);
7137c8c0b82SPatrick Mooney
7147c8c0b82SPatrick Mooney /*
7157c8c0b82SPatrick Mooney * XXX: delete the device.
7167c8c0b82SPatrick Mooney * don't allow detach, return EBUSY.
7177c8c0b82SPatrick Mooney */
7187c8c0b82SPatrick Mooney return (0);
7197c8c0b82SPatrick Mooney }
7207c8c0b82SPatrick Mooney
7217c8c0b82SPatrick Mooney static int
ivhd_suspend(device_t dev)7227c8c0b82SPatrick Mooney ivhd_suspend(device_t dev)
7237c8c0b82SPatrick Mooney {
7247c8c0b82SPatrick Mooney
7257c8c0b82SPatrick Mooney return (0);
7267c8c0b82SPatrick Mooney }
7277c8c0b82SPatrick Mooney
7287c8c0b82SPatrick Mooney static int
ivhd_resume(device_t dev)7297c8c0b82SPatrick Mooney ivhd_resume(device_t dev)
7307c8c0b82SPatrick Mooney {
7317c8c0b82SPatrick Mooney
7327c8c0b82SPatrick Mooney return (0);
7337c8c0b82SPatrick Mooney }
7347c8c0b82SPatrick Mooney
7357c8c0b82SPatrick Mooney static device_method_t ivhd_methods[] = {
7367c8c0b82SPatrick Mooney DEVMETHOD(device_identify, ivhd_identify),
7377c8c0b82SPatrick Mooney DEVMETHOD(device_probe, ivhd_probe),
7387c8c0b82SPatrick Mooney DEVMETHOD(device_attach, ivhd_attach),
7397c8c0b82SPatrick Mooney DEVMETHOD(device_detach, ivhd_detach),
7407c8c0b82SPatrick Mooney DEVMETHOD(device_suspend, ivhd_suspend),
7417c8c0b82SPatrick Mooney DEVMETHOD(device_resume, ivhd_resume),
7427c8c0b82SPatrick Mooney DEVMETHOD_END
7437c8c0b82SPatrick Mooney };
7447c8c0b82SPatrick Mooney
7457c8c0b82SPatrick Mooney static driver_t ivhd_driver = {
7467c8c0b82SPatrick Mooney "ivhd",
7477c8c0b82SPatrick Mooney ivhd_methods,
7487c8c0b82SPatrick Mooney sizeof(struct amdvi_softc),
7497c8c0b82SPatrick Mooney };
7507c8c0b82SPatrick Mooney
7517c8c0b82SPatrick Mooney static devclass_t ivhd_devclass;
7527c8c0b82SPatrick Mooney
7537c8c0b82SPatrick Mooney /*
7547c8c0b82SPatrick Mooney * Load this module at the end after PCI re-probing to configure interrupt.
7557c8c0b82SPatrick Mooney */
7567c8c0b82SPatrick Mooney DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0,
7577c8c0b82SPatrick Mooney SI_ORDER_ANY);
7587c8c0b82SPatrick Mooney MODULE_DEPEND(ivhd, acpi, 1, 1, 1);
7597c8c0b82SPatrick Mooney MODULE_DEPEND(ivhd, pci, 1, 1, 1);
760