Diff for /qemu/hw/pci.c between versions 1.1.1.15 and 1.1.1.16

version 1.1.1.15, 2018/04/24 19:01:56 version 1.1.1.16, 2018/04/24 19:29:57
Line 29 Line 29
 #include "net.h"  #include "net.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "loader.h"  #include "loader.h"
 #include "qemu-objects.h"  
 #include "range.h"  #include "range.h"
   #include "qmp-commands.h"
   
 //#define DEBUG_PCI  //#define DEBUG_PCI
 #ifdef DEBUG_PCI  #ifdef DEBUG_PCI
Line 223  static int pcibus_reset(BusState *qbus) Line 223  static int pcibus_reset(BusState *qbus)
 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;
     host = qemu_mallocz(sizeof(*host));      host = g_malloc0(sizeof(*host));
     host->domain = domain;      host->domain = domain;
     host->bus = bus;      host->bus = bus;
     QLIST_INSERT_HEAD(&host_buses, host, next);      QLIST_INSERT_HEAD(&host_buses, host, next);
Line 263  int pci_find_domain(const PCIBus *bus) Line 263  int pci_find_domain(const PCIBus *bus)
 }  }
   
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,  void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name, uint8_t devfn_min)                           const char *name,
                            MemoryRegion *address_space_mem,
                            MemoryRegion *address_space_io,
                            uint8_t devfn_min)
 {  {
     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);      qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
     assert(PCI_FUNC(devfn_min) == 0);      assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;      bus->devfn_min = devfn_min;
       bus->address_space_mem = address_space_mem;
       bus->address_space_io = address_space_io;
   
     /* host bridge */      /* host bridge */
     QLIST_INIT(&bus->child);      QLIST_INIT(&bus->child);
Line 276  void pci_bus_new_inplace(PCIBus *bus, De Line 281  void pci_bus_new_inplace(PCIBus *bus, De
     vmstate_register(NULL, -1, &vmstate_pcibus, bus);      vmstate_register(NULL, -1, &vmstate_pcibus, bus);
 }  }
   
 PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min)  PCIBus *pci_bus_new(DeviceState *parent, const char *name,
                       MemoryRegion *address_space_mem,
                       MemoryRegion *address_space_io,
                       uint8_t devfn_min)
 {  {
     PCIBus *bus;      PCIBus *bus;
   
     bus = qemu_mallocz(sizeof(*bus));      bus = g_malloc0(sizeof(*bus));
     bus->qbus.qdev_allocated = 1;      bus->qbus.qdev_allocated = 1;
     pci_bus_new_inplace(bus, parent, name, devfn_min);      pci_bus_new_inplace(bus, parent, name, address_space_mem,
                           address_space_io, devfn_min);
     return bus;      return bus;
 }  }
   
Line 293  void pci_bus_irqs(PCIBus *bus, pci_set_i Line 302  void pci_bus_irqs(PCIBus *bus, pci_set_i
     bus->map_irq = map_irq;      bus->map_irq = map_irq;
     bus->irq_opaque = irq_opaque;      bus->irq_opaque = irq_opaque;
     bus->nirq = nirq;      bus->nirq = nirq;
     bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));      bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
 }  }
   
 void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)  void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
Line 303  void pci_bus_hotplug(PCIBus *bus, pci_ho Line 312  void pci_bus_hotplug(PCIBus *bus, pci_ho
     bus->hotplug_qdev = qdev;      bus->hotplug_qdev = qdev;
 }  }
   
 void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)  
 {  
     bus->mem_base = base;  
 }  
   
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,  PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,                           pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          void *irq_opaque, uint8_t devfn_min, int nirq)                           void *irq_opaque,
                            MemoryRegion *address_space_mem,
                            MemoryRegion *address_space_io,
                            uint8_t devfn_min, int nirq)
 {  {
     PCIBus *bus;      PCIBus *bus;
   
     bus = pci_bus_new(parent, name, devfn_min);      bus = pci_bus_new(parent, name, address_space_mem,
                         address_space_io, devfn_min);
     pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);      pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
     return bus;      return bus;
 }  }
Line 333  static int get_pci_config_device(QEMUFil Line 341  static int get_pci_config_device(QEMUFil
     int i;      int i;
   
     assert(size == pci_config_size(s));      assert(size == pci_config_size(s));
     config = qemu_malloc(size);      config = g_malloc(size);
   
     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]) &          if ((config[i] ^ s->config[i]) &
             s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {              s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
             qemu_free(config);              g_free(config);
             return -EINVAL;              return -EINVAL;
         }          }
     }      }
