Diff for /qemu/hw/pci.c between versions 1.1.1.13 and 1.1.1.14

version 1.1.1.13, 2018/04/24 18:30:30 version 1.1.1.14, 2018/04/24 18:39:57
Line 23 Line 23
  */   */
 #include "hw.h"  #include "hw.h"
 #include "pci.h"  #include "pci.h"
   #include "pci_bridge.h"
   #include "pci_internals.h"
 #include "monitor.h"  #include "monitor.h"
 #include "net.h"  #include "net.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "loader.h"  #include "loader.h"
 #include "qemu-objects.h"  #include "qemu-objects.h"
   #include "range.h"
   
 //#define DEBUG_PCI  //#define DEBUG_PCI
 #ifdef DEBUG_PCI  #ifdef DEBUG_PCI
Line 36 Line 39
 # define PCI_DPRINTF(format, ...)       do { } while (0)  # define PCI_DPRINTF(format, ...)       do { } while (0)
 #endif  #endif
   
 struct PCIBus {  
     BusState qbus;  
     int devfn_min;  
     pci_set_irq_fn set_irq;  
     pci_map_irq_fn map_irq;  
     pci_hotplug_fn hotplug;  
     DeviceState *hotplug_qdev;  
     void *irq_opaque;  
     PCIDevice *devices[256];  
     PCIDevice *parent_dev;  
     target_phys_addr_t mem_base;  
   
     QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */  
     QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */  
   
     /* The bus IRQ state is the logical OR of the connected devices.  
        Keep a count of the number of devices with raised IRQs.  */  
     int nirq;  
     int *irq_count;  
 };  
   
 static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);  static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *pcibus_get_dev_path(DeviceState *dev);  static char *pcibus_get_dev_path(DeviceState *dev);
   static char *pcibus_get_fw_dev_path(DeviceState *dev);
   static int pcibus_reset(BusState *qbus);
   
 static struct BusInfo pci_bus_info = {  struct BusInfo pci_bus_info = {
     .name       = "PCI",      .name       = "PCI",
     .size       = sizeof(PCIBus),      .size       = sizeof(PCIBus),
     .print_dev  = pcibus_dev_print,      .print_dev  = pcibus_dev_print,
     .get_dev_path = pcibus_get_dev_path,      .get_dev_path = pcibus_get_dev_path,
       .get_fw_dev_path = pcibus_get_fw_dev_path,
       .reset      = pcibus_reset,
     .props      = (Property[]) {      .props      = (Property[]) {
         DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),          DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
         DEFINE_PROP_STRING("romfile", PCIDevice, romfile),          DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
         DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),          DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
         DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,          DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
                         QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),                          QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
           DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
                           QEMU_PCI_CAP_SERR_BITNR, true),
         DEFINE_PROP_END_OF_LIST()          DEFINE_PROP_END_OF_LIST()
     }      }
 };  };
   
 static void pci_update_mappings(PCIDevice *d);  static void pci_update_mappings(PCIDevice *d);
 static void pci_set_irq(void *opaque, int irq_num, int level);  static void pci_set_irq(void *opaque, int irq_num, int level);
 static int pci_add_option_rom(PCIDevice *pdev);  static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom);
 static void pci_del_option_rom(PCIDevice *pdev);  static void pci_del_option_rom(PCIDevice *pdev);
   
 static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;  static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
