All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Cédric Le Goater" <clg@redhat.com>
To: Alex Williamson <alex@shazbot.org>
Cc: qemu-devel@nongnu.org,
	Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>,
	Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>,
	Jason Wang <jasowangio@gmail.com>, Peter Xu <peterx@redhat.com>
Subject: Re: [RFC PATCH v2 1/9] igb: Add x-vf-migration property and DVSEC extended capability
Date: Mon, 7 Sep 2026 22:58:02 +0200	[thread overview]
Message-ID: <91423389-8f61-475d-8993-2966286f4f4f@redhat.com> (raw)
In-Reply-To: <20260903135736.6b527d04@shazbot.org>

On 9/3/26 21:57, Alex Williamson wrote:
> On Wed,  2 Sep 2026 21:20:46 +0200
> Cédric Le Goater <clg@redhat.com> wrote:
> 
>> diff --git a/hw/net/igb_migration.c b/hw/net/igb_migration.c
>> new file mode 100644
>> index 000000000000..4dfebd82344c
>> --- /dev/null
>> +++ b/hw/net/igb_migration.c
>> @@ -0,0 +1,106 @@
>> +/*
>> + * QEMU Intel 82576 SR/IOV VF Migration Support
>> + *
>> + * Copyright (c) 2026 Red Hat, Inc.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/pci/pci_device.h"
>> +#include "hw/pci/pcie.h"
>> +#include "igb_common.h"
>> +#include "igb_migration.h"
>> +
>> +static void igbvf_mig_update_status(IgbVfState *s, uint8_t err)
>> +{
>> +    IgbVfMigState *ms = &s->mig;
>> +    PCIDevice *dev = PCI_DEVICE(s);
>> +    uint32_t status;
>> +
>> +    status = ms->mig_state & IGB_MIG_STATUS_STATE_MASK;
>> +
>> +    if (err) {
>> +        status = IGB_MIG_STATE_ERROR | IGB_MIG_STATUS_ERR(err);
>> +    }
>> +
>> +    pci_set_long(dev->config + IGB_MIG_DVSEC_OFFSET + IGB_MIG_STATUS, status);
>> +}
>> +
>> +
>> +bool igbvf_add_migration_dvsec(PCIDevice *dev, Error **errp)
>> +{
>> +    uint16_t offset = IGB_MIG_DVSEC_OFFSET;
>> +    uint32_t caps;
>> +
>> +    pcie_add_capability(dev, PCI_EXT_CAP_ID_DVSEC, 1, offset,
>> +                        IGB_MIG_DVSEC_SIZE);
>> +
>> +    /* DVSEC header 1: length[31:20] | rev[19:16] | vendor_id[15:0] */
>> +    pci_set_long(dev->config + offset + 0x4,
>> +                 (IGB_MIG_DVSEC_SIZE << 20) |
>> +                 (IGB_MIG_DVSEC_VER << 16) |
>> +                 PCI_VENDOR_ID_INTEL);
> 
> Let's not co-opt an Intel DVSEC ID, we should use a vendor ID that we
> have a claim to, the RedHat/Qumranet one, I'd guess.  We may need to
> add DVSEC IDs to the spreadsheet for whoever is tracking Device IDs.
> Gerd?
> 
>> +
>> +    /* DVSEC header 2: DVSEC ID */
>> +    pci_set_word(dev->config + offset + 0x8, IGB_MIG_DVSEC_ID);
>> +
>> +    /* CAPS: features (state migration only) */
>> +    caps = IGB_MIG_CAP_F_STATE;
>> +    pci_set_long(dev->config + offset + IGB_MIG_CAPS, caps);
>> +
>> +    /* STATUS: initial state is RUNNING */
>> +    pci_set_long(dev->config + offset + IGB_MIG_STATUS,
>> +                 IGB_MIG_STATE_RUNNING);
>> +
>> +    /* BUF_ADDR_LO and BUF_ADDR_HI are writable */
>> +    memset(dev->wmask + offset + IGB_MIG_BUF_ADDR_LO, 0xff, 4);
>> +    memset(dev->wmask + offset + IGB_MIG_BUF_ADDR_HI, 0xff, 4);
>> +
>> +    return true;
>> +}
> ...
>> diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
>> index 9a165c7063ee..30dfdb574ac7 100644
>> --- a/hw/net/igbvf.c
>> +++ b/hw/net/igbvf.c
>> @@ -38,27 +38,21 @@
>>    */
>>   
>>   #include "qemu/osdep.h"
>> +#include "qemu/range.h"
>>   #include "hw/core/hw-error.h"
>>   #include "hw/net/mii.h"
>>   #include "hw/pci/pci_device.h"
>>   #include "hw/pci/pcie.h"
>> +#include "hw/pci/pcie_sriov.h"
>>   #include "hw/pci/msix.h"
>>   #include "net/eth.h"
>>   #include "net/net.h"
>>   #include "igb_common.h"
>>   #include "igb_core.h"
>> +#include "igb_migration.h"
>>   #include "trace.h"
>>   #include "qapi/error.h"
>>   
>> -OBJECT_DECLARE_SIMPLE_TYPE(IgbVfState, IGBVF)
>> -
>> -struct IgbVfState {
>> -    PCIDevice parent_obj;
>> -
>> -    MemoryRegion mmio;
>> -    MemoryRegion msix;
>> -};
>> -
>>   static hwaddr vf_to_pf_addr(hwaddr addr, uint16_t vfn, bool write)
>>   {
>>       switch (addr) {
>> @@ -199,10 +193,35 @@ static hwaddr vf_to_pf_addr(hwaddr addr, uint16_t vfn, bool write)
>>       return HWADDR_MAX;
>>   }
>>   
>> +static bool igbvf_addr_in_dvsec(uint32_t addr, int len)
>> +{
>> +    return ranges_overlap(addr, len,
>> +                          IGB_MIG_DVSEC_OFFSET, IGB_MIG_DVSEC_SIZE);
>> +}
>> +
>> +static uint32_t igbvf_read_config(PCIDevice *dev, uint32_t addr, int size)
>> +{
>> +    IgbVfState *s = IGBVF(dev);
>> +
>> +    if (s->migration_enabled && igbvf_addr_in_dvsec(addr, size)) {
>> +        return igbvf_mig_config_read(s, addr, size);
>> +    }
>> +
>> +    return pci_default_read_config(dev, addr, size);
>> +}
>> +
>>   static void igbvf_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
>>       int len)
>>   {
>> +    IgbVfState *s = IGBVF(dev);
>> +
>>       trace_igbvf_write_config(addr, val, len);
>> +
>> +    if (s->migration_enabled && igbvf_addr_in_dvsec(addr, len)) {
>> +        igbvf_mig_config_write(s, addr, val, len);
>> +        return;
>> +    }
>> +
>>       pci_default_write_config(dev, addr, val, len);
>>       if (object_property_get_bool(OBJECT(pcie_sriov_get_pf(dev)),
>>                                    "x-pcie-flr-init", &error_abort)) {
>> @@ -282,13 +301,27 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
>>       }
>>   
>>       pcie_ari_init(dev, 0x150);
>> +
>> +    if (object_property_get_bool(OBJECT(pcie_sriov_get_pf(dev)),
>> +                                 "x-vf-migration", &error_abort)) {
>> +        s->vfn = pcie_sriov_vf_number(dev);
>> +        s->migration_enabled = true;
>> +        if (!igbvf_add_migration_dvsec(dev, errp)) {
>> +            return;
>> +        }
> 
> The migration blocker noted later in the docs should be added here.
> Trivial to add, avoids the internal migration state being reset by the
> L0 VM being migrated, doesn't seem worth extending this driver's VMState
> while the feature is experimental.
> 
>> +    }
>>   }
>>   
>>   static void igbvf_qdev_reset_hold(Object *obj, ResetType type)
>>   {
>>       PCIDevice *vf = PCI_DEVICE(obj);
>> +    IgbVfState *s = IGBVF(vf);
>>   
>>       igb_vf_reset(pcie_sriov_get_pf(vf), pcie_sriov_vf_number(vf));
>> +
>> +    if (s->migration_enabled) {
>> +        igbvf_mig_state_reset(s);
>> +    }
> 
> Hmm, I think reset is more complicated that this.  This seems to define
> that any device reset will reset the migration state.  The vfio
> migration protocol only defines that a VFIO_DEVICE_RESET returns the
> device to running.
> 
> Consider the case of an FLR triggered by the L2 guest.  L1 QEMU passes
> through the config space write, that lands in vfio-pci core config
> space handling in the L1 variant driver, which turns into a
> pci_reset_function() in the L1 kernel and I think lands here in the L0
> QEMU.  Therefore, it seems like the L2 guest can corrupt the migration
> state.
> 
> As above, the migration state is defined to be reset via the RESET
> ioctl, which also turns into a pci_reset_function() in the L1 kernel.
> So L0 QEMU can't tell the difference here.
> 
> I think that means that the variant driver itself needs to own this
> part of the protocol, performing the migration state housekeeping on
> RESET ioctl, while both allow the state to persist on other resets.  In
> that sense QEMU cannot emulate this DVSEC as normal config space, it's
> a persistent control plane that lives in the VMM and happens to be
> accessed through config space.  Thanks,


Hi Alex,
  
You are right. The key principle: The DVSEC is a persistent control
plane living in the VMM, not device state. Device reset (VFIO ioctl
and L2 FLR) resets the device, not the mailbox. The variant driver
owns the reset, not the emulated device in L0 QEMU.

I missed two things : 1. transferring the DVSEC hiding (as it was done
for the mig BAR) and 2. reset of migration state.

Looking closer at it, the changes are small.

In QEMU:

The cold boot initialization sets all fields to defaults (zero). The
only change from today is that the initial state is ERROR, which means
migration isn't operational until the driver binds. The variant driver
activates the control plane by cycling the machine state to RUNNING.

The VF functional registers (queues, DMA rings, interrupts ... ) are
reset normally by igb_core_vf_reset(), and the migration control plane
(IgbVfMigState) persists in memory. It survives pci_do_device_reset()
and the variant driver sets the fields as needed through the normal
DVSEC command flow.

BUF_ADDR could be restored from the IgbVfMigState cache values since
it's a RW reg, but even that isn't a strong requirement.

So igbvf_mig_state_reset() is no longer needed in the reset path.
That's all for QEMU.

Driver :

Variant driver owns all the cleanup after reset: closes migration fds,
disables dirty tracking, reads and cycles the DVSEC state back to
RUNNING.

The first path, VFIO_DEVICE_RESET, needs a custom ioctl handler to run
the cleanup.

Second path, L2 FLR. To hide the DVSEC range from the L2 guest, the
driver implements custom VFIO config space reads and writes. The
config write handler can detect the FLR and implement the same cleanup
logic.

That's for v3.

Thanks,

C.




  reply	other threads:[~2026-09-07 20:59 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-02 19:20 [RFC PATCH v2 0/9] igb: Add experimental VF live migration support Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 1/9] igb: Add x-vf-migration property and DVSEC extended capability Cédric Le Goater
2026-09-03 19:57   ` Alex Williamson
2026-09-07 20:58     ` Cédric Le Goater [this message]
2026-09-02 19:20 ` [RFC PATCH v2 2/9] igb: Add migration state machine via extended config space Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 3/9] igb: Add VF state serialization for live migration Cédric Le Goater
2026-09-08  8:01   ` Akihiko Odaki
2026-09-15  7:47     ` Cédric Le Goater
2026-09-17 18:59       ` Akihiko Odaki
2026-09-02 19:20 ` [RFC PATCH v2 4/9] igb: Add VF post-load fixups " Cédric Le Goater
2026-09-08  8:10   ` Akihiko Odaki
2026-09-15  7:58     ` Cédric Le Goater
2026-09-17 19:01       ` Akihiko Odaki
2026-09-02 19:20 ` [RFC PATCH v2 5/9] igb: Add dirty page tracking for IGBVF migration Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 6/9] igb: Quiesce VFs on STOP and include PF enable state in migration Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 7/9] igb: Fix post-migration RX ring deadlock Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 8/9] igb: Add dirty page tracking statistics Cédric Le Goater
2026-09-02 19:20 ` [RFC PATCH v2 9/9] docs: Add igb VF migration testing setup guide Cédric Le Goater
2026-09-08  8:39   ` Akihiko Odaki
2026-09-15  7:59     ` Cédric Le Goater
2026-09-09  7:19 ` [RFC PATCH v2 0/9] igb: Add experimental VF live migration support Akihiko Odaki
2026-09-15  8:20   ` Cédric Le Goater
2026-09-17 19:49     ` Akihiko Odaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=91423389-8f61-475d-8993-2966286f4f4f@redhat.com \
    --to=clg@redhat.com \
    --cc=alex@shazbot.org \
    --cc=jasowangio@gmail.com \
    --cc=odaki@rsg.ci.i.u-tokyo.ac.jp \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sriram.yagnaraman@ericsson.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.