Skip to content

Commit

Permalink
pci: Convert msi_init() to Error and fix callers to check it
Browse files Browse the repository at this point in the history
msi_init() reports errors with error_report(), which is wrong
when it's used in realize().

Fix by converting it to Error.

Fix its callers to handle failure instead of ignoring it.

For those callers who don't handle the failure, it might happen:
when user want msi on, but he doesn't get what he want because of
msi_init fails silently.

cc: Gerd Hoffmann <[email protected]>
cc: John Snow <[email protected]>
cc: Dmitry Fleytman <[email protected]>
cc: Jason Wang <[email protected]>
cc: Michael S. Tsirkin <[email protected]>
cc: Hannes Reinecke <[email protected]>
cc: Paolo Bonzini <[email protected]>
cc: Alex Williamson <[email protected]>
cc: Markus Armbruster <[email protected]>
cc: Marcel Apfelbaum <[email protected]>

Reviewed-by: Markus Armbruster <[email protected]>
Signed-off-by: Cao jin <[email protected]>
Reviewed-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
  • Loading branch information
Cao jin authored and mstsirkin committed Jul 5, 2016
1 parent 69b205b commit 1108b2f
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 67 deletions.
24 changes: 20 additions & 4 deletions hw/audio/intel-hda.c
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,8 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
{
IntelHDAState *d = INTEL_HDA(pci);
uint8_t *conf = d->pci.config;
Error *err = NULL;
int ret;

d->name = object_get_typename(OBJECT(d));

Expand All @@ -1140,13 +1142,27 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp)
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
conf[0x40] = 0x01;

if (d->msi != ON_OFF_AUTO_OFF) {
ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60,
1, true, false, &err);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error */
assert(!ret || ret == -ENOTSUP);
if (ret && d->msi == ON_OFF_AUTO_ON) {
/* Can't satisfy user's explicit msi=on request, fail */
error_append_hint(&err, "You have to use msi=auto (default) or "
"msi=off with this machine type.\n");
error_propagate(errp, err);
return;
}
assert(!err || d->msi == ON_OFF_AUTO_AUTO);
/* With msi=auto, we fall back to MSI off silently */
error_free(err);
}

memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d,
"intel-hda", 0x4000);
pci_register_bar(&d->pci, 0, 0, &d->mmio);
if (d->msi != ON_OFF_AUTO_OFF) {
/* TODO check for errors */
msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
}

hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
intel_hda_response, intel_hda_xfer);
Expand Down
7 changes: 5 additions & 2 deletions hw/ide/ich.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
#include <hw/isa/isa.h>
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"

#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>

Expand Down Expand Up @@ -111,6 +110,7 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
int sata_cap_offset;
uint8_t *sata_cap;
d = ICH_AHCI(dev);
int ret;

ahci_realize(&d->ahci, DEVICE(dev), pci_get_address_space(dev), 6);

Expand Down Expand Up @@ -146,7 +146,10 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
/* Although the AHCI 1.3 specification states that the first capability
* should be PMCAP, the Intel ICH9 data sheet specifies that the ICH9
* AHCI device puts the MSI capability first, pointing to 0x80. */
msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false);
ret = msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false, NULL);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error. Fall back to INTx silently on -ENOTSUP */
assert(!ret || ret == -ENOTSUP);
}

static void pci_ich9_uninit(PCIDevice *dev)
Expand Down
8 changes: 2 additions & 6 deletions hw/net/e1000e.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,9 @@ e1000e_init_msi(E1000EState *s)
{
int res;

res = msi_init(PCI_DEVICE(s),
0xD0, /* MSI capability offset */
1, /* MAC MSI interrupts */
true, /* 64-bit message addresses supported */
false); /* Per vector mask supported */
res = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL);

if (res > 0) {
if (!res) {
s->intr_state |= E1000E_USE_MSI;
} else {
trace_e1000e_msi_init_fail(res);
Expand Down
37 changes: 12 additions & 25 deletions hw/net/vmxnet3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2216,27 +2216,6 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
}
}