Line 149  static void pci_update_irq_status(PCIDev Line 137  static void pci_update_irq_status(PCIDev
     }      }
 }  }
   
 static void pci_device_reset(PCIDevice *dev)  void pci_device_deassert_intx(PCIDevice *dev)
   {
       int i;
       for (i = 0; i < PCI_NUM_PINS; ++i) {
           qemu_set_irq(dev->irq[i], 0);
       }
   }
   
   /*
    * This function is called on #RST and FLR.
    * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
    */
   void pci_device_reset(PCIDevice *dev)
 {  {
     int r;      int r;
       /* TODO: call the below unconditionally once all pci devices
        * are qdevified */
       if (dev->qdev.info) {
           qdev_reset_all(&dev->qdev);
       }
   
     dev->irq_state = 0;      dev->irq_state = 0;
     pci_update_irq_status(dev);      pci_update_irq_status(dev);
       pci_device_deassert_intx(dev);
     /* Clear all writeable bits */      /* Clear all writeable bits */
     pci_set_word(dev->config + PCI_COMMAND,      pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
                  pci_get_word(dev->config + PCI_COMMAND) &                                   pci_get_word(dev->wmask + PCI_COMMAND) |
                  ~pci_get_word(dev->wmask + PCI_COMMAND));                                   pci_get_word(dev->w1cmask + PCI_COMMAND));
       pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
                                    pci_get_word(dev->wmask + PCI_STATUS) |
                                    pci_get_word(dev->w1cmask + PCI_STATUS));
     dev->config[PCI_CACHE_LINE_SIZE] = 0x0;      dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
     dev->config[PCI_INTERRUPT_LINE] = 0x0;      dev->config[PCI_INTERRUPT_LINE] = 0x0;
     for (r = 0; r < PCI_NUM_REGIONS; ++r) {      for (r = 0; r < PCI_NUM_REGIONS; ++r) {
Line 177  static void pci_device_reset(PCIDevice * Line 186  static void pci_device_reset(PCIDevice *
     pci_update_mappings(dev);      pci_update_mappings(dev);
 }  }
   
 static void pci_bus_reset(void *opaque)  /*
    * Trigger pci bus reset under a given bus.
    * To be called on RST# assert.
    */
   void pci_bus_reset(PCIBus *bus)
 {  {
     PCIBus *bus = opaque;  
     int i;      int i;
   
     for (i = 0; i < bus->nirq; i++) {      for (i = 0; i < bus->nirq; i++) {
Line 192  static void pci_bus_reset(void *opaque) Line 204  static void pci_bus_reset(void *opaque)
     }      }
 }  }
   
   static int pcibus_reset(BusState *qbus)
   {
       pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
   
       /* topology traverse is done by pci_bus_reset().
          Tell qbus/qdev walker not to traverse the tree */
       return 1;
   }
   
 static void pci_host_bus_register(int domain, PCIBus *bus)  static void pci_host_bus_register(int domain, PCIBus *bus)
 {  {
     struct PCIHostBus *host;      struct PCIHostBus *host;
Line 246  void pci_bus_new_inplace(PCIBus *bus, De Line 267  void pci_bus_new_inplace(PCIBus *bus, De
     pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */      pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */
   
     vmstate_register(NULL, -1, &vmstate_pcibus, bus);      vmstate_register(NULL, -1, &vmstate_pcibus, bus);
     qemu_register_reset(pci_bus_reset, bus);  
 }  }
   
 PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min)  PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min)
Line 292  PCIBus *pci_register_bus(DeviceState *pa Line 312  PCIBus *pci_register_bus(DeviceState *pa
     return bus;      return bus;
 }  }
   
 static void pci_register_secondary_bus(PCIBus *parent,  
                                        PCIBus *bus,  
                                        PCIDevice *dev,  
                                        pci_map_irq_fn map_irq,  
                                        const char *name)  
 {  
     qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);  
     bus->map_irq = map_irq;  
     bus->parent_dev = dev;  
   
     QLIST_INIT(&bus->child);  
     QLIST_INSERT_HEAD(&parent->child, bus, sibling);  
 }  
   
 static void pci_unregister_secondary_bus(PCIBus *bus)  
 {  
     assert(QLIST_EMPTY(&bus->child));  
     QLIST_REMOVE(bus, sibling);  
 }  
   
 int pci_bus_num(PCIBus *s)  int pci_bus_num(PCIBus *s)
 {  {
     if (!s->parent_dev)      if (!s->parent_dev)
Line 330  static int get_pci_config_device(QEMUFil Line 330  static int get_pci_config_device(QEMUFil
   
     qemu_get_buffer(f, config, size);      qemu_get_buffer(f, config, size);
     for (i = 0; i < size; ++i) {      for (i = 0; i < size; ++i) {
         if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) {          if ((config[i] ^ s->config[i]) &
               s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
             qemu_free(config);              qemu_free(config);
             return -EINVAL;              return -EINVAL;
         }          }
Line 463  static void pci_set_default_subsystem_id Line 464  static void pci_set_default_subsystem_id
 }  }
   
 /*  /*
  * Parse [[<domain>:]<bus>:]<slot>, return -1 on error   * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
    *       [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
  */   */
 static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)  int pci_parse_devaddr(const char *addr, int *domp, int *busp,
                         unsigned int *slotp, unsigned int *funcp)
 {  {
     const char *p;      const char *p;
     char *e;      char *e;
     unsigned long val;      unsigned long val;
     unsigned long dom = 0, bus = 0;      unsigned long dom = 0, bus = 0;
     unsigned slot = 0;      unsigned int slot = 0;
       unsigned int func = 0;
   
     p = addr;      p = addr;
     val = strtoul(p, &e, 16);      val = strtoul(p, &e, 16);
Line 493  static int pci_parse_devaddr(const char  Line 497  static int pci_parse_devaddr(const char 
         }          }
     }      }
   
     if (dom > 0xffff || bus > 0xff || val > 0x1f)  
         return -1;  
   
     slot = val;      slot = val;
   
       if (funcp != NULL) {
           if (*e != '.')
               return -1;
   
           p = e + 1;
           val = strtoul(p, &e, 16);
           if (e == p)
               return -1;
   
           func = val;
       }
   
       /* if funcp == NULL func is 0 */
       if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
           return -1;
   
     if (*e)      if (*e)
         return -1;          return -1;
   
Line 508  static int pci_parse_devaddr(const char  Line 525  static int pci_parse_devaddr(const char 
     *domp = dom;      *domp = dom;
     *busp = bus;      *busp = bus;
     *slotp = slot;      *slotp = slot;
       if (funcp != NULL)
           *funcp = func;
     return 0;      return 0;
 }  }
   
Line 518  int pci_read_devaddr(Monitor *mon, const Line 537  int pci_read_devaddr(Monitor *mon, const
     if (!strncmp(addr, "pci_addr=", 9)) {      if (!strncmp(addr, "pci_addr=", 9)) {
         addr += 9;          addr += 9;
     }      }
     if (pci_parse_devaddr(addr, domp, busp, slotp)) {      if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
         monitor_printf(mon, "Invalid pci address\n");          monitor_printf(mon, "Invalid pci address\n");
         return -1;          return -1;
     }      }
Line 535  PCIBus *pci_get_bus_devfn(int *devfnp, c Line 554  PCIBus *pci_get_bus_devfn(int *devfnp, c
         return pci_find_bus(pci_find_root_bus(0), 0);          return pci_find_bus(pci_find_root_bus(0), 0);
     }      }
   
     if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) {      if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
         return NULL;          return NULL;
     }      }
   
Line 564  static void pci_init_wmask(PCIDevice *de Line 583  static void pci_init_wmask(PCIDevice *de
     pci_set_word(dev->wmask + PCI_COMMAND,      pci_set_word(dev->wmask + PCI_COMMAND,
                  PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |                   PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
                  PCI_COMMAND_INTX_DISABLE);                   PCI_COMMAND_INTX_DISABLE);
       if (dev->cap_present & QEMU_PCI_CAP_SERR) {
           pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
       }
   
     memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,      memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
            config_size - PCI_CONFIG_HEADER_SIZE);             config_size - PCI_CONFIG_HEADER_SIZE);
 }  }
   
   static void pci_init_w1cmask(PCIDevice *dev)
   {
       /*
        * Note: It's okay to set w1cmask even for readonly bits as
        * long as their value is hardwired to 0.
        */
       pci_set_word(dev->w1cmask + PCI_STATUS,
                    PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
                    PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
                    PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
   }
   
 static void pci_init_wmask_bridge(PCIDevice *d)  static void pci_init_wmask_bridge(PCIDevice *d)
 {  {
     /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and      /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and
Line 590  static void pci_init_wmask_bridge(PCIDev Line 624  static void pci_init_wmask_bridge(PCIDev
     /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */      /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */
     memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);      memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8);
   
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff);  /* TODO: add this define to pci_regs.h in linux and then in qemu. */
   #define  PCI_BRIDGE_CTL_VGA_16BIT       0x10    /* VGA 16-bit decode */
   #define  PCI_BRIDGE_CTL_DISCARD         0x100   /* Primary discard timer */
   #define  PCI_BRIDGE_CTL_SEC_DISCARD     0x200   /* Secondary discard timer */
   #define  PCI_BRIDGE_CTL_DISCARD_STATUS  0x400   /* Discard timer status */
   #define  PCI_BRIDGE_CTL_DISCARD_SERR    0x800   /* Discard timer SERR# enable */
       pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
                    PCI_BRIDGE_CTL_PARITY |
                    PCI_BRIDGE_CTL_SERR |
                    PCI_BRIDGE_CTL_ISA |
                    PCI_BRIDGE_CTL_VGA |
                    PCI_BRIDGE_CTL_VGA_16BIT |
                    PCI_BRIDGE_CTL_MASTER_ABORT |
                    PCI_BRIDGE_CTL_BUS_RESET |
                    PCI_BRIDGE_CTL_FAST_BACK |
                    PCI_BRIDGE_CTL_DISCARD |
                    PCI_BRIDGE_CTL_SEC_DISCARD |
                    PCI_BRIDGE_CTL_DISCARD_SERR);
       /* Below does not do anything as we never set this bit, put here for
        * completeness. */
       pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL,
                    PCI_BRIDGE_CTL_DISCARD_STATUS);
 }  }
   
 static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)  static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
