[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init()
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init() |
Date: |
Fri, 08 Apr 2016 10:44:49 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) |
Cao jin <address@hidden> writes:
> Add param Error **errp, and change pci_add_capability() to
> pci_add_capability2(), because pci_add_capability() report error, and
> msi_init() is widely used in realize(), so it is not suitable for realize()
Suggest:
pci: Convert msi_init() to Error and fix callers to check it
msi_init() reports errors with error_report(), which is wrong when
it's used in realize().
Fix by converting it to Error.
But see the discussion of the msi_init() failure modes below; commit
message may need further work for that.
Same issue in msix_init(). Please fix that as well, if it's not too
much trouble.
> Also fix all the callers who should deal with the msi_init() failure
> but actually not.
Grammar: "but actually don't" (you need a verb).
You neglect to explain the bug's impact. Something like
Fix its callers to handle failure instead of ignoring it.
[Description on what goes wrong because of that goes here]
>
> Signed-off-by: Cao jin <address@hidden>
> ---
> hw/audio/intel-hda.c | 11 +++++++---
> hw/ide/ich.c | 2 +-
> hw/net/vmxnet3.c | 41
> +++++++++++++++-----------------------
> hw/pci-bridge/ioh3420.c | 4 +++-
> hw/pci-bridge/pci_bridge_dev.c | 4 +++-
> hw/pci-bridge/xio3130_downstream.c | 4 +++-
> hw/pci-bridge/xio3130_upstream.c | 4 +++-
> hw/pci/msi.c | 9 +++++++--
> hw/scsi/megasas.c | 12 +++++++----
> hw/scsi/mptsas.c | 15 +++++++++-----
> hw/scsi/vmw_pvscsi.c | 6 +++++-
> hw/usb/hcd-xhci.c | 10 +++++++---
> hw/vfio/pci.c | 6 ++++--
> include/hw/pci/msi.h | 3 ++-
> 14 files changed, 80 insertions(+), 51 deletions(-)
>
> diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
> index d372d4a..c3856cc 100644
> --- a/hw/audio/intel-hda.c
> +++ b/hw/audio/intel-hda.c
> @@ -1139,12 +1139,17 @@ 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) {
> + msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1,
> + true, false, errp);
> + if (*errp) {
Crash bug if errp is null. I guess it's never null here right now, but
let's not rely on that for robustness, and to avoid setting a bad
example. Bad examples multiply like rabbits.
The big comment in error.h explains how to receive an error correctly:
* Receive an error and pass it on to the caller:
* Error *err = NULL;
* foo(arg, &err);
* if (err) {
* handle the error...
* error_propagate(errp, err);
* }
* where Error **errp is a parameter, by convention the last one.
This is what you should do here.
*
* Do *not* "optimize" this to
* foo(arg, errp);
* if (*errp) { // WRONG!
* handle the error...
* }
* because errp may be NULL!
This is what your patch does.
*
* But when all you do with the error is pass it on, please use
* foo(arg, errp);
* for readability.
*
> + return;
> + }
> + }
> +
> 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) {
> - 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);
> diff --git a/hw/ide/ich.c b/hw/ide/ich.c
> index 0a13334..db4fdb5 100644
> --- a/hw/ide/ich.c
> +++ b/hw/ide/ich.c
> @@ -146,7 +146,7 @@ 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);
> + msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false, errp);
Sure there's nothing to undo on error? Instead of undoing, you may want
to move msi_init() before the stuff that needs undoing.
> }
>
> static void pci_ich9_uninit(PCIDevice *dev)
> diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
> index 7a38e47..d8dbb0b 100644
> --- a/hw/net/vmxnet3.c
> +++ b/hw/net/vmxnet3.c
> @@ -2189,27 +2189,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)
> {
> @@ -2271,13 +2250,29 @@ static uint8_t
> *vmxnet3_device_serial_num(VMXNET3State *s)
> return dsnp;
> }
>
> +
> +#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...");
>
> + ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
> + VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, errp);
> + if (ret < 0) {
> + error_free_or_abort(errp);
Aborts when errp is null.
> + VMW_WRPRN("Failed to initialize MSI, error = %d."
> + " Configuration is inconsistent.", ret);
For friendlier debug messages, you could do
ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, &err);
if (ret < 0) {
VMW_WRPRN("Failed to initialize MSI: %s", error_get_pretty(err);
error_free(err);
However, begs the question why we let realize succeed after msi_init()
failure for this device, but not for others. See discussion of
msi_init() failure modes below.
> + s->msi_used = false;
> + } else {
> + s->msi_used = true;
> + }
> +
> memory_region_init_io(&s->bar0, OBJECT(s), &b0_ops, s,
> "vmxnet3-b0", VMXNET3_PT_REG_SIZE);
> pci_register_bar(pci_dev, VMXNET3_BAR0_IDX,
> @@ -2302,10 +2297,6 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev,
> Error **errp)
> 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)) {
> diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
> index b4a7806..d752e62 100644
> --- a/hw/pci-bridge/ioh3420.c
> +++ b/hw/pci-bridge/ioh3420.c
> @@ -97,6 +97,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);
> @@ -109,8 +110,9 @@ 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) {
> + error_report_err(err);
> goto err_bridge;
> }
>
> diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
> index 32f4daa..07c7bf8 100644
> --- a/hw/pci-bridge/pci_bridge_dev.c
> +++ b/hw/pci-bridge/pci_bridge_dev.c
> @@ -52,6 +52,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);
>
> @@ -75,8 +76,9 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
>
> if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
> msi_nonbroken) {
> - err = msi_init(dev, 0, 1, true, true);
> + err = msi_init(dev, 0, 1, true, true, &local_err);
> if (err < 0) {
> + error_report_err(local_err);
> goto msi_error;
> }
> }
> diff --git a/hw/pci-bridge/xio3130_downstream.c
> b/hw/pci-bridge/xio3130_downstream.c
> index e6d653d..0982801 100644
> --- a/hw/pci-bridge/xio3130_downstream.c
> +++ b/hw/pci-bridge/xio3130_downstream.c
> @@ -60,14 +60,16 @@ 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) {
> + error_report_err(err);
> goto err_bridge;
> }
>
> diff --git a/hw/pci-bridge/xio3130_upstream.c
> b/hw/pci-bridge/xio3130_upstream.c
> index d976844..1d2c597 100644
> --- a/hw/pci-bridge/xio3130_upstream.c
> +++ b/hw/pci-bridge/xio3130_upstream.c
> @@ -56,14 +56,16 @@ 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) {
> + error_report_err(err);
> goto err_bridge;
> }
>
> diff --git a/hw/pci/msi.c b/hw/pci/msi.c
> index e2a701b..bf7a3b9 100644
> --- a/hw/pci/msi.c
> +++ b/hw/pci/msi.c
> @@ -179,14 +179,17 @@ bool msi_enabled(const PCIDevice *dev)
> * -ENOTSUP means lacking msi support for a msi-capable platform.
> */
> 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;
> + Error *err = NULL;
>
> if (!msi_nonbroken) {
> + error_setg(errp, "MSI is not supported by interrupt controller");
> return -ENOTSUP;
> }
>
> @@ -210,8 +213,10 @@ 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, &err);
> if (config_offset < 0) {
> + error_propagate(errp, err);
> return config_offset;
> }
>
msi_init() has three failure modes:
* -ENOTSUP
Board's MSI emulation is not known to work: !msi_nonbroken.
This is not necessarily an error.
It is when the device model requires MSI.
It isnt' when a non-MSI variant of the device model exists. Then
caller should silently switch to the non-MSI variant[*].
* -ENOSPC
Out of PCI config space. Can happen only when offset == 0. I believe
this is a programming error, and therefore should be an assertion
failure. But changing pci_add_capability2() that way is outside this
patch's scope, and up to the PCI maintainers.
* -EINVAL
PCI capabilities overlap. Can happen only when offset != 0. Also a
programming error, except when assigning a physical device. There,
it's a broken physical device.
So, for devices with a non-MSI variant, realize() should use msi_init()
like this:
ret = msi_init(..., &err);
if (ret == -ENOTSUP) {
error_free(err);
[switch off MSI]
} else if (ret < 0) {
error_propagate(errp, err);
[handle error]
}
Your patch lacks the special -ENOTSUP case.
init() should error_report_err() + return -1 instead of
error_propagate(), of course.
[handle error] needs to take care to revert previous side effects.
For devices that require MSI, it's either
msi_init(..., &err);
if (err) {
error_propagate(errp, err);
[handle error]
}
or
if (msi_init(..., errp)) {
[handle error]
}
I don't have the time to review the rest of the patch now, but I hope
this is enough for a productive v5.
[...]
[*] Inappropriate when the user ordered msi=on, but that's outside this
patch's scope.
- [Qemu-devel] [PATCH v4 4/5] mptsas: change .realize function name, (continued)
- [Qemu-devel] [PATCH v4 4/5] mptsas: change .realize function name, Cao jin, 2016/04/05
- [Qemu-devel] [PATCH v4 1/5] fix some coding style problems, Cao jin, 2016/04/05
- [Qemu-devel] [PATCH v4 3/5] megasas: bugfix, Cao jin, 2016/04/05
- [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/05
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(),
Markus Armbruster <=
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/09
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/09
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Marcel Apfelbaum, 2016/04/10
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/10
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Marcel Apfelbaum, 2016/04/11
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/11
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Markus Armbruster, 2016/04/12
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Cao jin, 2016/04/29
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Markus Armbruster, 2016/04/29
- Re: [Qemu-devel] [PATCH v4 5/5] Add param Error ** for msi_init(), Markus Armbruster, 2016/04/12