Fix a bug in the MSI-X resource allocation for PCI passthrough devices.
In the case where the underlying host had disabled MSI-X via the "hw.pci.enable_msix" tunable, the ppt_setup_msix() function would fail and return an error without properly cleaning up. This in turn would cause a page fault on the next boot of the guest. Fix this by calling ppt_teardown_msix() in all the error return paths. Obtained from: NetApp
This commit is contained in:
parent
288aeb8561
commit
920bc34090
@ -247,7 +247,7 @@ ppt_teardown_msix_intr(struct pptdev *ppt, int idx)
|
|||||||
static void
|
static void
|
||||||
ppt_teardown_msix(struct pptdev *ppt)
|
ppt_teardown_msix(struct pptdev *ppt)
|
||||||
{
|
{
|
||||||
int i, error;
|
int i;
|
||||||
|
|
||||||
if (ppt->msix.num_msgs == 0)
|
if (ppt->msix.num_msgs == 0)
|
||||||
return;
|
return;
|
||||||
@ -267,9 +267,7 @@ ppt_teardown_msix(struct pptdev *ppt)
|
|||||||
free(ppt->msix.cookie, M_PPTMSIX);
|
free(ppt->msix.cookie, M_PPTMSIX);
|
||||||
free(ppt->msix.arg, M_PPTMSIX);
|
free(ppt->msix.arg, M_PPTMSIX);
|
||||||
|
|
||||||
error = pci_release_msi(ppt->dev);
|
pci_release_msi(ppt->dev);
|
||||||
if (error)
|
|
||||||
printf("ppt_teardown_msix: Failed to release MSI-X resources (error %i)\n", error);
|
|
||||||
|
|
||||||
ppt->msix.num_msgs = 0;
|
ppt->msix.num_msgs = 0;
|
||||||
}
|
}
|
||||||
@ -519,7 +517,7 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
|
|||||||
{
|
{
|
||||||
struct pptdev *ppt;
|
struct pptdev *ppt;
|
||||||
struct pci_devinfo *dinfo;
|
struct pci_devinfo *dinfo;
|
||||||
int numvec, vector_count, rid, error;
|
int numvec, alloced, rid, error;
|
||||||
size_t res_size, cookie_size, arg_size;
|
size_t res_size, cookie_size, arg_size;
|
||||||
|
|
||||||
ppt = ppt_find(bus, slot, func);
|
ppt = ppt_find(bus, slot, func);
|
||||||
@ -538,48 +536,39 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
|
|||||||
* Allocate the IRQ resources
|
* Allocate the IRQ resources
|
||||||
* Set up some variables in ppt->msix
|
* Set up some variables in ppt->msix
|
||||||
*/
|
*/
|
||||||
if (!ppt->msix.msix_table_res) {
|
if (ppt->msix.num_msgs == 0) {
|
||||||
ppt->msix.res = NULL;
|
numvec = pci_msix_count(ppt->dev);
|
||||||
ppt->msix.cookie = NULL;
|
if (numvec <= 0)
|
||||||
ppt->msix.arg = NULL;
|
return (EINVAL);
|
||||||
|
|
||||||
rid = dinfo->cfg.msix.msix_table_bar;
|
|
||||||
ppt->msix.msix_table_res = bus_alloc_resource_any(ppt->dev, SYS_RES_MEMORY,
|
|
||||||
&rid, RF_ACTIVE);
|
|
||||||
if (ppt->msix.msix_table_res == NULL)
|
|
||||||
return (ENOSPC);
|
|
||||||
|
|
||||||
ppt->msix.msix_table_rid = rid;
|
|
||||||
|
|
||||||
vector_count = numvec = pci_msix_count(ppt->dev);
|
|
||||||
|
|
||||||
error = pci_alloc_msix(ppt->dev, &numvec);
|
|
||||||
if (error)
|
|
||||||
return (error);
|
|
||||||
else if (vector_count != numvec) {
|
|
||||||
pci_release_msi(ppt->dev);
|
|
||||||
return (ENOSPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
ppt->msix.num_msgs = numvec;
|
|
||||||
|
|
||||||
ppt->msix.startrid = 1;
|
ppt->msix.startrid = 1;
|
||||||
|
ppt->msix.num_msgs = numvec;
|
||||||
|
|
||||||
res_size = numvec * sizeof(ppt->msix.res[0]);
|
res_size = numvec * sizeof(ppt->msix.res[0]);
|
||||||
cookie_size = numvec * sizeof(ppt->msix.cookie[0]);
|
cookie_size = numvec * sizeof(ppt->msix.cookie[0]);
|
||||||
arg_size = numvec * sizeof(ppt->msix.arg[0]);
|
arg_size = numvec * sizeof(ppt->msix.arg[0]);
|
||||||
|
|
||||||
ppt->msix.res = malloc(res_size, M_PPTMSIX, M_WAITOK);
|
ppt->msix.res = malloc(res_size, M_PPTMSIX, M_WAITOK | M_ZERO);
|
||||||
ppt->msix.cookie = malloc(cookie_size, M_PPTMSIX, M_WAITOK);
|
ppt->msix.cookie = malloc(cookie_size, M_PPTMSIX,
|
||||||
ppt->msix.arg = malloc(arg_size, M_PPTMSIX, M_WAITOK);
|
M_WAITOK | M_ZERO);
|
||||||
if (ppt->msix.res == NULL || ppt->msix.cookie == NULL ||
|
ppt->msix.arg = malloc(arg_size, M_PPTMSIX, M_WAITOK | M_ZERO);
|
||||||
ppt->msix.arg == NULL) {
|
|
||||||
|
rid = dinfo->cfg.msix.msix_table_bar;
|
||||||
|
ppt->msix.msix_table_res = bus_alloc_resource_any(ppt->dev,
|
||||||
|
SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||||
|
|
||||||
|
if (ppt->msix.msix_table_res == NULL) {
|
||||||
ppt_teardown_msix(ppt);
|
ppt_teardown_msix(ppt);
|
||||||
return (ENOSPC);
|
return (ENOSPC);
|
||||||
}
|
}
|
||||||
bzero(ppt->msix.res, res_size);
|
ppt->msix.msix_table_rid = rid;
|
||||||
bzero(ppt->msix.cookie, cookie_size);
|
|
||||||
bzero(ppt->msix.arg, arg_size);
|
alloced = numvec;
|
||||||
|
error = pci_alloc_msix(ppt->dev, &alloced);
|
||||||
|
if (error || alloced != numvec) {
|
||||||
|
ppt_teardown_msix(ppt);
|
||||||
|
return (error == 0 ? ENOSPC: error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
|
if ((vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user