Line 603  static int pci_init_multifunction(PCIBus Line 658  static int pci_init_multifunction(PCIBus
     }      }
   
     /*      /*
      * multifuction bit is interpreted in two ways as follows.       * multifunction bit is interpreted in two ways as follows.
      *   - all functions must set the bit to 1.       *   - all functions must set the bit to 1.
      *     Example: Intel X53       *     Example: Intel X53
      *   - function 0 must set the bit, but the rest function (> 0)       *   - function 0 must set the bit, but the rest function (> 0)
Line 648  static void pci_config_alloc(PCIDevice * Line 703  static void pci_config_alloc(PCIDevice *
     pci_dev->config = qemu_mallocz(config_size);      pci_dev->config = qemu_mallocz(config_size);
     pci_dev->cmask = qemu_mallocz(config_size);      pci_dev->cmask = qemu_mallocz(config_size);
     pci_dev->wmask = qemu_mallocz(config_size);      pci_dev->wmask = qemu_mallocz(config_size);
       pci_dev->w1cmask = qemu_mallocz(config_size);
     pci_dev->used = qemu_mallocz(config_size);      pci_dev->used = qemu_mallocz(config_size);
 }  }
   
Line 656  static void pci_config_free(PCIDevice *p Line 712  static void pci_config_free(PCIDevice *p
     qemu_free(pci_dev->config);      qemu_free(pci_dev->config);
     qemu_free(pci_dev->cmask);      qemu_free(pci_dev->cmask);
     qemu_free(pci_dev->wmask);      qemu_free(pci_dev->wmask);
       qemu_free(pci_dev->w1cmask);
     qemu_free(pci_dev->used);      qemu_free(pci_dev->used);
 }  }
   
Line 691  static PCIDevice *do_pci_register_device Line 748  static PCIDevice *do_pci_register_device
     }      }
     pci_init_cmask(pci_dev);      pci_init_cmask(pci_dev);
     pci_init_wmask(pci_dev);      pci_init_wmask(pci_dev);
       pci_init_w1cmask(pci_dev);
     if (is_bridge) {      if (is_bridge) {
         pci_init_wmask_bridge(pci_dev);          pci_init_wmask_bridge(pci_dev);
     }      }
Line 774  static int pci_unregister_device(DeviceS Line 832  static int pci_unregister_device(DeviceS
   
     pci_unregister_io_regions(pci_dev);      pci_unregister_io_regions(pci_dev);
     pci_del_option_rom(pci_dev);      pci_del_option_rom(pci_dev);
       qemu_free(pci_dev->romfile);
     do_pci_unregister_device(pci_dev);      do_pci_unregister_device(pci_dev);
     return 0;      return 0;
 }  }
   
 void pci_register_bar(PCIDevice *pci_dev, int region_num,  void pci_register_bar(PCIDevice *pci_dev, int region_num,
                             pcibus_t size, int type,                              pcibus_t size, uint8_t type,
                             PCIMapIORegionFunc *map_func)                              PCIMapIORegionFunc *map_func)
 {  {
     PCIIORegion *r;      PCIIORegion *r;
     uint32_t addr;      uint32_t addr;
     pcibus_t wmask;      uint64_t wmask;
   
     if ((unsigned int)region_num >= PCI_NUM_REGIONS)  
         return;  
   
       assert(region_num >= 0);
       assert(region_num < PCI_NUM_REGIONS);
     if (size & (size-1)) {      if (size & (size-1)) {
         fprintf(stderr, "ERROR: PCI region size must be pow2 "          fprintf(stderr, "ERROR: PCI region size must be pow2 "
                     "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);                      "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
Line 819  void pci_register_bar(PCIDevice *pci_dev Line 877  void pci_register_bar(PCIDevice *pci_dev
     }      }
 }  }
   
 static uint32_t pci_config_get_io_base(PCIDevice *d,  
                                        uint32_t base, uint32_t base_upper16)  
 {  
     uint32_t val;  
   
     val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;  
     if (d->config[base] & PCI_IO_RANGE_TYPE_32) {  
         val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16;  
     }  
     return val;  
 }  
   
 static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)  
 {  
     return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)  
         << 16;  
 }  
   
 static pcibus_t pci_config_get_pref_base(PCIDevice *d,  
                                          uint32_t base, uint32_t upper)  
 {  
     pcibus_t tmp;  
     pcibus_t val;  
   
     tmp = (pcibus_t)pci_get_word(d->config + base);  
     val = (tmp & PCI_PREF_RANGE_MASK) << 16;  
     if (tmp & PCI_PREF_RANGE_TYPE_64) {  
         val |= (pcibus_t)pci_get_long(d->config + upper) << 32;  
     }  
     return val;  
 }  
   
 static pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)  
 {  
     pcibus_t base;  
     if (type & PCI_BASE_ADDRESS_SPACE_IO) {  
         base = pci_config_get_io_base(bridge,  
                                       PCI_IO_BASE, PCI_IO_BASE_UPPER16);  
     } else {  
         if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {  
             base = pci_config_get_pref_base(  
                 bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);  
         } else {  
             base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);  
         }  
     }  
   
     return base;  
 }  
   
 static pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)  
 {  
     pcibus_t limit;  
     if (type & PCI_BASE_ADDRESS_SPACE_IO) {  
         limit = pci_config_get_io_base(bridge,  
                                       PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);  
         limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */  
     } else {  
         if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {  
             limit = pci_config_get_pref_base(  
                 bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);  
         } else {  
             limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);  
         }  
         limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */  
     }  
     return limit;  
 }  
   
 static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,  static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
                               uint8_t type)                                uint8_t type)
 {  {
Line 1088  void pci_default_write_config(PCIDevice  Line 1077  void pci_default_write_config(PCIDevice 
   
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {      for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];          uint8_t wmask = d->wmask[addr + i];
           uint8_t w1cmask = d->w1cmask[addr + i];
           assert(!(wmask & w1cmask));
         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);          d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
           d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
     }      }
     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||      if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||          ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
Line 1126  static void pci_set_irq(void *opaque, in Line 1118  static void pci_set_irq(void *opaque, in
 typedef struct {  typedef struct {
     uint16_t class;      uint16_t class;
     const char *desc;      const char *desc;
       const char *fw_name;
       uint16_t fw_ign_bits;
 } pci_class_desc;  } pci_class_desc;
   
 static const pci_class_desc pci_class_descriptions[] =  static const pci_class_desc pci_class_descriptions[] =
 {  {
     { 0x0100, "SCSI controller"},      { 0x0001, "VGA controller", "display"},
     { 0x0101, "IDE controller"},      { 0x0100, "SCSI controller", "scsi"},
     { 0x0102, "Floppy controller"},      { 0x0101, "IDE controller", "ide"},
     { 0x0103, "IPI controller"},      { 0x0102, "Floppy controller", "fdc"},
     { 0x0104, "RAID controller"},      { 0x0103, "IPI controller", "ipi"},
       { 0x0104, "RAID controller", "raid"},
     { 0x0106, "SATA controller"},      { 0x0106, "SATA controller"},
     { 0x0107, "SAS controller"},      { 0x0107, "SAS controller"},
     { 0x0180, "Storage controller"},      { 0x0180, "Storage controller"},
     { 0x0200, "Ethernet controller"},      { 0x0200, "Ethernet controller", "ethernet"},
     { 0x0201, "Token Ring controller"},      { 0x0201, "Token Ring controller", "token-ring"},
     { 0x0202, "FDDI controller"},      { 0x0202, "FDDI controller", "fddi"},
     { 0x0203, "ATM controller"},      { 0x0203, "ATM controller", "atm"},
     { 0x0280, "Network controller"},      { 0x0280, "Network controller"},
     { 0x0300, "VGA controller"},      { 0x0300, "VGA controller", "display", 0x00ff},
     { 0x0301, "XGA controller"},      { 0x0301, "XGA controller"},
     { 0x0302, "3D controller"},      { 0x0302, "3D controller"},
     { 0x0380, "Display controller"},      { 0x0380, "Display controller"},
     { 0x0400, "Video controller"},      { 0x0400, "Video controller", "video"},
     { 0x0401, "Audio controller"},      { 0x0401, "Audio controller", "sound"},
     { 0x0402, "Phone"},      { 0x0402, "Phone"},
     { 0x0480, "Multimedia controller"},      { 0x0480, "Multimedia controller"},
     { 0x0500, "RAM controller"},      { 0x0500, "RAM controller", "memory"},
     { 0x0501, "Flash controller"},      { 0x0501, "Flash controller", "flash"},
     { 0x0580, "Memory controller"},      { 0x0580, "Memory controller"},
     { 0x0600, "Host bridge"},      { 0x0600, "Host bridge", "host"},
     { 0x0601, "ISA bridge"},      { 0x0601, "ISA bridge", "isa"},
     { 0x0602, "EISA bridge"},      { 0x0602, "EISA bridge", "eisa"},
     { 0x0603, "MC bridge"},      { 0x0603, "MC bridge", "mca"},
     { 0x0604, "PCI bridge"},      { 0x0604, "PCI bridge", "pci"},
     { 0x0605, "PCMCIA bridge"},      { 0x0605, "PCMCIA bridge", "pcmcia"},
     { 0x0606, "NUBUS bridge"},      { 0x0606, "NUBUS bridge", "nubus"},
     { 0x0607, "CARDBUS bridge"},      { 0x0607, "CARDBUS bridge", "cardbus"},
     { 0x0608, "RACEWAY bridge"},      { 0x0608, "RACEWAY bridge"},
     { 0x0680, "Bridge"},      { 0x0680, "Bridge"},
     { 0x0c03, "USB controller"},      { 0x0700, "Serial port", "serial"},
       { 0x0701, "Parallel port", "parallel"},
       { 0x0800, "Interrupt controller", "interrupt-controller"},
       { 0x0801, "DMA controller", "dma-controller"},
       { 0x0802, "Timer", "timer"},
       { 0x0803, "RTC", "rtc"},
       { 0x0900, "Keyboard", "keyboard"},
       { 0x0901, "Pen", "pen"},
       { 0x0902, "Mouse", "mouse"},
       { 0x0A00, "Dock station", "dock", 0x00ff},
       { 0x0B00, "i386 cpu", "cpu", 0x00ff},
       { 0x0c00, "Fireware contorller", "fireware"},
       { 0x0c01, "Access bus controller", "access-bus"},
       { 0x0c02, "SSA controller", "ssa"},
       { 0x0c03, "USB controller", "usb"},
       { 0x0c04, "Fibre channel controller", "fibre-channel"},
     { 0, NULL}      { 0, NULL}
 };  };
   
Line 1533  PCIDevice *pci_nic_init_nofail(NICInfo * Line 1543  PCIDevice *pci_nic_init_nofail(NICInfo *
     return res;      return res;
 }  }
   
 typedef struct {  
     PCIDevice dev;  
     PCIBus bus;  
     uint32_t vid;  
     uint32_t did;  
 } PCIBridge;  
   
   
 static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)  static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
 {  {
     pci_update_mappings(d);      pci_update_mappings(d);
 }  }
   
 static void pci_bridge_update_mappings(PCIBus *b)  void pci_bridge_update_mappings(PCIBus *b)
 {  {
     PCIBus *child;      PCIBus *child;
   
Line 1557  static void pci_bridge_update_mappings(P Line 1559  static void pci_bridge_update_mappings(P
     }      }
 }  }
   
 static void pci_bridge_write_config(PCIDevice *d,  /* Whether a given bus number is in range of the secondary
                              uint32_t address, uint32_t val, int len)   * bus of the given bridge device. */
 {  static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
     pci_default_write_config(d, address, val, len);  {
       return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) &
     if (/* io base/limit */               PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ &&
         ranges_overlap(address, len, PCI_IO_BASE, 2) ||          dev->config[PCI_SECONDARY_BUS] < bus_num &&
           bus_num <= dev->config[PCI_SUBORDINATE_BUS];
         /* memory base/limit, prefetchable base/limit and  
            io base/limit upper 16 */  
         ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {  
         PCIBridge *s = container_of(d, PCIBridge, dev);  
         PCIBus *secondary_bus = &s->bus;  
         pci_bridge_update_mappings(secondary_bus);  
     }  
 }  }
   
 PCIBus *pci_find_bus(PCIBus *bus, int bus_num)  PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
Line 1586  PCIBus *pci_find_bus(PCIBus *bus, int bu Line 1581  PCIBus *pci_find_bus(PCIBus *bus, int bu
         return bus;          return bus;
     }      }
   
       /* Consider all bus numbers in range for the host pci bridge. */
       if (bus->parent_dev &&
           !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
           return NULL;
       }
   
     /* try child bus */      /* try child bus */
     if (!bus->parent_dev /* host pci bridge */ ||      for (; bus; bus = sec) {
         (bus->parent_dev->config[PCI_SECONDARY_BUS] < bus_num &&          QLIST_FOREACH(sec, &bus->child, sibling) {
          bus_num <= bus->parent_dev->config[PCI_SUBORDINATE_BUS])) {              assert(sec->parent_dev);
         for (; bus; bus = sec) {              if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
             QLIST_FOREACH(sec, &bus->child, sibling) {                  return sec;
                 assert(sec->parent_dev);              }
                 if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {              if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) {
                     return sec;                  break;
                 }  
                 if (sec->parent_dev->config[PCI_SECONDARY_BUS] < bus_num &&  
                     bus_num <= sec->parent_dev->config[PCI_SUBORDINATE_BUS]) {  
                     break;  
                 }  
             }              }
         }          }
     }      }
Line 1617  PCIDevice *pci_find_device(PCIBus *bus,  Line 1613  PCIDevice *pci_find_device(PCIBus *bus, 
     return bus->devices[PCI_DEVFN(slot, function)];      return bus->devices[PCI_DEVFN(slot, function)];
 }  }
   
 static int pci_bridge_initfn(PCIDevice *dev)  
 {  
     PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);  
   
     pci_config_set_vendor_id(s->dev.config, s->vid);  
     pci_config_set_device_id(s->dev.config, s->did);  
   
     pci_set_word(dev->config + PCI_STATUS,  
                  PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);  
     pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);  
     dev->config[PCI_HEADER_TYPE] =  
         (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |  
         PCI_HEADER_TYPE_BRIDGE;  
     pci_set_word(dev->config + PCI_SEC_STATUS,  
                  PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);  
     return 0;  
 }  
   
 static int pci_bridge_exitfn(PCIDevice *pci_dev)  
 {  
     PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);  
     PCIBus *bus = &s->bus;  
     pci_unregister_secondary_bus(bus);  
     return 0;  
 }  
   
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,  
                         uint16_t vid, uint16_t did,  
                         pci_map_irq_fn map_irq, const char *name)  
 {  
     PCIDevice *dev;  
     PCIBridge *s;  
   
     dev = pci_create_multifunction(bus, devfn, multifunction, "pci-bridge");  
     qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);  
     qdev_prop_set_uint32(&dev->qdev, "deviceid", did);  
     qdev_init_nofail(&dev->qdev);  
   
     s = DO_UPCAST(PCIBridge, dev, dev);  
     pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);  
     return &s->bus;  
 }  
   
 PCIDevice *pci_bridge_get_device(PCIBus *bus)  
 {  
     return bus->parent_dev;  
 }  
   
 static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)  static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {  {
     PCIDevice *pci_dev = (PCIDevice *)qdev;      PCIDevice *pci_dev = (PCIDevice *)qdev;
     PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);      PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
     PCIBus *bus;      PCIBus *bus;
     int devfn, rc;      int devfn, rc;
       bool is_default_rom;
   
     /* initialize cap_present for pci_is_express() and pci_config_size() */      /* initialize cap_present for pci_is_express() and pci_config_size() */
     if (info->is_express) {      if (info->is_express) {
Line 1684  static int pci_qdev_init(DeviceState *qd Line 1633  static int pci_qdev_init(DeviceState *qd
                                      info->is_bridge);                                       info->is_bridge);
     if (pci_dev == NULL)      if (pci_dev == NULL)
         return -1;          return -1;
       if (qdev->hotplugged && info->no_hotplug) {
           qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
           do_pci_unregister_device(pci_dev);
           return -1;
       }
     rc = info->init(pci_dev);      rc = info->init(pci_dev);
     if (rc != 0) {      if (rc != 0) {
         do_pci_unregister_device(pci_dev);          do_pci_unregister_device(pci_dev);
Line 1691  static int pci_qdev_init(DeviceState *qd Line 1645  static int pci_qdev_init(DeviceState *qd
     }      }
   
     /* rom loading */      /* rom loading */
     if (pci_dev->romfile == NULL && info->romfile != NULL)      is_default_rom = false;
       if (pci_dev->romfile == NULL && info->romfile != NULL) {
         pci_dev->romfile = qemu_strdup(info->romfile);          pci_dev->romfile = qemu_strdup(info->romfile);
     pci_add_option_rom(pci_dev);          is_default_rom = true;
       }
       pci_add_option_rom(pci_dev, is_default_rom);
   
     if (qdev->hotplugged) {      if (bus->hotplug) {
         rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);          /* Let buses differentiate between hotplug and when device is
            * enabled during qemu machine creation. */
           rc = bus->hotplug(bus->hotplug_qdev, pci_dev,
                             qdev->hotplugged ? PCI_HOTPLUG_ENABLED:
                             PCI_COLDPLUG_ENABLED);
         if (rc != 0) {          if (rc != 0) {
             int r = pci_unregister_device(&pci_dev->qdev);              int r = pci_unregister_device(&pci_dev->qdev);
             assert(!r);              assert(!r);
Line 1709  static int pci_qdev_init(DeviceState *qd Line 1670  static int pci_qdev_init(DeviceState *qd
 static int pci_unplug_device(DeviceState *qdev)  static int pci_unplug_device(DeviceState *qdev)
 {  {
     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);      PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
       PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
   
     return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0);      if (info->no_hotplug) {
           qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
           return -1;
       }
       return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
                                PCI_HOTPLUG_DISABLED);
 }  }
   
 void pci_qdev_register(PCIDeviceInfo *info)  void pci_qdev_register(PCIDeviceInfo *info)
Line 1796  static void pci_map_option_rom(PCIDevice Line 1763  static void pci_map_option_rom(PCIDevice
     cpu_register_physical_memory(addr, size, pdev->rom_offset);      cpu_register_physical_memory(addr, size, pdev->rom_offset);
 }  }
   
   /* Patch the PCI vendor and device ids in a PCI rom image if necessary.
      This is needed for an option rom which is used for more than one device. */
   static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
   {
       uint16_t vendor_id;
       uint16_t device_id;
       uint16_t rom_vendor_id;
       uint16_t rom_device_id;
       uint16_t rom_magic;
       uint16_t pcir_offset;
       uint8_t checksum;
   
       /* Words in rom data are little endian (like in PCI configuration),
          so they can be read / written with pci_get_word / pci_set_word. */
   
       /* Only a valid rom will be patched. */
       rom_magic = pci_get_word(ptr);
       if (rom_magic != 0xaa55) {
           PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic);
           return;
       }
       pcir_offset = pci_get_word(ptr + 0x18);
       if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) {
           PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset);
           return;
       }
   
       vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
       device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
       rom_vendor_id = pci_get_word(ptr + pcir_offset + 4);
       rom_device_id = pci_get_word(ptr + pcir_offset + 6);
   
       PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile,
                   vendor_id, device_id, rom_vendor_id, rom_device_id);
   
       checksum = ptr[6];
   
       if (vendor_id != rom_vendor_id) {
           /* Patch vendor id and checksum (at offset 6 for etherboot roms). */
           checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8);
           checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8);
           PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
           ptr[6] = checksum;
           pci_set_word(ptr + pcir_offset + 4, vendor_id);
       }
   
       if (device_id != rom_device_id) {
           /* Patch device id and checksum (at offset 6 for etherboot roms). */
           checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8);
           checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8);
           PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum);
           ptr[6] = checksum;
           pci_set_word(ptr + pcir_offset + 6, device_id);
       }
   }
   
 /* Add an option rom for the device */  /* Add an option rom for the device */
 static int pci_add_option_rom(PCIDevice *pdev)  static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
 {  {
     int size;      int size;
     char *path;      char *path;
Line 1818  static int pci_add_option_rom(PCIDevice  Line 1841  static int pci_add_option_rom(PCIDevice 
         if (class == 0x0300) {          if (class == 0x0300) {
             rom_add_vga(pdev->romfile);              rom_add_vga(pdev->romfile);
         } else {          } else {
             rom_add_option(pdev->romfile);              rom_add_option(pdev->romfile, -1);
         }          }
         return 0;          return 0;
     }      }
Line 1848  static int pci_add_option_rom(PCIDevice  Line 1871  static int pci_add_option_rom(PCIDevice 
     load_image(path, ptr);      load_image(path, ptr);
     qemu_free(path);      qemu_free(path);
   
       if (is_default_rom) {
           /* Only the default rom images will be patched (if needed). */
           pci_patch_ids(pdev, ptr, size);
       }
   
     pci_register_bar(pdev, PCI_ROM_SLOT, size,      pci_register_bar(pdev, PCI_ROM_SLOT, size,
                      0, pci_map_option_rom);                       0, pci_map_option_rom);
   
Line 1863  static void pci_del_option_rom(PCIDevice Line 1891  static void pci_del_option_rom(PCIDevice
     pdev->rom_offset = 0;      pdev->rom_offset = 0;
 }  }
   
 /* Reserve space and add capability to the linked list in pci config space */  /*
 int pci_add_capability_at_offset(PCIDevice *pdev, uint8_t cap_id,   * if !offset
                                  uint8_t offset, uint8_t size)   * Reserve space and add capability to the linked list in pci config space
    *
    * if offset = 0,
    * Find and reserve space and add capability to the linked list
    * in pci config space */
   int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
                          uint8_t offset, uint8_t size)
 {  {
     uint8_t *config = pdev->config + offset;      uint8_t *config;
       if (!offset) {
           offset = pci_find_space(pdev, size);
           if (!offset) {
               return -ENOSPC;
           }
       }
   
       config = pdev->config + offset;
     config[PCI_CAP_LIST_ID] = cap_id;      config[PCI_CAP_LIST_ID] = cap_id;
     config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];      config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
     pdev->config[PCI_CAPABILITY_LIST] = offset;      pdev->config[PCI_CAPABILITY_LIST] = offset;
Line 1880  int pci_add_capability_at_offset(PCIDevi Line 1922  int pci_add_capability_at_offset(PCIDevi
     return offset;      return offset;
 }  }
   
 /* Find and reserve space and add capability to the linked list  
  * in pci config space */  
 int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)  
 {  
     uint8_t offset = pci_find_space(pdev, size);  
     if (!offset) {  
         return -ENOSPC;  
     }  
     return pci_add_capability_at_offset(pdev, cap_id, offset, size);  
 }  
   
 /* Unlink capability from the pci config space. */  /* Unlink capability from the pci config space. */
 void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)  void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
 {  {
Line 1900  void pci_del_capability(PCIDevice *pdev, Line 1931  void pci_del_capability(PCIDevice *pdev,
     pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];      pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
     /* Make capability writeable again */      /* Make capability writeable again */
     memset(pdev->wmask + offset, 0xff, size);      memset(pdev->wmask + offset, 0xff, size);
       memset(pdev->w1cmask + offset, 0, size);
     /* Clear cmask as device-specific registers can't be checked */      /* Clear cmask as device-specific registers can't be checked */
     memset(pdev->cmask + offset, 0, size);      memset(pdev->cmask + offset, 0, size);
     memset(pdev->used + offset, 0, size);      memset(pdev->used + offset, 0, size);
Line 1939  static void pcibus_dev_print(Monitor *mo Line 1971  static void pcibus_dev_print(Monitor *mo
   
     monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "      monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, "
                    "pci id %04x:%04x (sub %04x:%04x)\n",                     "pci id %04x:%04x (sub %04x:%04x)\n",
                    indent, "", ctxt,                     indent, "", ctxt, pci_bus_num(d->bus),
                    d->config[PCI_SECONDARY_BUS],  
                    PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),                     PCI_SLOT(d->devfn), PCI_FUNC(d->devfn),
                    pci_get_word(d->config + PCI_VENDOR_ID),                     pci_get_word(d->config + PCI_VENDOR_ID),
                    pci_get_word(d->config + PCI_DEVICE_ID),                     pci_get_word(d->config + PCI_DEVICE_ID),
Line 1958  static void pcibus_dev_print(Monitor *mo Line 1989  static void pcibus_dev_print(Monitor *mo
     }      }
 }  }
   
 static char *pcibus_get_dev_path(DeviceState *dev)  static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
 {  {
     PCIDevice *d = (PCIDevice *)dev;      PCIDevice *d = (PCIDevice *)dev;
     char path[16];      const char *name = NULL;
       const pci_class_desc *desc =  pci_class_descriptions;
       int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
   
       while (desc->desc &&
             (class & ~desc->fw_ign_bits) !=
             (desc->class & ~desc->fw_ign_bits)) {
           desc++;
       }
   
       if (desc->desc) {
           name = desc->fw_name;
       }
   
       if (name) {
           pstrcpy(buf, len, name);
       } else {
           snprintf(buf, len, "pci%04x,%04x",
                    pci_get_word(d->config + PCI_VENDOR_ID),
                    pci_get_word(d->config + PCI_DEVICE_ID));
       }
   
     snprintf(path, sizeof(path), "%04x:%02x:%02x.%x",      return buf;
              pci_find_domain(d->bus), d->config[PCI_SECONDARY_BUS],  }
              PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));  
   static char *pcibus_get_fw_dev_path(DeviceState *dev)
   {
       PCIDevice *d = (PCIDevice *)dev;
       char path[50], name[33];
       int off;
   
       off = snprintf(path, sizeof(path), "%s@%x",
                      pci_dev_fw_name(dev, name, sizeof name),
                      PCI_SLOT(d->devfn));
       if (PCI_FUNC(d->devfn))
           snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
     return strdup(path);      return strdup(path);
 }  }
   
 static PCIDeviceInfo bridge_info = {  static char *pcibus_get_dev_path(DeviceState *dev)
     .qdev.name    = "pci-bridge",  {
     .qdev.size    = sizeof(PCIBridge),      PCIDevice *d = container_of(dev, PCIDevice, qdev);
     .init         = pci_bridge_initfn,      PCIDevice *t;
     .exit         = pci_bridge_exitfn,      int slot_depth;
     .config_write = pci_bridge_write_config,      /* Path format: Domain:00:Slot.Function:Slot.Function....:Slot.Function.
     .is_bridge    = 1,       * 00 is added here to make this format compatible with
     .qdev.props   = (Property[]) {       * domain:Bus:Slot.Func for systems without nested PCI bridges.
         DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),       * Slot.Function list specifies the slot and function numbers for all
         DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),       * devices on the path from root to the specific device. */
         DEFINE_PROP_END_OF_LIST(),      char domain[] = "DDDD:00";
       char slot[] = ":SS.F";
       int domain_len = sizeof domain - 1 /* For '\0' */;
       int slot_len = sizeof slot - 1 /* For '\0' */;
       int path_len;
       char *path, *p;
       int s;
   
       /* Calculate # of slots on path between device and root. */;
       slot_depth = 0;
       for (t = d; t; t = t->bus->parent_dev) {
           ++slot_depth;
       }
   
       path_len = domain_len + slot_len * slot_depth;
   
       /* Allocate memory, fill in the terminating null byte. */
       path = qemu_malloc(path_len + 1 /* For '\0' */);
       path[path_len] = '\0';
   
       /* First field is the domain. */
       s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
       assert(s == domain_len);
       memcpy(path, domain, domain_len);
   
       /* Fill in slot numbers. We walk up from device to root, so need to print
        * them in the reverse order, last to first. */
       p = path + path_len;
       for (t = d; t; t = t->bus->parent_dev) {
           p -= slot_len;
           s = snprintf(slot, sizeof slot, ":%02x.%x",
                        PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
           assert(s == slot_len);
           memcpy(p, slot, slot_len);
       }
   
       return path;
   }
   
   static int pci_qdev_find_recursive(PCIBus *bus,
                                      const char *id, PCIDevice **pdev)
   {
       DeviceState *qdev = qdev_find_recursive(&bus->qbus, id);
       if (!qdev) {
           return -ENODEV;
       }
   
       /* roughly check if given qdev is pci device */
       if (qdev->info->init == &pci_qdev_init &&
           qdev->parent_bus->info == &pci_bus_info) {
           *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
           return 0;
     }      }
 };      return -EINVAL;
   }
   
 static void pci_register_devices(void)  int pci_qdev_find_device(const char *id, PCIDevice **pdev)
 {  {
     pci_qdev_register(&bridge_info);      struct PCIHostBus *host;
 }      int rc = -ENODEV;
   
       QLIST_FOREACH(host, &host_buses, next) {
           int tmp = pci_qdev_find_recursive(host->bus, id, pdev);
           if (!tmp) {
               rc = 0;
               break;
           }
           if (tmp != -ENODEV) {
               rc = tmp;
           }
       }
   
 device_init(pci_register_devices)      return rc;
   }

Removed from v.1.1.1.13  
changed lines
  Added in v.1.1.1.14


unix.superglobalmegacorp.com