Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/amd/amdvi_hw.c
Show First 20 Lines • Show All 766 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); | ||||
mmio_dev = softc->pci_dev; | |||||
if (softc->event_tag != NULL) { | 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) { | 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); | softc->event_res); | ||||
} | } | ||||
bus_delete_resource(dev, SYS_RES_IRQ, softc->event_rid); | pci_release_msi(mmio_dev); | ||||
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; | int err, count; | ||||
uint64_t msi_addr; | |||||
uint32_t msi_data; | |||||
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), | if (!device_is_attached(mmio_dev)) { | ||||
PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid)); | if (device_set_devclass(mmio_dev, "amdiommu")) | ||||
if (device_is_attached(mmio_dev)) { | return (ENXIO); | ||||
device_printf(dev, | if (device_set_driver(mmio_dev, &amdiommu_driver)) | ||||
jhb: I'm not a big fan of this. I think what I'd rather you is instead define a new kobj class that… | |||||
"warning: IOMMU device is claimed by another driver %s\n", | return (ENXIO); | ||||
device_get_driver(mmio_dev)->name); | device_quiet(mmio_dev); | ||||
if (device_attach(mmio_dev)) | |||||
return (ENXIO); | |||||
} | } | ||||
softc->event_irq = -1; | softc->event_rid = 1; | ||||
softc->event_rid = 0; | |||||
/* | /* | ||||
* Section 3.7.1 of IOMMU rev 2.0. With MSI, there is only one | * Section 3.7.1 of IOMMU rev 2.0. With MSI, there is only one | ||||
* interrupt. XXX: Enable MSI/X support. | * 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) { | if (err) { | ||||
device_printf(dev, | device_printf(mmio_dev, | ||||
"Couldn't find event MSI IRQ resource.\n"); | "Couldn't find event MSI IRQ resource.\n"); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
err = bus_set_resource(dev, SYS_RES_IRQ, softc->event_rid, | softc->event_res = bus_alloc_resource_any(mmio_dev, SYS_RES_IRQ, | ||||
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); | &softc->event_rid, RF_ACTIVE); | ||||
if (!softc->event_res) { | if (!softc->event_res) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Unable to allocate event INTR resource.\n"); | "Unable to allocate event INTR resource.\n"); | ||||
return (ENOMEM); | 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, | INTR_TYPE_MISC | INTR_MPSAFE, NULL, amdvi_event_intr, | ||||
softc, &softc->event_tag)) { | softc, &softc->event_tag)) { | ||||
device_printf(dev, "Fail to setup event intr\n"); | 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_rid, softc->event_res); | ||||
softc->event_res = NULL; | softc->event_res = NULL; | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
bus_describe_intr(dev, softc->event_res, softc->event_tag, | bus_describe_intr(mmio_dev, softc->event_res, softc->event_tag, | ||||
"fault"); | "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); | return (0); | ||||
} | } | ||||
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 582 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.