qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Don Slutz <dslutz@verizon.com>
Cc: Paul Durrant <paul.durrant@citrix.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Subject: Re: [Qemu-devel] [PATCH 1/1] Fix device listener interface for PCI to PCI bridges
Date: Thu, 28 May 2015 14:28:50 +0200	[thread overview]
Message-ID: <20150528142229-mutt-send-email-mst@redhat.com> (raw)
In-Reply-To: <5566FB3E.3080002@one.verizon.com>

On Thu, May 28, 2015 at 07:25:50AM -0400, Don Slutz wrote:
> On 05/28/15 05:30, Michael S. Tsirkin wrote:
> > On Thu, May 28, 2015 at 04:46:37AM -0400, Don Slutz wrote:
> >> The commit 707ff80021ccd7a68f4b3d2c44eebf87efbb41c4 assumed that a
> >> PCI device has a static address.  This is not true for PCI devices
> >> that are on the secondary bus of a PCI to PCI bridge.
> >>
> >> BIOS and/or guest OS can change the secondary bus number to a new
> >> value at any time.
> >>
> >> When a PCI to PCI bridge bridge is reset, the secondary bus number
> >> is set to zero.  Normally the BIOS will set it to 255 during PCI bus
> >> scanning so that only the PCI devices on the root can be accessed
> >> via bus 0.  Later it is set to a number between 1 and 254.
> >>
> >> Adjust xen_map_pcidev() to not register with Xen for secondary bus
> >> numbers 0 and 255.
> >>
> >> Extend the device listener interface to be called when ever the
> >> secondary bus number is set to a usable value.  This includes
> >> a call on unrealize if the secondary bus number was valid.
> >>
> >> Signed-off-by: Don Slutz <dslutz@verizon.com>
> >> ---
> >>
> >> Note: Right now hvmloader in Xen does not handle PCI to PCI bridges
> >> and so SeaBIOS does not have access to PCI device(s) on secondary
> >> buses.  How ever domU can setup the secondary bus(es) and this patch
> >> will restore access to these PCI devices.
> >>
> >>  hw/core/qdev.c              | 10 ++++++++++
> >>  hw/pci/pci_bridge.c         | 30 ++++++++++++++++++++++++++++++
> >>  include/hw/qdev-core.h      |  2 ++
> >>  include/hw/xen/xen_common.h | 31 +++++++++++++++++++++++++------
> >>  trace-events                |  1 +
> >>  5 files changed, 68 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> >> index b0f0f84..6a514ee 100644
> >> --- a/hw/core/qdev.c
> >> +++ b/hw/core/qdev.c
> >> @@ -239,6 +239,16 @@ void device_listener_unregister(DeviceListener *listener)
> >>      QTAILQ_REMOVE(&device_listeners, listener, link);
> >>  }
> >>  
> >> +void device_listener_realize(DeviceState *dev)
> >> +{
> >> +    DEVICE_LISTENER_CALL(realize, Forward, dev);
> >> +}
> >> +
> >> +void device_listener_unrealize(DeviceState *dev)
> >> +{
> >> +    DEVICE_LISTENER_CALL(unrealize, Forward, dev);
> >> +}
> >> +
> >>  static void device_realize(DeviceState *dev, Error **errp)
> >>  {
> >>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> > 
> > 
> > This looks wrong.  Devices not accessible to config cycles are still
> > accessible e.g. to memory or IO.  It's not the same as unrealize.
> > 
> > You need some other API that makes sense,
> > probably pci specific.
> > 
> 
> If I am understanding you correctly, you would like:
> 
> void device_listener_change_pci_bus_num(PCIDevice *d, uint8_t oldbus)
> {
>     DEVICE_LISTENER_CALL(change_pci_bus_num, Forward, d, oldbus);
> }
> 

I'm not sure what oldbus is but basically ok.
And it must be invoked whenever bus visibility changes,
not just its number.

> > 
> > 
> >> diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
> >> index 40c97b1..042680d 100644
> >> --- a/hw/pci/pci_bridge.c
> >> +++ b/hw/pci/pci_bridge.c
> >> @@ -241,6 +241,18 @@ void pci_bridge_update_mappings(PCIBridge *br)
> >>      pci_bridge_region_cleanup(br, w);
> >>  }
> >>  
> >> +static void pci_bridge_realize_sub(PCIBus *b, PCIDevice *d,
> >> +                                   void *opaque)
> >> +{
> >> +    device_listener_realize(DEVICE(d));
> >> +}
> >> +
> >> +static void pci_bridge_unrealize_sub(PCIBus *b, PCIDevice *d,
> >> +                                     void *opaque)
> >> +{
> >> +    device_listener_unrealize(DEVICE(d));
> >> +}
> >> +
> >>  /* default write_config function for PCI-to-PCI bridge */
> >>  void pci_bridge_write_config(PCIDevice *d,
> >>                               uint32_t address, uint32_t val, int len)
> >> @@ -248,6 +260,8 @@ void pci_bridge_write_config(PCIDevice *d,
> >>      PCIBridge *s = PCI_BRIDGE(d);
> >>      uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> >>      uint16_t newctl;
> >> +    uint8_t oldbus = pci_get_byte(d->config + PCI_SECONDARY_BUS);
> >> +    uint8_t newbus;
> >>  
> >>      pci_default_write_config(d, address, val, len);
> >>  
> >> @@ -265,6 +279,22 @@ void pci_bridge_write_config(PCIDevice *d,
> >>          pci_bridge_update_mappings(s);
> >>      }
> >>  
> >> +    newbus = pci_get_byte(d->config + PCI_SECONDARY_BUS);
> >> +    if (newbus != oldbus) {
> >> +        PCIBus *sec_bus = pci_bridge_get_sec_bus(s);
> >> +
> >> +        if (oldbus && oldbus != 255) {
> >> +            pci_set_byte(d->config + PCI_SECONDARY_BUS, oldbus);
> >> +            pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
> >> +                                pci_bridge_unrealize_sub, NULL);
> >> +            pci_set_byte(d->config + PCI_SECONDARY_BUS, newbus);
> >> +        }
> >> +        if (newbus && newbus != 255) {
> >> +            pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
> >> +                                pci_bridge_realize_sub, NULL);
> >> +        }
> >> +    }
> >> +
> > 
> > 
> > This is relying on undocumented assumptions and how specific firmware
> > works. There's nothing special about bus number 255, and 0 is not very
> > special either (except it happens to be the reset value).
> > 
> 
> Ok, using the above it would change to (almost):
> 
> 
> if (newbus != oldbus) {
>     pci_for_each_device(pci_bridge_get_sec_bus(s),
>                         pci_bus_num(sec_bus),
>                         device_listener_change_pci_bus_num,
>                         oldbus);
> }