Line 347  static int get_pci_config_device(QEMUFil Line 355  static int get_pci_config_device(QEMUFil
   
     pci_update_mappings(s);      pci_update_mappings(s);
   
     qemu_free(config);      g_free(config);
     return 0;      return 0;
 }  }
   
Line 707  static void pci_config_alloc(PCIDevice * Line 715  static void pci_config_alloc(PCIDevice *
 {  {
     int config_size = pci_config_size(pci_dev);      int config_size = pci_config_size(pci_dev);
   
     pci_dev->config = qemu_mallocz(config_size);      pci_dev->config = g_malloc0(config_size);
     pci_dev->cmask = qemu_mallocz(config_size);      pci_dev->cmask = g_malloc0(config_size);
     pci_dev->wmask = qemu_mallocz(config_size);      pci_dev->wmask = g_malloc0(config_size);
     pci_dev->w1cmask = qemu_mallocz(config_size);      pci_dev->w1cmask = g_malloc0(config_size);
     pci_dev->used = qemu_mallocz(config_size);      pci_dev->used = g_malloc0(config_size);
 }  }
   
 static void pci_config_free(PCIDevice *pci_dev)  static void pci_config_free(PCIDevice *pci_dev)
 {  {
     qemu_free(pci_dev->config);      g_free(pci_dev->config);
     qemu_free(pci_dev->cmask);      g_free(pci_dev->cmask);
     qemu_free(pci_dev->wmask);      g_free(pci_dev->wmask);
     qemu_free(pci_dev->w1cmask);      g_free(pci_dev->w1cmask);
     qemu_free(pci_dev->used);      g_free(pci_dev->used);
 }  }
   
 /* -1 for devfn means auto assign */  /* -1 for devfn means auto assign */
Line 812  PCIDevice *pci_register_device(PCIBus *b Line 820  PCIDevice *pci_register_device(PCIBus *b
         .config_write = config_write,          .config_write = config_write,
     };      };
   
     pci_dev = qemu_mallocz(instance_size);      pci_dev = g_malloc0(instance_size);
     pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);      pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
     if (pci_dev == NULL) {      if (pci_dev == NULL) {
         hw_error("PCI: can't register device\n");          hw_error("PCI: can't register device\n");
Line 820  PCIDevice *pci_register_device(PCIBus *b Line 828  PCIDevice *pci_register_device(PCIBus *b
     return pci_dev;      return pci_dev;
 }  }
   
 static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,  
                                           target_phys_addr_t addr)  
 {  
     return addr + bus->mem_base;  
 }  
   
 static void pci_unregister_io_regions(PCIDevice *pci_dev)  static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {  {
     PCIIORegion *r;      PCIIORegion *r;
Line 835  static void pci_unregister_io_regions(PC Line 837  static void pci_unregister_io_regions(PC
         r = &pci_dev->io_regions[i];          r = &pci_dev->io_regions[i];
         if (!r->size || r->addr == PCI_BAR_UNMAPPED)          if (!r->size || r->addr == PCI_BAR_UNMAPPED)
             continue;              continue;
         if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {          memory_region_del_subregion(r->address_space, r->memory);
             isa_unassign_ioport(r->addr, r->filtered_size);  
         } else {  
             cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,  
                                                          r->addr),  
                                          r->filtered_size,  
                                          IO_MEM_UNASSIGNED);  
         }  
     }      }
 }  }
   