#define VMXNET3_USE_64BIT (true)
#define VMXNET3_PER_VECTOR_MASK (false)

static bool
vmxnet3_init_msi(VMXNET3State *s)
{
PCIDevice *d = PCI_DEVICE(s);
int res;

res = msi_init(d, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
if (0 > res) {
VMW_WRPRN("Failed to initialize MSI, error %d", res);
s->msi_used = false;
} else {
s->msi_used = true;
}

return s->msi_used;
}

static void
vmxnet3_cleanup_msi(VMXNET3State *s)
{
Expand Down Expand Up @@ -2298,10 +2277,15 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s)
return dsn_payload;
}


#define VMXNET3_USE_64BIT (true)
#define VMXNET3_PER_VECTOR_MASK (false)

static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
{
DeviceState *dev = DEVICE(pci_dev);
VMXNET3State *s = VMXNET3(pci_dev);
int ret;

VMW_CBPRN("Starting init...");

Expand All @@ -2325,14 +2309,17 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
/* Interrupt pin A */
pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;

ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error. Fall back to INTx silently on -ENOTSUP */
assert(!ret || ret == -ENOTSUP);
s->msi_used = !ret;

if (!vmxnet3_init_msix(s)) {
VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent.");
}

if (!vmxnet3_init_msi(s)) {
VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent.");
}

vmxnet3_net_init(s);

if (pci_is_express(pci_dev)) {
Expand Down
6 changes: 5 additions & 1 deletion hw/pci-bridge/ioh3420.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "ioh3420.h"
#include "qapi/error.h"

#define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */
#define PCI_DEVICE_ID_IOH_REV 0x2
Expand Down Expand Up @@ -97,6 +98,7 @@ static int ioh3420_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
PCIESlot *s = PCIE_SLOT(d);
int rc;
Error *err = NULL;

pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);
Expand All @@ -109,8 +111,10 @@ static int ioh3420_initfn(PCIDevice *d)

rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
assert(rc == -ENOTSUP);
error_report_err(err);
goto err_bridge;
}

Expand Down
20 changes: 16 additions & 4 deletions hw/pci-bridge/pci_bridge_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
PCIBridge *br = PCI_BRIDGE(dev);
PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
int err;
Error *local_err = NULL;

pci_bridge_initfn(dev, TYPE_PCI_BUS);

Expand All @@ -75,12 +76,23 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
goto slotid_error;
}

if (bridge_dev->msi != ON_OFF_AUTO_OFF &&
msi_nonbroken) {
err = msi_init(dev, 0, 1, true, true);
if (err < 0) {
if (bridge_dev->msi != ON_OFF_AUTO_OFF) {
/* it means SHPC exists, because MSI is needed by SHPC */

err = msi_init(dev, 0, 1, true, true, &local_err);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error */
assert(!err || err == -ENOTSUP);
if (err && bridge_dev->msi == ON_OFF_AUTO_ON) {
/* Can't satisfy user's explicit msi=on request, fail */
error_append_hint(&local_err, "You have to use msi=auto (default) "
"or msi=off with this machine type.\n");
error_report_err(local_err);
goto msi_error;
}
assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO);
/* With msi=auto, we fall back to MSI off silently */
error_free(local_err);
}

if (shpc_present(dev)) {
Expand Down
6 changes: 5 additions & 1 deletion hw/pci-bridge/xio3130_downstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_downstream.h"
#include "qapi/error.h"

#define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */
#define XIO3130_REVISION 0x1
Expand Down Expand Up @@ -60,14 +61,17 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIEPort *p = PCIE_PORT(d);
PCIESlot *s = PCIE_SLOT(d);
int rc;
Error *err = NULL;

pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);

rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
assert(rc == -ENOTSUP);
error_report_err(err);
goto err_bridge;
}

