diff options
author | Isaku Yamahata <yamahata@valinux.co.jp> | 2009-10-30 21:21:22 +0900 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2009-11-09 08:43:10 -0600 |
commit | fb23162885f7fd8cf7334bed22c25ac32c7d8b9d (patch) | |
tree | c0a02f0d3a402336ecf847074692fd486ff41b18 /hw/pci.c | |
parent | edb000350d265b2eddb297453ddf9d504fb85fd0 (diff) |
pci: initialize pci config headers depending it pci header type.
- Only sets default subsystem id for header type 00.(normal header type)
because header type 01 doesn't have subsystem id, and uses the register
for other purpose. So setting default subsystem id doesn't make sense.
- initialize wmask more for header type 01.(bridge header type)
Without those wmasks, linux was confused not boot,
and lspci was confused not to print out expected IO/memory range.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/pci.c')
-rw-r--r-- | hw/pci.c | 42 |
1 files changed, 38 insertions, 4 deletions
@@ -445,6 +445,30 @@ static void pci_init_wmask(PCIDevice *dev) dev->wmask[i] = 0xff; } +static void pci_init_wmask_bridge(PCIDevice *d) +{ + /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and + PCI_SEC_LETENCY_TIMER */ + memset(d->wmask + PCI_PRIMARY_BUS, 0xff, 4); + + /* base and limit */ + d->wmask[PCI_IO_BASE] = PCI_IO_RANGE_MASK & 0xff; + d->wmask[PCI_IO_LIMIT] = PCI_IO_RANGE_MASK & 0xff; + pci_set_word(d->wmask + PCI_MEMORY_BASE, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_MEMORY_LIMIT, + PCI_MEMORY_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_PREF_MEMORY_BASE, + PCI_PREF_RANGE_MASK & 0xffff); + pci_set_word(d->wmask + PCI_PREF_MEMORY_LIMIT, + PCI_PREF_RANGE_MASK & 0xffff); + + /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ + memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); + + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff); +} + static void pci_config_alloc(PCIDevice *pci_dev) { int config_size = pci_config_size(pci_dev); @@ -467,7 +491,8 @@ static void pci_config_free(PCIDevice *pci_dev) static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, const char *name, int devfn, PCIConfigReadFunc *config_read, - PCIConfigWriteFunc *config_write) + PCIConfigWriteFunc *config_write, + uint8_t header_type) { if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { @@ -484,9 +509,16 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); pci_config_alloc(pci_dev); - pci_set_default_subsystem_id(pci_dev); + + header_type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + if (header_type == PCI_HEADER_TYPE_NORMAL) { + pci_set_default_subsystem_id(pci_dev); + } pci_init_cmask(pci_dev); pci_init_wmask(pci_dev); + if (header_type == PCI_HEADER_TYPE_BRIDGE) { + pci_init_wmask_bridge(pci_dev); + } if (!config_read) config_read = pci_default_read_config; @@ -509,7 +541,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, pci_dev = qemu_mallocz(instance_size); pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, - config_read, config_write); + config_read, config_write, + PCI_HEADER_TYPE_NORMAL); return pci_dev; } static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) @@ -1059,7 +1092,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); devfn = pci_dev->devfn; pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn, - info->config_read, info->config_write); + info->config_read, info->config_write, + info->header_type); assert(pci_dev); rc = info->init(pci_dev); if (rc != 0) |