Line 859  static int pci_unregister_device(DeviceS Line 854  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);      g_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, uint8_t type,                        uint8_t type, MemoryRegion *memory)
                             PCIMapIORegionFunc *map_func)  
 {  {
     PCIIORegion *r;      PCIIORegion *r;
     uint32_t addr;      uint32_t addr;
     uint64_t wmask;      uint64_t wmask;
       pcibus_t size = memory_region_size(memory);
   
     assert(region_num >= 0);      assert(region_num >= 0);
     assert(region_num < PCI_NUM_REGIONS);      assert(region_num < PCI_NUM_REGIONS);
Line 883  void pci_register_bar(PCIDevice *pci_dev Line 878  void pci_register_bar(PCIDevice *pci_dev
     r = &pci_dev->io_regions[region_num];      r = &pci_dev->io_regions[region_num];
     r->addr = PCI_BAR_UNMAPPED;      r->addr = PCI_BAR_UNMAPPED;
     r->size = size;      r->size = size;
     r->filtered_size = size;  
     r->type = type;      r->type = type;
     r->map_func = map_func;      r->memory = NULL;
     r->ram_addr = IO_MEM_UNASSIGNED;  
   
     wmask = ~(size - 1);      wmask = ~(size - 1);
     addr = pci_bar(pci_dev, region_num);      addr = pci_bar(pci_dev, region_num);
Line 903  void pci_register_bar(PCIDevice *pci_dev Line 896  void pci_register_bar(PCIDevice *pci_dev
         pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);          pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
         pci_set_long(pci_dev->cmask + addr, 0xffffffff);          pci_set_long(pci_dev->cmask + addr, 0xffffffff);
     }      }
       pci_dev->io_regions[region_num].memory = memory;
       pci_dev->io_regions[region_num].address_space
           = type & PCI_BASE_ADDRESS_SPACE_IO
           ? pci_dev->bus->address_space_io
           : pci_dev->bus->address_space_mem;
 }  }
   
 static void pci_simple_bar_mapfunc(PCIDevice *pci_dev, int region_num,  pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
                                    pcibus_t addr, pcibus_t size, int type)  
 {  {
     cpu_register_physical_memory(addr, size,      return pci_dev->io_regions[region_num].addr;
                                  pci_dev->io_regions[region_num].ram_addr);  
 }  
   
 void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,  
                              pcibus_t size,  uint8_t attr, ram_addr_t ram_addr)  
 {  
     pci_register_bar(pci_dev, region_num, size,  
                      PCI_BASE_ADDRESS_SPACE_MEMORY | attr,  
                      pci_simple_bar_mapfunc);  
     pci_dev->io_regions[region_num].ram_addr = ram_addr;  
 }  
   
 static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,  
                               uint8_t type)  
 {  
     pcibus_t base = *addr;  
     pcibus_t limit = *addr + *size - 1;  
     PCIDevice *br;  
   
     for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) {  
         uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);  
   
         if (type & PCI_BASE_ADDRESS_SPACE_IO) {  
             if (!(cmd & PCI_COMMAND_IO)) {  
                 goto no_map;  
             }  
         } else {  
             if (!(cmd & PCI_COMMAND_MEMORY)) {  
                 goto no_map;  
             }  
         }  
   
         base = MAX(base, pci_bridge_get_base(br, type));  
         limit = MIN(limit, pci_bridge_get_limit(br, type));  
     }  
   
     if (base > limit) {  
         goto no_map;  
     }  
     *addr = base;  
     *size = limit - base + 1;  
     return;  
 no_map:  
     *addr = PCI_BAR_UNMAPPED;  
     *size = 0;  
 }  }
   
 static pcibus_t pci_bar_address(PCIDevice *d,  static pcibus_t pci_bar_address(PCIDevice *d,
Line 1025  static void pci_update_mappings(PCIDevic Line 977  static void pci_update_mappings(PCIDevic
 {  {
     PCIIORegion *r;      PCIIORegion *r;
     int i;      int i;
     pcibus_t new_addr, filtered_size;      pcibus_t new_addr;
   
     for(i = 0; i < PCI_NUM_REGIONS; i++) {      for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];          r = &d->io_regions[i];
Line 1036  static void pci_update_mappings(PCIDevic Line 988  static void pci_update_mappings(PCIDevic
   
         new_addr = pci_bar_address(d, i, r->type, r->size);          new_addr = pci_bar_address(d, i, r->type, r->size);
   
         /* bridge filtering */  
         filtered_size = r->size;  
         if (new_addr != PCI_BAR_UNMAPPED) {  
             pci_bridge_filter(d, &new_addr, &filtered_size, r->type);  
         }  
   
         /* This bar isn't changed */          /* This bar isn't changed */
         if (new_addr == r->addr && filtered_size == r->filtered_size)          if (new_addr == r->addr)
             continue;              continue;
   
         /* now do the real mapping */          /* now do the real mapping */
         if (r->addr != PCI_BAR_UNMAPPED) {          if (r->addr != PCI_BAR_UNMAPPED) {
             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {              memory_region_del_subregion(r->address_space, r->memory);
                 int class;  
                 /* NOTE: specific hack for IDE in PC case:  
                    only one byte must be mapped. */  
                 class = pci_get_word(d->config + PCI_CLASS_DEVICE);  
                 if (class == 0x0101 && r->size == 4) {  
                     isa_unassign_ioport(r->addr + 2, 1);  
                 } else {  
                     isa_unassign_ioport(r->addr, r->filtered_size);  
                 }  
             } else {  
                 cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),  
                                              r->filtered_size,  
                                              IO_MEM_UNASSIGNED);  
                 qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);  
             }  
         }          }
         r->addr = new_addr;          r->addr = new_addr;
         r->filtered_size = filtered_size;  
         if (r->addr != PCI_BAR_UNMAPPED) {          if (r->addr != PCI_BAR_UNMAPPED) {
             /*              memory_region_add_subregion_overlap(r->address_space,
              * TODO: currently almost all the map funcions assumes                                                  r->addr, r->memory, 1);
              * filtered_size == size and addr & ~(size - 1) == addr.  
              * However with bridge filtering, they aren't always true.  
              * Teach them such cases, such that filtered_size < size and  
              * addr & (size - 1) != 0.  
              */  
             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {  
                 r->map_func(d, i, r->addr, r->filtered_size, r->type);  
             } else {  
                 r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),  
                             r->filtered_size, r->type);  
             }  
         }          }
     }      }
 }  }