Expand Down
6 changes: 5 additions & 1 deletion hw/pci-bridge/xio3130_upstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "xio3130_upstream.h"
#include "qapi/error.h"

#define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */
#define XIO3130_REVISION 0x2
Expand Down Expand Up @@ -56,14 +57,17 @@ static int xio3130_upstream_initfn(PCIDevice *d)
{
PCIEPort *p = PCIE_PORT(d);
int rc;
Error *err = NULL;

pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);

rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
if (rc < 0) {
assert(rc == -ENOTSUP);
error_report_err(err);
goto err_bridge;
}

Expand Down
11 changes: 8 additions & 3 deletions hw/pci/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "hw/pci/msi.h"
#include "hw/xen/xen.h"
#include "qemu/range.h"
#include "qapi/error.h"

/* PCI_MSI_ADDRESS_LO */
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
Expand Down Expand Up @@ -173,22 +174,25 @@ bool msi_enabled(const PCIDevice *dev)
* If @msi64bit, make the device capable of sending a 64-bit message
* address.
* If @msi_per_vector_mask, make the device support per-vector masking.
* Return 0 on success, return -errno on error.
* @errp is for returning errors.
* Return 0 on success; set @errp and return -errno on error.
*
* -ENOTSUP means lacking msi support for a msi-capable platform.
* -EINVAL means capability overlap, happens when @offset is non-zero,
* also means a programming error, except device assignment, which can check
* if a real HW is broken.
*/
int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
unsigned int nr_vectors, bool msi64bit,
bool msi_per_vector_mask, Error **errp)
{
unsigned int vectors_order;
uint16_t flags;
uint8_t cap_size;
int config_offset;

if (!msi_nonbroken) {
error_setg(errp, "MSI is not supported by interrupt controller");
return -ENOTSUP;
}

Expand All @@ -212,7 +216,8 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
}

cap_size = msi_cap_sizeof(flags);
config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
config_offset = pci_add_capability2(dev, PCI_CAP_ID_MSI, offset,
cap_size, errp);
if (config_offset < 0) {
return config_offset;
}
Expand Down
26 changes: 21 additions & 5 deletions hw/scsi/megasas.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "hw/scsi/scsi.h"
#include "block/scsi.h"
#include "trace.h"

#include "qapi/error.h"
#include "mfi.h"

#define MEGASAS_VERSION_GEN1 "1.70"
Expand Down Expand Up @@ -2330,6 +2330,8 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s);
uint8_t *pci_conf;
int i, bar_type;
Error *err = NULL;
int ret;

pci_conf = dev->config;

Expand All @@ -2338,17 +2340,31 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
/* Interrupt pin 1 */
pci_conf[PCI_INTERRUPT_PIN] = 0x01;

if (megasas_use_msi(s)) {
ret = msi_init(dev, 0x50, 1, true, false, &err);
/* Any error other than -ENOTSUP(board's MSI support is broken)
* is a programming error */
assert(!ret || ret == -ENOTSUP);
if (ret && s->msi == ON_OFF_AUTO_ON) {
/* Can't satisfy user's explicit msi=on request, fail */
error_append_hint(&err, "You have to use msi=auto (default) or "
"msi=off with this machine type.\n");
error_propagate(errp, err);
return;
} else if (ret) {
/* With msi=auto, we fall back to MSI off silently */
s->msi = ON_OFF_AUTO_OFF;
error_free(err);
}
}

memory_region_init_io(&s->mmio_io, OBJECT(s), &megasas_mmio_ops, s,
"megasas-mmio", 0x4000);
memory_region_init_io(&s->port_io, OBJECT(s), &megasas_port_ops, s,
"megasas-io", 256);
memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
"megasas-queue", 0x40000);

if (megasas_use_msi(s) &&
msi_init(dev, 0x50, 1, true, false)) {
s->msi = ON_OFF_AUTO_OFF;
}
if (megasas_use_msix(s) &&
msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
&s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
Expand Down
Loading

0 comments on commit 1108b2f

Please sign in to comment.