Index: sys/amd64/vmm/amd/amdiommu.c =================================================================== --- /dev/null +++ sys/amd64/vmm/amd/amdiommu.c @@ -0,0 +1,79 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021, Ka Ho Ng + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "amdvi_priv.h" + +static devclass_t amdiommu_devclass; + +static int amdiommu_probe(device_t); +static int amdiommu_attach(device_t); +static int amdiommu_detach(device_t); + +static device_method_t amdiommu_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, amdiommu_probe), + DEVMETHOD(device_attach, amdiommu_attach), + DEVMETHOD(device_detach, amdiommu_detach), + DEVMETHOD_END +}; +driver_t amdiommu_driver = { + "amdiommu", + amdiommu_methods, + 0 +}; + +static int +amdiommu_probe(device_t dev) +{ + return (ENXIO); +} + +static int +amdiommu_attach(device_t dev) +{ + device_set_desc(dev, "AMD-Vi/IOMMU PCI function"); + device_printf(dev, "attached\n"); + return (0); +} + +static int +amdiommu_detach(device_t dev) +{ + device_printf(dev, "detached\n"); + return (0); +} + +DRIVER_MODULE(amdiommu, pci, amdiommu_driver, amdiommu_devclass, 0, 0); +MODULE_DEPEND(amdiommu, pci, 1, 1, 1); Index: sys/amd64/vmm/amd/amdvi_hw.c =================================================================== --- sys/amd64/vmm/amd/amdvi_hw.c +++ sys/amd64/vmm/amd/amdvi_hw.c @@ -772,62 +772,55 @@ { struct amdvi_softc *softc; + device_t mmio_dev; softc = device_get_softc(dev); + mmio_dev = softc->pci_dev; + if (softc->event_tag != NULL) { - bus_teardown_intr(dev, softc->event_res, softc->event_tag); + bus_teardown_intr(mmio_dev, softc->event_res, softc->event_tag); } if (softc->event_res != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, softc->event_rid, + bus_release_resource(mmio_dev, SYS_RES_IRQ, softc->event_rid, softc->event_res); } - bus_delete_resource(dev, SYS_RES_IRQ, softc->event_rid); - PCIB_RELEASE_MSI(device_get_parent(device_get_parent(dev)), - dev, 1, &softc->event_irq); + pci_release_msi(mmio_dev); } static bool amdvi_alloc_intr_resources(struct amdvi_softc *softc) { struct amdvi_ctrl *ctrl; - device_t dev, pcib; - device_t mmio_dev; - uint64_t msi_addr; - uint32_t msi_data; - int err; + device_t dev, mmio_dev; + int err, count; dev = softc->dev; - pcib = device_get_parent(device_get_parent(dev)); - mmio_dev = pci_find_bsf(PCI_RID2BUS(softc->pci_rid), - PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid)); - if (device_is_attached(mmio_dev)) { - device_printf(dev, - "warning: IOMMU device is claimed by another driver %s\n", - device_get_driver(mmio_dev)->name); + mmio_dev = softc->pci_dev; + if (!device_is_attached(mmio_dev)) { + if (device_set_devclass(mmio_dev, "amdiommu")) + return (ENXIO); + if (device_set_driver(mmio_dev, &amdiommu_driver)) + return (ENXIO); + device_quiet(mmio_dev); + if (device_attach(mmio_dev)) + return (ENXIO); } - softc->event_irq = -1; - softc->event_rid = 0; + softc->event_rid = 1; /* * Section 3.7.1 of IOMMU rev 2.0. With MSI, there is only one * interrupt. XXX: Enable MSI/X support. */ - err = PCIB_ALLOC_MSI(pcib, dev, 1, 1, &softc->event_irq); + count = 1; + err = pci_alloc_msi(mmio_dev, &count); if (err) { - device_printf(dev, + device_printf(mmio_dev, "Couldn't find event MSI IRQ resource.\n"); return (ENOENT); } - err = bus_set_resource(dev, SYS_RES_IRQ, softc->event_rid, - softc->event_irq, 1); - if (err) { - device_printf(dev, "Couldn't set event MSI resource.\n"); - return (ENXIO); - } - - softc->event_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + softc->event_res = bus_alloc_resource_any(mmio_dev, SYS_RES_IRQ, &softc->event_rid, RF_ACTIVE); if (!softc->event_res) { device_printf(dev, @@ -835,35 +828,23 @@ return (ENOMEM); } - if (bus_setup_intr(dev, softc->event_res, + /* Clear interrupt status bits. */ + ctrl = softc->ctrl; + ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; + + /* Now enable MSI interrupt. */ + if (bus_setup_intr(mmio_dev, softc->event_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, amdvi_event_intr, softc, &softc->event_tag)) { device_printf(dev, "Fail to setup event intr\n"); - bus_release_resource(softc->dev, SYS_RES_IRQ, + bus_release_resource(mmio_dev, SYS_RES_IRQ, softc->event_rid, softc->event_res); softc->event_res = NULL; return (ENXIO); } - bus_describe_intr(dev, softc->event_res, softc->event_tag, + bus_describe_intr(mmio_dev, softc->event_res, softc->event_tag, "fault"); - - err = PCIB_MAP_MSI(pcib, dev, softc->event_irq, &msi_addr, - &msi_data); - if (err) { - device_printf(dev, - "Event interrupt config failed, err=%d.\n", - err); - amdvi_free_evt_intr_res(softc->dev); - return (err); - } - - /* Clear interrupt status bits. */ - ctrl = softc->ctrl; - ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; - - /* Now enable MSI interrupt. */ - pci_enable_msi(mmio_dev, msi_addr, msi_data); return (0); } Index: sys/amd64/vmm/amd/amdvi_priv.h =================================================================== --- sys/amd64/vmm/amd/amdvi_priv.h +++ sys/amd64/vmm/amd/amdvi_priv.h @@ -375,6 +375,7 @@ struct amdvi_softc { struct amdvi_ctrl *ctrl; /* Control area. */ device_t dev; /* IOMMU device. */ + device_t pci_dev; /* IOMMU PCI function device. */ enum IvrsType ivhd_type; /* IOMMU IVHD type. */ bool iotlb; /* IOTLB supported by IOMMU */ struct amdvi_cmd *cmd; /* Command descriptor area. */ @@ -384,7 +385,6 @@ struct resource *event_res; /* Event interrupt resource. */ void *event_tag; /* Event interrupt tag. */ int event_max; /* Max number of events. */ - int event_irq; int event_rid; /* ACPI various flags. */ uint32_t ivhd_flag; /* ACPI IVHD flag. */ @@ -408,6 +408,8 @@ uint64_t total_cmd; /* Total number of commands. */ }; +extern driver_t amdiommu_driver; + int amdvi_setup_hw(struct amdvi_softc *softc); int amdvi_teardown_hw(struct amdvi_softc *softc); #endif /* _AMDVI_PRIV_H_ */ Index: sys/amd64/vmm/amd/ivrs_drv.c =================================================================== --- sys/amd64/vmm/amd/ivrs_drv.c +++ sys/amd64/vmm/amd/ivrs_drv.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include "io/iommu.h" #include "amdvi_priv.h" @@ -627,6 +629,9 @@ softc->dev = dev; ivhd = ivhd_hdrs[unit]; KASSERT(ivhd, ("ivhd is NULL")); + softc->pci_dev = pci_find_bsf(PCI_RID2BUS(ivhd->Header.DeviceId), + PCI_RID2SLOT(ivhd->Header.DeviceId), + PCI_RID2FUNC(ivhd->Header.DeviceId)); softc->ivhd_type = ivhd->Header.Type; softc->pci_seg = ivhd->PciSegmentGroup; Index: sys/modules/vmm/Makefile =================================================================== --- sys/modules/vmm/Makefile +++ sys/modules/vmm/Makefile @@ -51,6 +51,7 @@ # amd-specific files .PATH: ${SRCTOP}/sys/amd64/vmm/amd SRCS+= vmcb.c \ + amdiommu.c \ svm.c \ svm_support.S \ npt.c \