Line 1108  uint32_t pci_default_read_config(PCIDevi Line 1027  uint32_t pci_default_read_config(PCIDevi
                                  uint32_t address, int len)                                   uint32_t address, int len)
 {  {
     uint32_t val = 0;      uint32_t val = 0;
     assert(len == 1 || len == 2 || len == 4);  
     len = MIN(len, pci_config_size(d) - address);  
     memcpy(&val, d->config + address, len);      memcpy(&val, d->config + address, len);
     return le32_to_cpu(val);      return le32_to_cpu(val);
 }  }
Line 1117  uint32_t pci_default_read_config(PCIDevi Line 1035  uint32_t pci_default_read_config(PCIDevi
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)  void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {  {
     int i, was_irq_disabled = pci_irq_disabled(d);      int i, was_irq_disabled = pci_irq_disabled(d);
     uint32_t config_size = pci_config_size(d);  
   
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {      for (i = 0; i < l; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];          uint8_t wmask = d->wmask[addr + i];
         uint8_t w1cmask = d->w1cmask[addr + i];          uint8_t w1cmask = d->w1cmask[addr + i];
         assert(!(wmask & w1cmask));          assert(!(wmask & w1cmask));
Line 1247  void pci_for_each_device(PCIBus *bus, in Line 1164  void pci_for_each_device(PCIBus *bus, in
     }      }
 }  }
   
 static void pci_device_print(Monitor *mon, QDict *device)  static const pci_class_desc *get_class_desc(int class)
 {  {
     QDict *qdict;      const pci_class_desc *desc;
     QListEntry *entry;  
     uint64_t addr, size;  
   
     monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));  
     monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",  
                         qdict_get_int(device, "slot"),  
                         qdict_get_int(device, "function"));  
     monitor_printf(mon, "    ");  
   
     qdict = qdict_get_qdict(device, "class_info");  
     if (qdict_haskey(qdict, "desc")) {  
         monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));  
     } else {  
         monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));  
     }  
   
     qdict = qdict_get_qdict(device, "id");  
     monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",  
                         qdict_get_int(qdict, "device"),  
                         qdict_get_int(qdict, "vendor"));  
   
     if (qdict_haskey(device, "irq")) {      desc = pci_class_descriptions;
         monitor_printf(mon, "      IRQ %" PRId64 ".\n",      while (desc->desc && class != desc->class) {
                             qdict_get_int(device, "irq"));          desc++;
     }      }
   
     if (qdict_haskey(device, "pci_bridge")) {      return desc;
         QDict *info;  }
   
         qdict = qdict_get_qdict(device, "pci_bridge");  
   
         info = qdict_get_qdict(qdict, "bus");  
         monitor_printf(mon, "      BUS %" PRId64 ".\n",  
                             qdict_get_int(info, "number"));  
         monitor_printf(mon, "      secondary bus %" PRId64 ".\n",  
                             qdict_get_int(info, "secondary"));  
         monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",  
                             qdict_get_int(info, "subordinate"));  
   
         info = qdict_get_qdict(qdict, "io_range");  static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num);
         monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",  
                        qdict_get_int(info, "base"),  
                        qdict_get_int(info, "limit"));  
   
         info = qdict_get_qdict(qdict, "memory_range");  static PciMemoryRegionList *qmp_query_pci_regions(const PCIDevice *dev)
         monitor_printf(mon,  {
                        "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",      PciMemoryRegionList *head = NULL, *cur_item = NULL;
                        qdict_get_int(info, "base"),      int i;
                        qdict_get_int(info, "limit"));  
   
         info = qdict_get_qdict(qdict, "prefetchable_range");      for (i = 0; i < PCI_NUM_REGIONS; i++) {
         monitor_printf(mon, "      prefetchable memory range "          const PCIIORegion *r = &dev->io_regions[i];
                        "[0x%08"PRIx64", 0x%08"PRIx64"]\n",          PciMemoryRegionList *region;
                        qdict_get_int(info, "base"),  
         qdict_get_int(info, "limit"));  
     }  
   
     QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {          if (!r->size) {
         qdict = qobject_to_qdict(qlist_entry_obj(entry));              continue;
         monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));          }
   
         addr = qdict_get_int(qdict, "address");          region = g_malloc0(sizeof(*region));
         size = qdict_get_int(qdict, "size");          region->value = g_malloc0(sizeof(*region->value));
   
         if (!strcmp(qdict_get_str(qdict, "type"), "io")) {          if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
             monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS              region->value->type = g_strdup("io");
                                 " [0x%04"FMT_PCIBUS"].\n",  
                                 addr, addr + size - 1);  
         } else {          } else {
             monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS              region->value->type = g_strdup("memory");
                                " [0x%08"FMT_PCIBUS"].\n",              region->value->has_prefetch = true;
                                 qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,              region->value->prefetch = !!(r->type & PCI_BASE_ADDRESS_MEM_PREFETCH);
                                 qdict_get_bool(qdict, "prefetch") ?              region->value->has_mem_type_64 = true;
                                 " prefetchable" : "", addr, addr + size - 1);              region->value->mem_type_64 = !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
         }          }
     }  
   
     monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));          region->value->bar = i;
           region->value->address = r->addr;
     if (qdict_haskey(device, "pci_bridge")) {          region->value->size = r->size;
         qdict = qdict_get_qdict(device, "pci_bridge");  
         if (qdict_haskey(qdict, "devices")) {          /* XXX: waiting for the qapi to support GSList */
             QListEntry *dev;          if (!cur_item) {
             QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {              head = cur_item = region;
                 pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));          } else {
             }              cur_item->next = region;
               cur_item = region;
         }          }
     }      }
 }  
   
 void do_pci_info_print(Monitor *mon, const QObject *data)      return head;
 {  
     QListEntry *bus, *dev;  
   
     QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {  
         QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));  
         QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {  
             pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));  
         }  
     }  
 }  }
   
 static QObject *pci_get_dev_class(const PCIDevice *dev)  static PciBridgeInfo *qmp_query_pci_bridge(PCIDevice *dev, PCIBus *bus,
                                              int bus_num)
 {  {
     int class;      PciBridgeInfo *info;
     const pci_class_desc *desc;  
   
     class = pci_get_word(dev->config + PCI_CLASS_DEVICE);      info = g_malloc0(sizeof(*info));
     desc = pci_class_descriptions;  
     while (desc->desc && class != desc->class)  
         desc++;  
   
     if (desc->desc) {      info->bus.number = dev->config[PCI_PRIMARY_BUS];
         return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",      info->bus.secondary = dev->config[PCI_SECONDARY_BUS];
                                   desc->desc, class);      info->bus.subordinate = dev->config[PCI_SUBORDINATE_BUS];
     } else {  
         return qobject_from_jsonf("{ 'class': %d }", class);  
     }  
 }  
   
 static QObject *pci_get_dev_id(const PCIDevice *dev)      info->bus.io_range = g_malloc0(sizeof(*info->bus.io_range));
 {      info->bus.io_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO);
     return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",      info->bus.io_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO);
                               pci_get_word(dev->config + PCI_VENDOR_ID),  
                               pci_get_word(dev->config + PCI_DEVICE_ID));  
 }  
   
 static QObject *pci_get_regions_list(const PCIDevice *dev)      info->bus.memory_range = g_malloc0(sizeof(*info->bus.memory_range));
 {      info->bus.memory_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
     int i;      info->bus.memory_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY);
     QList *regions_list;  
   
     regions_list = qlist_new();      info->bus.prefetchable_range = g_malloc0(sizeof(*info->bus.prefetchable_range));
       info->bus.prefetchable_range->base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
       info->bus.prefetchable_range->limit = pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
   
     for (i = 0; i < PCI_NUM_REGIONS; i++) {      if (dev->config[PCI_SECONDARY_BUS] != 0) {
         QObject *obj;          PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
         const PCIIORegion *r = &dev->io_regions[i];          if (child_bus) {
               info->has_devices = true;
         if (!r->size) {              info->devices = qmp_query_pci_devices(child_bus, dev->config[PCI_SECONDARY_BUS]);
             continue;  
         }          }
   
         if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {  
             obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "  
                                      "'address': %" PRId64 ", "  
                                      "'size': %" PRId64 " }",  
                                      i, r->addr, r->size);  
         } else {  
             int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;  
   
             obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "  
                                      "'mem_type_64': %i, 'prefetch': %i, "  
                                      "'address': %" PRId64 ", "  
                                      "'size': %" PRId64 " }",  
                                      i, mem_type_64,  
                                      r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,  
                                      r->addr, r->size);  
         }  
   
         qlist_append_obj(regions_list, obj);  
     }      }
   
     return QOBJECT(regions_list);      return info;
 }  }
   
 static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);  static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus,
                                              int bus_num)
 static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)  
 {  {
       const pci_class_desc *desc;
       PciDeviceInfo *info;
     uint8_t type;      uint8_t type;
     QObject *obj;      int class;
   
     obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"      info = g_malloc0(sizeof(*info));
                               " 'qdev_id': %s }",      info->bus = bus_num;
                               bus_num,      info->slot = PCI_SLOT(dev->devfn);
                               PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),      info->function = PCI_FUNC(dev->devfn);
                               pci_get_dev_class(dev), pci_get_dev_id(dev),  
                               pci_get_regions_list(dev),      class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
                               dev->qdev.id ? dev->qdev.id : "");      info->class_info.class = class;
       desc = get_class_desc(class);
       if (desc->desc) {
           info->class_info.has_desc = true;
           info->class_info.desc = g_strdup(desc->desc);
       }
   
       info->id.vendor = pci_get_word(dev->config + PCI_VENDOR_ID);
       info->id.device = pci_get_word(dev->config + PCI_DEVICE_ID);
       info->regions = qmp_query_pci_regions(dev);
       info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : "");
   
     if (dev->config[PCI_INTERRUPT_PIN] != 0) {      if (dev->config[PCI_INTERRUPT_PIN] != 0) {
         QDict *qdict = qobject_to_qdict(obj);          info->has_irq = true;
         qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));          info->irq = dev->config[PCI_INTERRUPT_LINE];
     }      }
   
     type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;      type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
     if (type == PCI_HEADER_TYPE_BRIDGE) {      if (type == PCI_HEADER_TYPE_BRIDGE) {
         QDict *qdict;          info->has_pci_bridge = true;
         QObject *pci_bridge;          info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num);
   
         pci_bridge = qobject_from_jsonf("{ 'bus': "  
         "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "  
         "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "  
         "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "  
         "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",  
         dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],  
         dev->config[PCI_SUBORDINATE_BUS],  
         pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),  
         pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),  
         pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),  
         pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),  
         pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |  
                                PCI_BASE_ADDRESS_MEM_PREFETCH),  
         pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |  
                                 PCI_BASE_ADDRESS_MEM_PREFETCH));  
   
         if (dev->config[PCI_SECONDARY_BUS] != 0) {  
             PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);  
   
             if (child_bus) {  
                 qdict = qobject_to_qdict(pci_bridge);  
                 qdict_put_obj(qdict, "devices",  
                               pci_get_devices_list(child_bus,  
                                                    dev->config[PCI_SECONDARY_BUS]));  
             }  
         }  
         qdict = qobject_to_qdict(obj);  
         qdict_put_obj(qdict, "pci_bridge", pci_bridge);  
     }      }
   
     return obj;      return info;
 }  }
   
 static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)  static PciDeviceInfoList *qmp_query_pci_devices(PCIBus *bus, int bus_num)
 {  {
     int devfn;      PciDeviceInfoList *info, *head = NULL, *cur_item = NULL;
     PCIDevice *dev;      PCIDevice *dev;
     QList *dev_list;      int devfn;
   
     dev_list = qlist_new();  
   
     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {      for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
         dev = bus->devices[devfn];          dev = bus->devices[devfn];
         if (dev) {          if (dev) {
             qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));              info = g_malloc0(sizeof(*info));
               info->value = qmp_query_pci_device(dev, bus, bus_num);
   
               /* XXX: waiting for the qapi to support GSList */
               if (!cur_item) {
                   head = cur_item = info;
               } else {
                   cur_item->next = info;
                   cur_item = info;
               }
         }          }
     }      }
   
     return QOBJECT(dev_list);      return head;
 }  }
   
 static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)  static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
 {  {
       PciInfo *info = NULL;
   
     bus = pci_find_bus(bus, bus_num);      bus = pci_find_bus(bus, bus_num);
     if (bus) {      if (bus) {
         return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",          info = g_malloc0(sizeof(*info));
                                   bus_num, pci_get_devices_list(bus, bus_num));          info->bus = bus_num;
           info->devices = qmp_query_pci_devices(bus, bus_num);
     }      }
   
     return NULL;      return info;
 }  }
   
 void do_pci_info(Monitor *mon, QObject **ret_data)  PciInfoList *qmp_query_pci(Error **errp)
 {  {
     QList *bus_list;      PciInfoList *info, *head = NULL, *cur_item = NULL;
     struct PCIHostBus *host;      struct PCIHostBus *host;
   
     bus_list = qlist_new();  
   
     QLIST_FOREACH(host, &host_buses, next) {      QLIST_FOREACH(host, &host_buses, next) {
         QObject *obj = pci_get_bus_dict(host->bus, 0);          info = g_malloc0(sizeof(*info));
         if (obj) {          info->value = qmp_query_pci_bus(host->bus, 0);
             qlist_append_obj(bus_list, obj);  
           /* XXX: waiting for the qapi to support GSList */
           if (!cur_item) {
               head = cur_item = info;
           } else {
               cur_item->next = info;
               cur_item = info;
         }          }
     }      }
   
     *ret_data = QOBJECT(bus_list);      return head;
 }  }
   
 static const char * const pci_nic_models[] = {  static const char * const pci_nic_models[] = {
Line 1588  PCIDevice *pci_nic_init_nofail(NICInfo * Line 1423  PCIDevice *pci_nic_init_nofail(NICInfo *
     return res;      return res;
 }  }
   
 static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)  
 {  
     pci_update_mappings(d);  
 }  
   
 void pci_bridge_update_mappings(PCIBus *b)  
 {  
     PCIBus *child;  
   
     pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn);  
   
     QLIST_FOREACH(child, &b->child, sibling) {  
         pci_bridge_update_mappings(child);  
     }  
 }  
   
 /* Whether a given bus number is in range of the secondary  /* Whether a given bus number is in range of the secondary
  * bus of the given bridge device. */   * bus of the given bridge device. */
 static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)  static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
