qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [PATCH RFC] pcie: clean up hot plug notification


From: Michael S. Tsirkin
Subject: [Qemu-devel] Re: [PATCH RFC] pcie: clean up hot plug notification
Date: Mon, 25 Oct 2010 08:46:38 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

On Mon, Oct 25, 2010 at 03:44:01PM +0900, Isaku Yamahata wrote:
> On Mon, Oct 25, 2010 at 07:49:41AM +0200, Michael S. Tsirkin wrote:
> > Simplify logic for hotplug notification, by tracking state of the
> > logical interrupt condition.  We then simply use this variable to make
> > the interrupt decision, according to spec.
> > 
> > API is made cleaner as we no longer force users to pass in
> > old slot control value.
> 
> Thank you for looking into it.
> Some comments below.

Thanks! Care fixing up the remaining issues?
I will fold the fixup in.

> > 
> > Untested.
> > 
> > Signed-off-by: Michael S. Tsirkin <address@hidden>
> > ---
> >  hw/ioh3420.c            |    5 +--
> >  hw/pcie.c               |   79 
> > ++++++++++++++++++++++------------------------
> >  hw/pcie.h               |    8 +++-
> >  hw/xio3130_downstream.c |    5 +--
> >  4 files changed, 46 insertions(+), 51 deletions(-)
> > 
> > diff --git a/hw/ioh3420.c b/hw/ioh3420.c
> > index 1f340d3..23aecbf 100644
> > --- a/hw/ioh3420.c
> > +++ b/hw/ioh3420.c
> > @@ -39,12 +39,9 @@
> >  static void ioh3420_write_config(PCIDevice *d,
> >                                     uint32_t address, uint32_t val, int len)
> >  {
> > -    uint16_t sltctl =
> > -        pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
> > -
> >      pci_bridge_write_config(d, address, val, len);
> >      msi_write_config(d, address, val, len);
> > -    pcie_cap_slot_write_config(d, address, val, len, sltctl);
> > +    pcie_cap_slot_write_config(d, address, val, len);
> >      /* TODO: AER */
> >  }
> >  
> > diff --git a/hw/pcie.c b/hw/pcie.c
> > index c972337..74d2c18 100644
> > --- a/hw/pcie.c
> > +++ b/hw/pcie.c
> > @@ -155,20 +155,11 @@ static void pcie_cap_slot_event(PCIDevice *dev, 
> > PCIExpressHotPlugEvent event)
> >                      "sltctl: 0x%02"PRIx16" sltsta: 0x%02"PRIx16" event: 
> > %x\n",
> >                      sltctl, sltsta, event);
> >  
> > +    /* Minor optimization: if nothing changed - no event is needed. */
> >      if (pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, event)) {
> >          return;
> >      }
> > -    sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> > -    PCIE_DEV_PRINTF(dev, "sltsta -> %02"PRIx16"\n", sltsta);
> > -
> > -    if ((sltctl & PCI_EXP_SLTCTL_HPIE) &&
> > -        (sltctl & event & PCI_EXP_HP_EV_SUPPORTED)) {
> > -        if (pci_msi_enabled(dev)) {
> > -            pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
> > -        } else {
> > -            qemu_set_irq(dev->irq[dev->exp.hpev_intx], 1);
> > -        }
> > -    }
> > +    hotplug_event_notify(dev);
> >  }
> 
> The forward declaration of hotplug_event_notify() is necessary.
> Or move up hotplug_event_notify().

fixed up already

