qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH 1/1] Fix device listener interface for PCI to PC


From: Don Slutz
Subject: Re: [Qemu-devel] [PATCH 1/1] Fix device listener interface for PCI to PCI bridges
Date: Thu, 28 May 2015 07:25:50 -0400
User-agent: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0

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 <address@hidden>
>> ---
>>
>> 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);
}


> 
> 
>> 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);
}

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


Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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