Not really because it's not just secondary bus number.
Changing subordinate bus numbers can hide/unhide whole buses.



> Would it be better to have:
> 
> void device_listener_change_pci_bus_num(PCIBus *b, PCIDevice *d, void
> *opaque)
> {
>     uint8_t oldbus = (uint8_t)opaque;
>     DEVICE_LISTENER_CALL(change_pci_bus_num, Forward, d, oldbus);
> }
> 
> So that the above works, or to add a function to convert args?
> 
> > To know whether device is accessible to config cycles, you
> > really need to scan the hierarchy from root downwards.
> > 
> 
> Yes, that is correct.  However what I am doing here is not
> changing how QEMU checks if the device is accessible, but
> changing what pci config Xen sends to QEMU.  If the change
> to PCI_SECONDARY_BUS hides this PCI to PCI bridge, that is
> not an issue.
> 
> 
>    -Don Slutz
> 
> 

Imagine a bridge with secondary bus number 5
behind another one with subordinate numbers 1-3.
You should not send conf cycles for bus number 5 to qemu.

-- 
MST

  reply	other threads:[~2015-05-28 12:29 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-28  8:46 [Qemu-devel] [PATCH 1/1] Fix device listener interface for PCI to PCI bridges Don Slutz
2015-05-28  9:30 ` Michael S. Tsirkin
2015-05-28 11:25   ` Don Slutz
2015-05-28 12:28     ` Michael S. Tsirkin [this message]
2015-05-28 19:09       ` Don Slutz
2015-05-28 21:03         ` Michael S. Tsirkin
2015-05-28 21:05           ` Michael S. Tsirkin
2015-05-29 13:23             ` Don Slutz
2015-05-29 14:22               ` Paul Durrant

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=20150528142229-mutt-send-email-mst@redhat.com \
    --to=mst@redhat.com \
    --cc=dslutz@verizon.com \
    --cc=paul.durrant@citrix.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefano.stabellini@eu.citrix.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).