> >  
> >  static int pcie_cap_slot_hotplug(DeviceState *qdev,
> > @@ -212,6 +203,36 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev,
> >      return 0;
> >  }
> >  
> > +static void hotplug_event_notify(PCIDevice *dev)
> > +{
> > +    bool prev = dev->exp.hpev_notified;
> > +    uint32_t pos = dev->exp.exp_cap;
> > +    uint8_t *exp_cap = dev->config + pos;
> > +    uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
> > +    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
> > +
> > +    dev->exp.hpev_notified = (sltctl & PCI_EXP_SLTCTL_HPIE) &&
> > +        (sltsta & PCI_EXP_HP_EV_SUPPORTED)
> 
> should be (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED) instead of
> (sltsta & PCI_EXP_HP_EV_SUPPORTED).


Right. Care sending a patch on top of current pci branch?

> 
> > +
> > +    if (prev == dev->exp.hpev_notified) {
> > +        return;
> > +    }
> > +
> > +    /* Note: the logic above does not take into account whether interrupts
> > +     * are masked. The result is that interrupt will be sent when it is
> > +     * subsequently unmasked. This appears to be legal: Section 6.7.3.4:
> > +     * The Port may optionally send an MSI when there are hot-plug events 
> > that
> > +     * occur while interrupt generation is disabled, and interrupt 
> > generation is
> > +     * subsequently enabled. */
> > +    if (!pci_msi_enabled(dev)) {
> > +        qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
> > +    } else if (dev->exp.hpev_notified) {
> > +        pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
> > +        return;
> 
> This return seems redundant.

right. remove it

> > +    }
> > +
> > +}
> > +
> >  /* pci express slot for pci express root/downstream port
> >     PCI express capability slot registers */
> >  void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
> > @@ -256,6 +277,8 @@ void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
> >      pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
> >                                 PCI_EXP_HP_EV_SUPPORTED);
> >  
> > +    dev->cap.hpev_notified = false;
> > +
> >      pci_bus_hotplug(pci_bridge_get_sec_bus(DO_UPCAST(PCIBridge, dev, dev)),
> >                      pcie_cap_slot_hotplug, &dev->qdev);
> >  }
> > @@ -284,11 +307,12 @@ void pcie_cap_slot_reset(PCIDevice *dev)
> >                                   PCI_EXP_SLTSTA_CC |
> >                                   PCI_EXP_SLTSTA_PDC |
> >                                   PCI_EXP_SLTSTA_ABP);
> > +
> > +    hotplug_event_notify(dev);
> >  }
> >  
> >  void pcie_cap_slot_write_config(PCIDevice *dev,
> > -                                uint32_t addr, uint32_t val, int len,
> > -                                uint16_t sltctl_prev)
> > +                                uint32_t addr, uint32_t val, int len)
> >  {
> >      uint32_t pos = dev->exp.exp_cap;
> >      uint8_t *exp_cap = dev->config + pos;
> > @@ -313,34 +337,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
> >                          sltsta);
> >      }
> >  
> > -    /*
> > -     * The events control bits might be enabled or disabled,
> > -     * Check if the software notificastion condition is satisfied
> > -     * or disatisfied.
> > -     *
> > -     * 6.7.3.4 Software Notification of Hot-plug events
> > -     */
> > -    if (pci_msi_enabled(dev)) {
> > -        bool msi_trigger =
> > -            (sltctl & PCI_EXP_SLTCTL_HPIE) &&
> > -            ((sltctl_prev ^ sltctl) & sltctl & /* stlctl: 0 -> 1 */
> > -             sltsta & PCI_EXP_HP_EV_SUPPORTED);
> > -        if (msi_trigger) {
> > -            pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
> > -        }
> > -    } else {
> > -        int int_level =
> > -            (sltctl & PCI_EXP_SLTCTL_HPIE) &&
> > -            (sltctl & sltsta & PCI_EXP_HP_EV_SUPPORTED);
> > -        qemu_set_irq(dev->irq[dev->exp.hpev_intx], int_level);
> > -    }
> > -
> > -    if (!((sltctl_prev ^ sltctl) & PCI_EXP_SLTCTL_SUPPORTED)) {
> > -        PCIE_DEV_PRINTF(dev,
> > -                        "sprious command completion slctl "
> > -                        "0x%"PRIx16" -> 0x%"PRIx16"\n",
> > -                        sltctl_prev, sltctl);
> > -    }
> > +    hotplug_event_notify(dev);
> >  
> >      /* command completion.
> >       * Real hardware might take a while to complete
> > diff --git a/hw/pcie.h b/hw/pcie.h
> > index 2871e27..39c6e47 100644
> > --- a/hw/pcie.h
> > +++ b/hw/pcie.h
> > @@ -74,6 +74,11 @@ struct PCIExpressDevice {
> >                                   * also initialize it when loaded as
> >                                   * appropreately.
> >                                   */
> > +    bool hpev_notified; /* Logical AND of conditions for hot plug event.
> > +                         Following 6.7.3.4:
> > +                         Software Notification of Hot-Plug Events, an 
> > interrupt
> > +                         is sent whenever the logical and of these 
> > conditions
> > +                         transitions from false to true. */
> >  };
> 
> This breaks save/load.

Right. We'll need to restore this on load.
Take a subfunction of hotplug_event_notify
and put it in the appropriate _load function.

> 
> >  
> >  /* PCI express capability helper functions */
> > @@ -89,8 +94,7 @@ void pcie_cap_deverr_reset(PCIDevice *dev);
> >  void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
> >  void pcie_cap_slot_reset(PCIDevice *dev);
> >  void pcie_cap_slot_write_config(PCIDevice *dev,
> > -                                uint32_t addr, uint32_t val, int len,
> > -                                uint16_t sltctl_prev);
> > +                                uint32_t addr, uint32_t val, int len);
> >  void pcie_cap_slot_push_attention_button(PCIDevice *dev);
> >  
> >  void pcie_cap_root_init(PCIDevice *dev);
> > diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
> > index a44e188..d46f911 100644
> > --- a/hw/xio3130_downstream.c
> > +++ b/hw/xio3130_downstream.c
> > @@ -38,12 +38,9 @@
> >  static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
> >                                           uint32_t val, int len)
> >  {
> > -    uint16_t sltctl =
> > -        pci_get_word(d->config + d->exp.exp_cap + PCI_EXP_SLTCTL);
> > -
> >      pci_bridge_write_config(d, address, val, len);
> >      pcie_cap_flr_write_config(d, address, val, len);
> > -    pcie_cap_slot_write_config(d, address, val, len, sltctl);
> > +    pcie_cap_slot_write_config(d, address, val, len);
> >      msi_write_config(d, address, val, len);
> >      /* TODO: AER */
> >  }
> > -- 
> > 1.7.3-rc1
> > 
> 
> -- 
> yamahata



reply via email to

[Prev in Thread] Current Thread [Next in Thread]