Line 1692  static int pci_qdev_init(DeviceState *qd Line 1511  static int pci_qdev_init(DeviceState *qd
     /* rom loading */      /* rom loading */
     is_default_rom = false;      is_default_rom = false;
     if (pci_dev->romfile == NULL && info->romfile != NULL) {      if (pci_dev->romfile == NULL && info->romfile != NULL) {
         pci_dev->romfile = qemu_strdup(info->romfile);          pci_dev->romfile = g_strdup(info->romfile);
         is_default_rom = true;          is_default_rom = true;
     }      }
     pci_add_option_rom(pci_dev, is_default_rom);      pci_add_option_rom(pci_dev, is_default_rom);
Line 1823  static uint8_t pci_find_capability_list( Line 1642  static uint8_t pci_find_capability_list(
     return next;      return next;
 }  }
   
 static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)  static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
 {  {
     cpu_register_physical_memory(addr, size, pdev->rom_offset);      uint8_t next, prev, found = 0;
   
       if (!(pdev->used[offset])) {
           return 0;
       }
   
       assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
   
       for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
            prev = next + PCI_CAP_LIST_NEXT) {
           if (next <= offset && next > found) {
               found = next;
           }
       }
       return found;
 }  }
   
 /* Patch the PCI vendor and device ids in a PCI rom image if necessary.  /* Patch the PCI vendor and device ids in a PCI rom image if necessary.
Line 1913  static int pci_add_option_rom(PCIDevice  Line 1746  static int pci_add_option_rom(PCIDevice 
   
     path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);      path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
     if (path == NULL) {      if (path == NULL) {
         path = qemu_strdup(pdev->romfile);          path = g_strdup(pdev->romfile);
     }      }
   
     size = get_image_size(path);      size = get_image_size(path);
     if (size < 0) {      if (size < 0) {
         error_report("%s: failed to find romfile \"%s\"",          error_report("%s: failed to find romfile \"%s\"",
                      __FUNCTION__, pdev->romfile);                       __FUNCTION__, pdev->romfile);
         qemu_free(path);          g_free(path);
         return -1;          return -1;
     }      }
     if (size & (size - 1)) {      if (size & (size - 1)) {
Line 1931  static int pci_add_option_rom(PCIDevice  Line 1764  static int pci_add_option_rom(PCIDevice 
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);          snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
     else      else
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);          snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
     pdev->rom_offset = qemu_ram_alloc(&pdev->qdev, name, size);      pdev->has_rom = true;
       memory_region_init_ram(&pdev->rom, &pdev->qdev, name, size);
     ptr = qemu_get_ram_ptr(pdev->rom_offset);      ptr = memory_region_get_ram_ptr(&pdev->rom);
     load_image(path, ptr);      load_image(path, ptr);
     qemu_free(path);      g_free(path);
   
     if (is_default_rom) {      if (is_default_rom) {
         /* Only the default rom images will be patched (if needed). */          /* Only the default rom images will be patched (if needed). */
