Support MSI-X for passthrough devices with a separate PBA BAR.

pci_alloc_msix() requires both the table and PBA BARs to be allocated
by the driver.  ppt was only allocating the table BAR so would fail
for devices with the PBA in a separate BAR.  Fix this by allocating
the PBA BAR before pci_alloc_msix() if it is stored in a separate BAR.

While here, release BARs after calling pci_release_msi() instead of
before.  Also, don't call bus_teardown_intr() in error handling code
if bus_setup_intr() has just failed.

Reported by:	gallatin
Tested by:	gallatin
Reviewed by:	rgrimes, markj
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D20525
This commit is contained in:
jhb 2019-06-05 19:30:32 +00:00
parent 004c60515d
commit e1d9e7fdef

View File

@ -102,7 +102,9 @@ struct pptdev {
int num_msgs;
int startrid;
int msix_table_rid;
int msix_pba_rid;
struct resource *msix_table_res;
struct resource *msix_pba_res;
struct resource **res;
void **cookie;
struct pptintr_arg *arg;
@ -292,6 +294,12 @@ ppt_teardown_msix(struct pptdev *ppt)
for (i = 0; i < ppt->msix.num_msgs; i++)
ppt_teardown_msix_intr(ppt, i);
free(ppt->msix.res, M_PPTMSIX);
free(ppt->msix.cookie, M_PPTMSIX);
free(ppt->msix.arg, M_PPTMSIX);
pci_release_msi(ppt->dev);
if (ppt->msix.msix_table_res) {
bus_release_resource(ppt->dev, SYS_RES_MEMORY,
ppt->msix.msix_table_rid,
@ -299,12 +307,13 @@ ppt_teardown_msix(struct pptdev *ppt)
ppt->msix.msix_table_res = NULL;
ppt->msix.msix_table_rid = 0;
}
free(ppt->msix.res, M_PPTMSIX);
free(ppt->msix.cookie, M_PPTMSIX);
free(ppt->msix.arg, M_PPTMSIX);
pci_release_msi(ppt->dev);
if (ppt->msix.msix_pba_res) {
bus_release_resource(ppt->dev, SYS_RES_MEMORY,
ppt->msix.msix_pba_rid,
ppt->msix.msix_pba_res);
ppt->msix.msix_pba_res = NULL;
ppt->msix.msix_pba_rid = 0;
}
ppt->msix.num_msgs = 0;
}
@ -634,6 +643,19 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
}
ppt->msix.msix_table_rid = rid;
if (dinfo->cfg.msix.msix_table_bar !=
dinfo->cfg.msix.msix_pba_bar) {
rid = dinfo->cfg.msix.msix_pba_bar;
ppt->msix.msix_pba_res = bus_alloc_resource_any(
ppt->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (ppt->msix.msix_pba_res == NULL) {
ppt_teardown_msix(ppt);
return (ENOSPC);
}
ppt->msix.msix_pba_rid = rid;
}
alloced = numvec;
error = pci_alloc_msix(ppt->dev, &alloced);
if (error || alloced != numvec) {
@ -665,7 +687,6 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
&ppt->msix.cookie[idx]);
if (error != 0) {
bus_teardown_intr(ppt->dev, ppt->msix.res[idx], ppt->msix.cookie[idx]);
bus_release_resource(ppt->dev, SYS_RES_IRQ, rid, ppt->msix.res[idx]);
ppt->msix.cookie[idx] = NULL;
ppt->msix.res[idx] = NULL;