The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/amd64/vmm/amd/ivrs_drv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2016, Anish Gupta (anish@freebsd.org)
    5  * Copyright (c) 2021 The FreeBSD Foundation
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice unmodified, this list of conditions, and the following
   13  *    disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include "opt_acpi.h"
   34 #include <sys/param.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/malloc.h>
   39 
   40 #include <machine/vmparam.h>
   41 
   42 #include <vm/vm.h>
   43 #include <vm/pmap.h>
   44 
   45 #include <contrib/dev/acpica/include/acpi.h>
   46 #include <contrib/dev/acpica/include/accommon.h>
   47 #include <dev/acpica/acpivar.h>
   48 #include <dev/pci/pcireg.h>
   49 #include <dev/pci/pcivar.h>
   50 
   51 #include "io/iommu.h"
   52 #include "amdvi_priv.h"
   53 
   54 device_t *ivhd_devs;                    /* IVHD or AMD-Vi device list. */
   55 int     ivhd_count;                     /* Number of IVHD header. */
   56 /* 
   57  * Cached IVHD header list.
   58  * Single entry for each IVHD, filtered the legacy one.
   59  */
   60 ACPI_IVRS_HARDWARE1 **ivhd_hdrs;
   61 
   62 extern int amdvi_ptp_level;             /* Page table levels. */
   63 
   64 typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg);
   65 /*
   66  * Iterate IVRS table for IVHD and IVMD device type.
   67  */
   68 static void
   69 ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg)
   70 {
   71         ACPI_TABLE_IVRS *ivrs;
   72         ACPI_IVRS_HEADER *ivrs_hdr, *end;
   73         ACPI_STATUS status;
   74 
   75         status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
   76         if (ACPI_FAILURE(status))
   77                 return;
   78 
   79         if (ivrs->Header.Length == 0) {
   80                 return;
   81         }
   82 
   83         ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1);
   84         end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length);
   85 
   86         while (ivrs_hdr < end) {
   87                 if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) {
   88                         printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n",
   89                             ivrs_hdr->Length);
   90                         break;
   91                 }
   92 
   93                 switch (ivrs_hdr->Type) {
   94                 case IVRS_TYPE_HARDWARE_LEGACY: /* Legacy */
   95                 case IVRS_TYPE_HARDWARE_EFR:
   96                 case IVRS_TYPE_HARDWARE_MIXED:
   97                         if (!iter(ivrs_hdr, arg))
   98                                 return;
   99                         break;
  100 
  101                 case ACPI_IVRS_TYPE_MEMORY1:
  102                 case ACPI_IVRS_TYPE_MEMORY2:
  103                 case ACPI_IVRS_TYPE_MEMORY3:
  104                         if (!iter(ivrs_hdr, arg))
  105                                 return;
  106 
  107                         break;
  108 
  109                 default:
  110                         printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type);
  111                 }
  112 
  113                 ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr +
  114                         ivrs_hdr->Length);
  115         }
  116 }
  117 
  118 static bool
  119 ivrs_is_ivhd(UINT8 type)
  120 {
  121 
  122         switch(type) {
  123         case IVRS_TYPE_HARDWARE_LEGACY:
  124         case IVRS_TYPE_HARDWARE_EFR:
  125         case IVRS_TYPE_HARDWARE_MIXED:
  126                 return (true);
  127 
  128         default:
  129                 return (false);
  130         }
  131 }
  132 
  133 /* Count the number of AMD-Vi devices in the system. */
  134 static int
  135 ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg)
  136 {
  137         int *count;
  138 
  139         count = (int *)arg;
  140         if (ivrs_is_ivhd(ivrs_he->Type))
  141                 (*count)++;
  142 
  143         return (1);
  144 }
  145 
  146 struct find_ivrs_hdr_args {
  147         int     i;
  148         ACPI_IVRS_HEADER *ptr;
  149 };
  150 
  151 static int
  152 ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args)
  153 {
  154         struct find_ivrs_hdr_args *fi;
  155 
  156         fi = (struct find_ivrs_hdr_args *)args;
  157         if (ivrs_is_ivhd(ivrs_hdr->Type)) {
  158                 if (fi->i == 0) {
  159                         fi->ptr = ivrs_hdr;
  160                         return (0);
  161                 }
  162                 fi->i--;
  163         }
  164 
  165         return (1);
  166 }
  167 
  168 static ACPI_IVRS_HARDWARE1 *
  169 ivhd_find_by_index(int idx)
  170 {
  171         struct find_ivrs_hdr_args fi;
  172 
  173         fi.i = idx;
  174         fi.ptr = NULL;
  175 
  176         ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi);
  177 
  178         return ((ACPI_IVRS_HARDWARE1 *)fi.ptr);
  179 }
  180 
  181 static void
  182 ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id,
  183     uint32_t end_id, uint8_t cfg, bool ats)
  184 {
  185         struct ivhd_dev_cfg *dev_cfg;
  186 
  187         KASSERT(softc->dev_cfg_cap >= softc->dev_cfg_cnt,
  188             ("Impossible case: number of dev_cfg exceeding capacity"));
  189         if (softc->dev_cfg_cap == softc->dev_cfg_cnt) {
  190                 if (softc->dev_cfg_cap == 0)
  191                         softc->dev_cfg_cap = 1;
  192                 else
  193                         softc->dev_cfg_cap <<= 2;
  194                 softc->dev_cfg = realloc(softc->dev_cfg,
  195                     sizeof(*softc->dev_cfg) * softc->dev_cfg_cap, M_DEVBUF,
  196                     M_WAITOK);
  197         }
  198 
  199         dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++];
  200         dev_cfg->start_id = start_id;
  201         dev_cfg->end_id = end_id;
  202         dev_cfg->data = cfg;
  203         dev_cfg->enable_ats = ats;
  204 }
  205 
  206 /*
  207  * Record device attributes as suggested by BIOS.
  208  */
  209 static int
  210 ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc)
  211 {
  212         ACPI_IVRS_DE_HEADER *de;
  213         uint8_t *p, *end;
  214         int range_start_id = -1, range_end_id = -1, i;
  215         uint32_t *extended;
  216         uint8_t all_data = 0, range_data = 0;
  217         bool range_enable_ats = false, enable_ats;
  218 
  219         switch (ivhd->Header.Type) {
  220                 case IVRS_TYPE_HARDWARE_LEGACY:
  221                         p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1);
  222                         break;
  223 
  224                 case IVRS_TYPE_HARDWARE_EFR:
  225                 case IVRS_TYPE_HARDWARE_MIXED:
  226                         p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2);
  227                         break;
  228 
  229                 default:
  230                         device_printf(softc->dev, 
  231                                 "unknown type: 0x%x\n", ivhd->Header.Type);
  232                         return (-1);
  233         }
  234 
  235         end = (uint8_t *)ivhd + ivhd->Header.Length;
  236 
  237         while (p < end) {
  238                 de = (ACPI_IVRS_DE_HEADER *)p;
  239                 switch (de->Type) {
  240                 case ACPI_IVRS_TYPE_ALL:
  241                         all_data = de->DataSetting;
  242                         for (i = 0; i < softc->dev_cfg_cnt; i++)
  243                                 softc->dev_cfg[i].data |= all_data;
  244                         break;
  245 
  246                 case ACPI_IVRS_TYPE_SELECT:
  247                 case ACPI_IVRS_TYPE_ALIAS_SELECT:
  248                 case ACPI_IVRS_TYPE_EXT_SELECT:
  249                         enable_ats = false;
  250                         if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
  251                                 extended = (uint32_t *)(de + 1);
  252                                 enable_ats =
  253                                     (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
  254                                         false : true;
  255                         }
  256                         ivhd_dev_add_entry(softc, de->Id, de->Id,
  257                             de->DataSetting | all_data, enable_ats);
  258                         break;
  259 
  260                 case ACPI_IVRS_TYPE_START:
  261                 case ACPI_IVRS_TYPE_ALIAS_START:
  262                 case ACPI_IVRS_TYPE_EXT_START:
  263                         if (range_start_id != -1) {
  264                                 device_printf(softc->dev,
  265                                     "Unexpected start-of-range device entry\n");
  266                                 return (EINVAL);
  267                         }
  268                         range_start_id = de->Id;
  269                         range_data = de->DataSetting;
  270                         if (de->Type == ACPI_IVRS_TYPE_EXT_START) {
  271                                 extended = (uint32_t *)(de + 1);
  272                                 range_enable_ats =
  273                                     (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
  274                                         false : true;
  275                         }
  276                         break;
  277 
  278                 case ACPI_IVRS_TYPE_END:
  279                         if (range_start_id == -1) {
  280                                 device_printf(softc->dev,
  281                                     "Unexpected end-of-range device entry\n");
  282                                 return (EINVAL);
  283                         }
  284                         range_end_id = de->Id;
  285                         if (range_end_id < range_start_id) {
  286                                 device_printf(softc->dev,
  287                                     "Device entry range going backward\n");
  288                                 return (EINVAL);
  289                         }
  290                         ivhd_dev_add_entry(softc, range_start_id, range_end_id,
  291                             range_data | all_data, range_enable_ats);
  292                         range_start_id = range_end_id = -1;
  293                         range_data = 0;
  294                         all_data = 0;
  295                         break;
  296 
  297                 case ACPI_IVRS_TYPE_PAD4:
  298                         break;
  299 
  300                 case ACPI_IVRS_TYPE_SPECIAL:
  301                         /* HPET or IOAPIC */
  302                         break;
  303                 default:
  304                         if ((de->Type < 5) ||
  305                             (de->Type >= ACPI_IVRS_TYPE_PAD8))
  306                                 device_printf(softc->dev,
  307                                     "Unknown dev entry:0x%x\n", de->Type);
  308                 }
  309 
  310                 if (de->Type < 0x40)
  311                         p += sizeof(ACPI_IVRS_DEVICE4);
  312                 else if (de->Type < 0x80)
  313                         p += sizeof(ACPI_IVRS_DEVICE8A);
  314                 else {
  315                         printf("Variable size IVHD type 0x%x not supported\n",
  316                             de->Type);
  317                         break;
  318                 }
  319         }
  320 
  321         return (0);
  322 }
  323 
  324 static bool
  325 ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER  *new)
  326 {
  327         if (old->DeviceId == new->DeviceId) {
  328                 /*
  329                  * Newer IVRS header type take precedence.
  330                  */
  331                 if (old->Type == IVRS_TYPE_HARDWARE_LEGACY &&
  332                     ((new->Type == IVRS_TYPE_HARDWARE_EFR) ||
  333                     (new->Type == IVRS_TYPE_HARDWARE_MIXED)))
  334                         return (true);
  335 
  336                 /*
  337                  * Mixed format IVHD header type take precedence
  338                  * over fixed format IVHD header types.
  339                  */
  340                 if (old->Type == IVRS_TYPE_HARDWARE_EFR &&
  341                     new->Type == IVRS_TYPE_HARDWARE_MIXED)
  342                         return (true);
  343         }
  344 
  345         return (false);
  346 }
  347 
  348 static void
  349 ivhd_identify(driver_t *driver, device_t parent)
  350 {
  351         ACPI_TABLE_IVRS *ivrs;
  352         ACPI_IVRS_HARDWARE1 *ivhd;
  353         ACPI_STATUS status;
  354         int i, j, count = 0;
  355         uint32_t ivrs_ivinfo;
  356 
  357         if (acpi_disabled("ivhd"))
  358                 return;
  359 
  360         status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
  361         if (ACPI_FAILURE(status))
  362                 return;
  363 
  364         if (ivrs->Header.Length == 0) {
  365                 return;
  366         }
  367 
  368         ivrs_ivinfo = ivrs->Info;
  369         printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d"
  370                " flags:%b\n",
  371                 REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8), 
  372                 REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
  373                 "\020\001EFRSup");
  374 
  375         ivrs_hdr_iterate_tbl(ivhd_count_iter, &count);
  376         if (!count)
  377                 return;
  378 
  379         ivhd_hdrs = malloc(sizeof(void *) * count, M_DEVBUF,
  380                 M_WAITOK | M_ZERO);
  381         for (i = 0; i < count; i++) {
  382                 ivhd = ivhd_find_by_index(i);
  383                 KASSERT(ivhd, ("ivhd%d is NULL\n", i));
  384 
  385                 /*
  386                  * Scan for presence of legacy and non-legacy device type
  387                  * for same IOMMU device and override the old one.
  388                  *
  389                  * If there is no existing IVHD to the same IOMMU device,
  390                  * the IVHD header pointer is appended.
  391                  */
  392                 for (j = 0; j < ivhd_count; j++) {
  393                         if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header))
  394                                 break;
  395                 }
  396                 ivhd_hdrs[j] = ivhd;
  397                 if (j == ivhd_count)
  398                         ivhd_count++;
  399         }
  400 
  401         ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF,
  402                 M_WAITOK | M_ZERO);
  403         for (i = 0, j = 0; i < ivhd_count; i++) {
  404                 ivhd = ivhd_hdrs[i];
  405                 KASSERT(ivhd, ("ivhd%d is NULL\n", i));
  406 
  407                 /*
  408                  * Use a high order to ensure that this driver is probed after
  409                  * the Host-PCI bridge and the root PCI bus.
  410                  */
  411                 ivhd_devs[i] = BUS_ADD_CHILD(parent,
  412                     ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i);
  413 
  414                 /*
  415                  * XXX: In case device was not destroyed before, add will fail.
  416                  * locate the old device instance.
  417                  */
  418                 if (ivhd_devs[i] == NULL) {
  419                         ivhd_devs[i] = device_find_child(parent, "ivhd", i);
  420                         if (ivhd_devs[i] == NULL) {
  421                                 printf("AMD-Vi: cant find ivhd%d\n", i);
  422                                 break;
  423                         }
  424                 }
  425                 j++;
  426         }
  427 
  428         /*
  429          * Update device count in case failed to attach.
  430          */
  431         ivhd_count = j;
  432 }
  433 
  434 static int
  435 ivhd_probe(device_t dev)
  436 {
  437         ACPI_IVRS_HARDWARE1 *ivhd;
  438         int unit;
  439 
  440         if (acpi_get_handle(dev) != NULL)
  441                 return (ENXIO);
  442 
  443         unit = device_get_unit(dev);
  444         KASSERT((unit < ivhd_count), 
  445                 ("ivhd unit %d > count %d", unit, ivhd_count));
  446         ivhd = ivhd_hdrs[unit];
  447         KASSERT(ivhd, ("ivhd is NULL"));
  448 
  449         switch (ivhd->Header.Type) {
  450         case IVRS_TYPE_HARDWARE_EFR:
  451                 device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR");
  452                 break;
  453 
  454         case IVRS_TYPE_HARDWARE_MIXED:
  455                 device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format");
  456                 break;
  457 
  458         case IVRS_TYPE_HARDWARE_LEGACY:
  459         default:
  460                 device_set_desc(dev, "AMD-Vi/IOMMU ivhd");
  461                 break;
  462         }
  463 
  464         return (BUS_PROBE_NOWILDCARD);
  465 }
  466 
  467 static void
  468 ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag)
  469 {
  470         /*
  471          * IVHD lgeacy type has two extra high bits in flag which has
  472          * been moved to EFR for non-legacy device.
  473          */
  474         switch (ivhd_type) {
  475         case IVRS_TYPE_HARDWARE_LEGACY:
  476                 device_printf(dev, "Flag:%b\n", flag,
  477                         "\020"
  478                         "\001HtTunEn"
  479                         "\002PassPW"
  480                         "\003ResPassPW"
  481                         "\004Isoc"
  482                         "\005IotlbSup"
  483                         "\006Coherent"
  484                         "\007PreFSup"
  485                         "\010PPRSup");
  486                 break;
  487 
  488         case IVRS_TYPE_HARDWARE_EFR:
  489         case IVRS_TYPE_HARDWARE_MIXED:
  490                 device_printf(dev, "Flag:%b\n", flag,
  491                         "\020"
  492                         "\001HtTunEn"
  493                         "\002PassPW"
  494                         "\003ResPassPW"
  495                         "\004Isoc"
  496                         "\005IotlbSup"
  497                         "\006Coherent");
  498                 break;
  499 
  500         default:
  501                 device_printf(dev, "Can't decode flag of ivhd type :0x%x\n",
  502                         ivhd_type);
  503                 break;
  504         }
  505 }
  506 
  507 /*
  508  * Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40).
  509  */
  510 static void
  511 ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature) 
  512 {
  513         switch (ivhd_type) {
  514         case IVRS_TYPE_HARDWARE_LEGACY:
  515                 device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d"
  516                         " MsiNumPPR = %d PNBanks= %d PNCounters= %d\n",
  517                         ivhd_type,
  518                         REG_BITS(feature, 31, 30),
  519                         REG_BITS(feature, 29, 28),
  520                         REG_BITS(feature, 27, 23),
  521                         REG_BITS(feature, 22, 17),
  522                         REG_BITS(feature, 16, 13));
  523                 device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n",
  524                         REG_BITS(feature, 12, 8),
  525                         REG_BITS(feature, 4, 3),
  526                         feature,
  527                         "\020"
  528                         "\002NXSup"
  529                         "\003GTSup"
  530                         "\004<b4>"
  531                         "\005IASup"
  532                         "\006GASup"
  533                         "\007HESup");
  534                 break;
  535 
  536         /* Fewer features or attributes are reported in non-legacy type. */
  537         case IVRS_TYPE_HARDWARE_EFR:
  538         case IVRS_TYPE_HARDWARE_MIXED:
  539                 device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d"
  540                         " PNBanks= %d PNCounters= %d\n",
  541                         ivhd_type,
  542                         REG_BITS(feature, 27, 23),
  543                         REG_BITS(feature, 22, 17),
  544                         REG_BITS(feature, 16, 13));
  545                 break;
  546 
  547         default: /* Other ivhd type features are not decoded. */
  548                 device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type);
  549         }
  550 }
  551 
  552 /* Print extended features of IOMMU. */
  553 static void
  554 ivhd_print_ext_feature(device_t dev, uint64_t ext_feature)
  555 {
  556         uint32_t ext_low, ext_high;
  557 
  558         if (!ext_feature)
  559                 return;
  560 
  561         ext_low = ext_feature;
  562         device_printf(dev, "Extended features[31:0]:%b "
  563                 "HATS = 0x%x GATS = 0x%x "
  564                 "GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x "
  565                 "GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n",
  566                 (int)ext_low,
  567                 "\020"
  568                 "\001PreFSup"
  569                 "\002PPRSup"
  570                 "\003<b2>"
  571                 "\004NXSup"
  572                 "\005GTSup"
  573                 "\006<b5>"
  574                 "\007IASup"
  575                 "\010GASup"
  576                 "\011HESup"
  577                 "\012PCSup",
  578                 REG_BITS(ext_low, 11, 10),
  579                 REG_BITS(ext_low, 13, 12),
  580                 REG_BITS(ext_low, 15, 14),
  581                 REG_BITS(ext_low, 17, 16),
  582                 REG_BITS(ext_low, 20, 18),
  583                 REG_BITS(ext_low, 23, 21),
  584                 REG_BITS(ext_low, 25, 24),
  585                 REG_BITS(ext_low, 29, 28));
  586 
  587         ext_high = ext_feature >> 32;
  588         device_printf(dev, "Extended features[62:32]:%b "
  589                 "Max PASID: 0x%x DevTblSegSup = 0x%x "
  590                 "MarcSup = 0x%x\n",
  591                 (int)(ext_high),
  592                 "\020"
  593                 "\006USSup"
  594                 "\011PprOvrflwEarlySup"
  595                 "\012PPRAutoRspSup"
  596                 "\015BlKStopMrkSup"
  597                 "\016PerfOptSup"
  598                 "\017MsiCapMmioSup"
  599                 "\021GIOSup"
  600                 "\022HASup"
  601                 "\023EPHSup"
  602                 "\024AttrFWSup"
  603                 "\025HDSup"
  604                 "\027InvIotlbSup",
  605                 REG_BITS(ext_high, 5, 0),
  606                 REG_BITS(ext_high, 8, 7),
  607                 REG_BITS(ext_high, 11, 10));
  608 }
  609 
  610 static int
  611 ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd)
  612 {
  613         device_t dev;
  614         int max_ptp_level;
  615 
  616         dev = softc->dev;
  617 
  618         ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag);
  619         ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature);
  620         ivhd_print_ext_feature(dev, softc->ext_feature);
  621         max_ptp_level = 7;
  622         /* Make sure device support minimum page level as requested by user. */
  623         if (max_ptp_level < amdvi_ptp_level) {
  624                 device_printf(dev, "insufficient PTP level:%d\n",
  625                         max_ptp_level);
  626                 return (EINVAL);
  627         } else {
  628                 device_printf(softc->dev, "supported paging level:%d, will use only: %d\n",
  629                         max_ptp_level, amdvi_ptp_level);
  630         }
  631 
  632         return (0);
  633 }
  634 
  635 static int
  636 ivhd_attach(device_t dev)
  637 {
  638         ACPI_IVRS_HARDWARE1 *ivhd;
  639         ACPI_IVRS_HARDWARE2 *ivhd_efr;
  640         struct amdvi_softc *softc;
  641         int status, unit;
  642 
  643         unit = device_get_unit(dev);
  644         KASSERT((unit < ivhd_count), 
  645                 ("ivhd unit %d > count %d", unit, ivhd_count));
  646         /* Make sure its same device for which attach is called. */
  647         KASSERT((ivhd_devs[unit] == dev),
  648                 ("Not same device old %p new %p", ivhd_devs[unit], dev));
  649 
  650         softc = device_get_softc(dev);
  651         softc->dev = dev;
  652         ivhd = ivhd_hdrs[unit];
  653         KASSERT(ivhd, ("ivhd is NULL"));
  654         softc->pci_dev = pci_find_bsf(PCI_RID2BUS(ivhd->Header.DeviceId),
  655             PCI_RID2SLOT(ivhd->Header.DeviceId),
  656             PCI_RID2FUNC(ivhd->Header.DeviceId));
  657 
  658         softc->ivhd_type = ivhd->Header.Type;
  659         softc->pci_seg = ivhd->PciSegmentGroup;
  660         softc->pci_rid = ivhd->Header.DeviceId;
  661         softc->ivhd_flag = ivhd->Header.Flags;
  662         /* 
  663          * On lgeacy IVHD type(0x10), it is documented as feature
  664          * but in newer type it is attribute.
  665          */
  666         softc->ivhd_feature = ivhd->FeatureReporting;
  667         /* 
  668          * PCI capability has more capabilities that are not part of IVRS.
  669          */
  670         softc->cap_off = ivhd->CapabilityOffset;
  671 
  672 #ifdef notyet
  673         /* IVHD Info bit[4:0] is event MSI/X number. */
  674         softc->event_msix = ivhd->Info & 0x1F;
  675 #endif
  676         switch (ivhd->Header.Type) {
  677         case IVRS_TYPE_HARDWARE_EFR:
  678         case IVRS_TYPE_HARDWARE_MIXED:
  679                 ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd;
  680                 softc->ext_feature = ivhd_efr->EfrRegisterImage;
  681                 break;
  682         }
  683 
  684         softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress);
  685         status = ivhd_dev_parse(ivhd, softc);
  686         if (status != 0) {
  687                 device_printf(dev,
  688                     "endpoint device parsing error=%d\n", status);
  689                 goto fail;
  690         }
  691 
  692         status = ivhd_print_cap(softc, ivhd);
  693         if (status != 0)
  694                 goto fail;
  695 
  696         status = amdvi_setup_hw(softc);
  697         if (status != 0) {
  698                 device_printf(dev, "couldn't be initialised, error=%d\n", 
  699                     status);
  700                 goto fail;
  701         }
  702 
  703         return (0);
  704 
  705 fail:
  706         free(softc->dev_cfg, M_DEVBUF);
  707         return (status);
  708 }
  709 
  710 static int
  711 ivhd_detach(device_t dev)
  712 {
  713         struct amdvi_softc *softc;
  714 
  715         softc = device_get_softc(dev);
  716 
  717         amdvi_teardown_hw(softc);
  718         free(softc->dev_cfg, M_DEVBUF);
  719 
  720         /*
  721          * XXX: delete the device.
  722          * don't allow detach, return EBUSY.
  723          */
  724         return (0);
  725 }
  726 
  727 static int
  728 ivhd_suspend(device_t dev)
  729 {
  730 
  731         return (0);
  732 }
  733 
  734 static int
  735 ivhd_resume(device_t dev)
  736 {
  737 
  738         return (0);
  739 }
  740 
  741 static device_method_t ivhd_methods[] = {
  742         DEVMETHOD(device_identify, ivhd_identify),
  743         DEVMETHOD(device_probe, ivhd_probe),
  744         DEVMETHOD(device_attach, ivhd_attach),
  745         DEVMETHOD(device_detach, ivhd_detach),
  746         DEVMETHOD(device_suspend, ivhd_suspend),
  747         DEVMETHOD(device_resume, ivhd_resume),
  748         DEVMETHOD_END
  749 };
  750 
  751 static driver_t ivhd_driver = {
  752         "ivhd",
  753         ivhd_methods,
  754         sizeof(struct amdvi_softc),
  755 };
  756 
  757 /*
  758  * Load this module at the end after PCI re-probing to configure interrupt.
  759  */
  760 DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, 0, 0, SI_ORDER_ANY);
  761 MODULE_DEPEND(ivhd, acpi, 1, 1, 1);
  762 MODULE_DEPEND(ivhd, pci, 1, 1, 1);

Cache object: 15eea6e2647c4290e369ad10cbc5896b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.