Line 1944  static int pci_add_option_rom(PCIDevice  Line 1777  static int pci_add_option_rom(PCIDevice 
   
     qemu_put_ram_ptr(ptr);      qemu_put_ram_ptr(ptr);
   
     pci_register_bar(pdev, PCI_ROM_SLOT, size,      pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
                      0, pci_map_option_rom);  
   
     return 0;      return 0;
 }  }
   
 static void pci_del_option_rom(PCIDevice *pdev)  static void pci_del_option_rom(PCIDevice *pdev)
 {  {
     if (!pdev->rom_offset)      if (!pdev->has_rom)
         return;          return;
   
     qemu_ram_free(pdev->rom_offset);      memory_region_destroy(&pdev->rom);
     pdev->rom_offset = 0;      pdev->has_rom = false;
 }  }
   
 /*  /*
Line 1970  int pci_add_capability(PCIDevice *pdev,  Line 1802  int pci_add_capability(PCIDevice *pdev, 
                        uint8_t offset, uint8_t size)                         uint8_t offset, uint8_t size)
 {  {
     uint8_t *config;      uint8_t *config;
       int i, overlapping_cap;
   
     if (!offset) {      if (!offset) {
         offset = pci_find_space(pdev, size);          offset = pci_find_space(pdev, size);
         if (!offset) {          if (!offset) {
             return -ENOSPC;              return -ENOSPC;
         }          }
       } else {
           /* Verify that capabilities don't overlap.  Note: device assignment
            * depends on this check to verify that the device is not broken.
            * Should never trigger for emulated devices, but it's helpful
            * for debugging these. */
           for (i = offset; i < offset + size; i++) {
               overlapping_cap = pci_find_capability_at_offset(pdev, i);
               if (overlapping_cap) {
                   fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
                           "Attempt to add PCI capability %x at offset "
                           "%x overlaps existing capability %x at offset %x\n",
                           pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
                           PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
                           cap_id, offset, overlapping_cap, i);
                   return -EINVAL;
               }
           }
     }      }
   
     config = pdev->config + offset;      config = pdev->config + offset;
