Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/amd/amdvi_hw.c
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <machine/pmap.h> | #include <machine/pmap.h> | ||||
#include <machine/vmparam.h> | #include <machine/vmparam.h> | ||||
#include <machine/pci_cfgreg.h> | #include <machine/pci_cfgreg.h> | ||||
#include "ivhd_if.h" | |||||
#include "pcib_if.h" | #include "pcib_if.h" | ||||
#include "io/iommu.h" | #include "io/iommu.h" | ||||
#include "amdvi_priv.h" | #include "amdvi_priv.h" | ||||
SYSCTL_DECL(_hw_vmm); | SYSCTL_DECL(_hw_vmm); | ||||
SYSCTL_NODE(_hw_vmm, OID_AUTO, amdvi, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, | SYSCTL_NODE(_hw_vmm, OID_AUTO, amdvi, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, | ||||
NULL); | NULL); | ||||
▲ Show 20 Lines • Show All 704 Lines • ▼ Show 20 Lines | amdvi_event_intr(void *arg) | ||||
ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; | ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; | ||||
} | } | ||||
static void | static void | ||||
amdvi_free_evt_intr_res(device_t dev) | amdvi_free_evt_intr_res(device_t dev) | ||||
{ | { | ||||
struct amdvi_softc *softc; | struct amdvi_softc *softc; | ||||
device_t mmio_dev; | |||||
softc = device_get_softc(dev); | softc = device_get_softc(dev); | ||||
if (softc->event_tag != NULL) { | mmio_dev = softc->pci_dev; | ||||
bus_teardown_intr(dev, softc->event_res, softc->event_tag); | |||||
IVHD_TEARDOWN_INTR(mmio_dev); | |||||
} | } | ||||
if (softc->event_res != NULL) { | |||||
bus_release_resource(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); | |||||
} | |||||
static bool | static bool | ||||
amdvi_alloc_intr_resources(struct amdvi_softc *softc) | amdvi_alloc_intr_resources(struct amdvi_softc *softc) | ||||
{ | { | ||||
struct amdvi_ctrl *ctrl; | struct amdvi_ctrl *ctrl; | ||||
device_t dev, pcib; | device_t dev, mmio_dev; | ||||
device_t mmio_dev; | |||||
uint64_t msi_addr; | |||||
uint32_t msi_data; | |||||
int err; | int err; | ||||
dev = softc->dev; | dev = softc->dev; | ||||
pcib = device_get_parent(device_get_parent(dev)); | mmio_dev = softc->pci_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); | |||||
} | |||||
softc->event_irq = -1; | |||||
softc->event_rid = 0; | |||||
/* | |||||
* 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); | |||||
if (err) { | |||||
device_printf(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_rid, RF_ACTIVE); | |||||
if (!softc->event_res) { | |||||
device_printf(dev, | |||||
"Unable to allocate event INTR resource.\n"); | |||||
return (ENOMEM); | |||||
} | |||||
if (bus_setup_intr(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, | |||||
softc->event_rid, softc->event_res); | |||||
softc->event_res = NULL; | |||||
return (ENXIO); | |||||
} | |||||
bus_describe_intr(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. */ | /* Clear interrupt status bits. */ | ||||
ctrl = softc->ctrl; | ctrl = softc->ctrl; | ||||
jhb: I'm not a big fan of this. I think what I'd rather you is instead define a new kobj class that… | |||||
ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; | ctrl->status &= AMDVI_STATUS_EV_OF | AMDVI_STATUS_EV_INTR; | ||||
/* Now enable MSI interrupt. */ | err = IVHD_SETUP_INTR(mmio_dev, amdvi_event_intr, softc, "fault"); | ||||
pci_enable_msi(mmio_dev, msi_addr, msi_data); | if (err) | ||||
return (0); | device_printf(dev, "Interrupt setup failed on %s\n", | ||||
device_get_nameunit(mmio_dev)); | |||||
return (err); | |||||
} | } | ||||
static void | static void | ||||
amdvi_print_dev_cap(struct amdvi_softc *softc) | amdvi_print_dev_cap(struct amdvi_softc *softc) | ||||
{ | { | ||||
struct ivhd_dev_cfg *cfg; | struct ivhd_dev_cfg *cfg; | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 581 Lines • Show Last 20 Lines |
I'm not a big fan of this. I think what I'd rather you is instead define a new kobj class that you can call and ask the PCI device to register/unregister the interrupt. All of the MSI and bus_alloc_resouce/bus_setup_intr handling would be in the stub driver instead in the implementations of the new kobj methods. You could call it ivhd_if.m and have 'ivhd_setup_intr(device_t dev, driver_intr_t handler, void *arg, const char *desc)' and 'ivhd_teardown_intr(device_t dev)'. Here you would just call IVHD_SETUP_INTR()' and fail if it fails.