Line 2008  void pci_del_capability(PCIDevice *pdev, Line 1859  void pci_del_capability(PCIDevice *pdev,
         pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;          pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
 }  }
   
 /* Reserve space for capability at a known offset (to call after load). */  
 void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)  
 {  
     memset(pdev->used + offset, 0xff, size);  
 }  
   
 uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)  uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
 {  {
     return pci_find_capability_list(pdev, cap_id, NULL);      return pci_find_capability_list(pdev, cap_id, NULL);
Line 2126  static char *pcibus_get_dev_path(DeviceS Line 1971  static char *pcibus_get_dev_path(DeviceS
     path_len = domain_len + slot_len * slot_depth;      path_len = domain_len + slot_len * slot_depth;
   
     /* Allocate memory, fill in the terminating null byte. */      /* Allocate memory, fill in the terminating null byte. */
     path = qemu_malloc(path_len + 1 /* For '\0' */);      path = g_malloc(path_len + 1 /* For '\0' */);
     path[path_len] = '\0';      path[path_len] = '\0';
   
     /* First field is the domain. */      /* First field is the domain. */
Line 2183  int pci_qdev_find_device(const char *id, Line 2028  int pci_qdev_find_device(const char *id,
   
     return rc;      return rc;
 }  }
   
   MemoryRegion *pci_address_space(PCIDevice *dev)
   {
       return dev->bus->address_space_mem;
   }
   
   MemoryRegion *pci_address_space_io(PCIDevice *dev)
   {
       return dev->bus->address_space_io;
   }

Removed from v.1.1.1.15  
changed lines
  Added in v.1.1.1.16


unix.superglobalmegacorp.com