From f88d7509b444ffa289e5054b34bc6f4800f6b76d Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:29 +0900 Subject: pci: fix pci_info_device(). It printed wrong limit value of bridge. This patch fixes it. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index 5b3461cd66..040fa767fb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -986,7 +986,7 @@ static void pci_info_device(PCIBus *bus, PCIDevice *d) base, limit); base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY); - limit= pci_config_get_memory_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY); + limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY); monitor_printf(mon, " memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit); -- cgit 1.4.1 From 070297d2609fea4fd7afec05eb9a43688b91fb79 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:35 +0900 Subject: pci: remove pci_sub_bus() by open coding. Because pci_sub_bus() is used only once so eliminate it by open coding as suggested by "Michael S. Tsirkin" . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index 040fa767fb..aa677b2dbe 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -239,13 +239,6 @@ int pci_bus_num(PCIBus *s) return s->parent_dev->config[PCI_SECONDARY_BUS]; } -static uint8_t pci_sub_bus(PCIBus *s) -{ - if (!s->parent_dev) - return 255; /* pci host bridge */ - return s->parent_dev->config[PCI_SUBORDINATE_BUS]; -} - static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) { PCIDevice *s = container_of(pv, PCIDevice, config); @@ -1180,7 +1173,10 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num) /* try child bus */ QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_num(sec) <= bus_num && bus_num <= pci_sub_bus(sec)) { + + if (!bus->parent_dev /* pci host bridge */ + || (pci_bus_num(sec) <= bus_num && + bus->parent_dev->config[PCI_SUBORDINATE_BUS])) { return pci_find_bus(sec, bus_num); } } -- cgit 1.4.1 From c469e1dd6375c50bc61d995dde4714fc19f411ed Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:36 +0900 Subject: pci: s/pci_find_host_bus/pci_find_root_bus/g This patch renames pci_find_host_bus() to pci_find_root_bus() as suggested by "Michael S. Tsirkin" . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci-hotplug.c | 4 ++-- hw/pci.c | 8 ++++---- hw/pci.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index a254498143..081d6d1ac9 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -113,7 +113,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { goto err; } - dev = pci_find_device(pci_find_host_bus(0), pci_bus, slot, 0); + dev = pci_find_device(pci_find_root_bus(0), pci_bus, slot, 0); if (!dev) { monitor_printf(mon, "no pci device with address %s\n", pci_addr); goto err; @@ -257,7 +257,7 @@ void pci_device_hot_remove(Monitor *mon, const char *pci_addr) return; } - d = pci_find_device(pci_find_host_bus(0), bus, slot, 0); + d = pci_find_device(pci_find_root_bus(0), bus, slot, 0); if (!d) { monitor_printf(mon, "slot %d empty\n", slot); return; diff --git a/hw/pci.c b/hw/pci.c index aa677b2dbe..d8f5fa0ede 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -146,7 +146,7 @@ static void pci_host_bus_register(int domain, PCIBus *bus) QLIST_INSERT_HEAD(&host_buses, host, next); } -PCIBus *pci_find_host_bus(int domain) +PCIBus *pci_find_root_bus(int domain) { struct PCIHostBus *host; @@ -372,7 +372,7 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s return -1; /* Note: QEMU doesn't implement domains other than 0 */ - if (!pci_find_bus(pci_find_host_bus(dom), bus)) + if (!pci_find_bus(pci_find_root_bus(dom), bus)) return -1; *domp = dom; @@ -402,7 +402,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) if (!devaddr) { *devfnp = -1; - return pci_find_bus(pci_find_host_bus(0), 0); + return pci_find_bus(pci_find_root_bus(0), 0); } if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) { @@ -410,7 +410,7 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) } *devfnp = slot << 3; - return pci_find_bus(pci_find_host_bus(0), bus); + return pci_find_bus(pci_find_root_bus(0), bus); } static void pci_init_cmask(PCIDevice *dev) diff --git a/hw/pci.h b/hw/pci.h index 2f213524c5..ff5f36ceeb 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -295,7 +295,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, const char *default_devaddr); int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d)); -PCIBus *pci_find_host_bus(int domain); +PCIBus *pci_find_root_bus(int domain); PCIBus *pci_find_bus(PCIBus *bus, int bus_num); PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function); PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr); -- cgit 1.4.1 From c34369d48c9b94f5a71f65cc97caaa5a75ffad5c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:38 +0900 Subject: pci: kill unnecessary included in pci.c including pci_host.h isn't needed by pci.c. This patch kills it. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index d8f5fa0ede..c3ad1bbb89 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -23,7 +23,6 @@ */ #include "hw.h" #include "pci.h" -#include "pci_host.h" #include "monitor.h" #include "net.h" #include "sysemu.h" -- cgit 1.4.1 From 3e21ffc954c09e90b25a446813ff1c0b26817aef Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:39 +0900 Subject: pci: clean up of pci_init_wmask(). This patch replaces for loop by memset in pci_init_wmask(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index c3ad1bbb89..64cf0a8a50 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -426,15 +426,15 @@ static void pci_init_cmask(PCIDevice *dev) static void pci_init_wmask(PCIDevice *dev) { - int i; int config_size = pci_config_size(dev); dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; dev->wmask[PCI_INTERRUPT_LINE] = 0xff; pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i) - dev->wmask[i] = 0xff; + + memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff, + config_size - PCI_CONFIG_HEADER_SIZE); } static void pci_init_wmask_bridge(PCIDevice *d) -- cgit 1.4.1 From ec50344230aad67a867ac59e4a0cd7233149484c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:43 +0900 Subject: pci: clean up of pci_update_mappings() This patch converts r->size == 0 to !r_size. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index 64cf0a8a50..d6f647cc25 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -733,7 +733,7 @@ static void pci_update_mappings(PCIDevice *d) r = &d->io_regions[i]; /* this region isn't registered */ - if (r->size == 0) + if (!r->size) continue; if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { -- cgit 1.4.1 From 876a350d3daed88c5677397c287c6210cf163f6c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 12 Nov 2009 13:47:17 +0200 Subject: pci: split up up pci_update mappings Split bar address math into a separate function. In particular, this gets rid of an ugly forward goto into scope that we have there. Signed-off-by: Michael S. Tsirkin Acked-by: Isaku Yamahata --- hw/pci.c | 125 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 68 insertions(+), 57 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index d6f647cc25..49d06489e0 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -721,14 +721,77 @@ static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, } } +static pcibus_t pci_bar_address(PCIDevice *d, + int reg, uint8_t type, pcibus_t size) +{ + pcibus_t new_addr, last_addr; + int bar = pci_bar(d, reg); + uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); + + if (type & PCI_BASE_ADDRESS_SPACE_IO) { + if (!(cmd & PCI_COMMAND_IO)) { + return PCI_BAR_UNMAPPED; + } + new_addr = pci_get_long(d->config + bar) & ~(size - 1); + last_addr = new_addr + size - 1; + /* NOTE: we have only 64K ioports on PC */ + if (last_addr <= new_addr || new_addr == 0 || last_addr > UINT16_MAX) { + return PCI_BAR_UNMAPPED; + } + return new_addr; + } + + if (!(cmd & PCI_COMMAND_MEMORY)) { + return PCI_BAR_UNMAPPED; + } + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + new_addr = pci_get_quad(d->config + bar); + } else { + new_addr = pci_get_long(d->config + bar); + } + /* the ROM slot has a specific enable bit */ + if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { + return PCI_BAR_UNMAPPED; + } + new_addr &= ~(size - 1); + last_addr = new_addr + size - 1; + /* NOTE: we do not support wrapping */ + /* XXX: as we cannot support really dynamic + mappings, we handle specific values as invalid + mappings. */ + if (last_addr <= new_addr || new_addr == 0 || + last_addr == PCI_BAR_UNMAPPED) { + return PCI_BAR_UNMAPPED; + } + + /* Now pcibus_t is 64bit. + * Check if 32 bit BAR wraps around explicitly. + * Without this, PC ide doesn't work well. + * TODO: remove this work around. + */ + if (!(type & PCI_BASE_ADDRESS_MEM_TYPE_64) && last_addr >= UINT32_MAX) { + return PCI_BAR_UNMAPPED; + } + + /* + * OS is allowed to set BAR beyond its addressable + * bits. For example, 32 bit OS can set 64bit bar + * to >4G. Check it. TODO: we might need to support + * it in the future for e.g. PAE. + */ + if (last_addr >= TARGET_PHYS_ADDR_MAX) { + return PCI_BAR_UNMAPPED; + } + + return new_addr; +} + static void pci_update_mappings(PCIDevice *d) { PCIIORegion *r; - int cmd, i; - pcibus_t last_addr, new_addr; - pcibus_t filtered_size; + int i; + pcibus_t new_addr, filtered_size; - cmd = pci_get_word(d->config + PCI_COMMAND); for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -736,59 +799,7 @@ static void pci_update_mappings(PCIDevice *d) if (!r->size) continue; - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - if (cmd & PCI_COMMAND_IO) { - new_addr = pci_get_long(d->config + pci_bar(d, i)); - new_addr = new_addr & ~(r->size - 1); - last_addr = new_addr + r->size - 1; - /* NOTE: we have only 64K ioports on PC */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr >= 0x10000) { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - if (cmd & PCI_COMMAND_MEMORY) { - if (r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - new_addr = pci_get_quad(d->config + pci_bar(d, i)); - } else { - new_addr = pci_get_long(d->config + pci_bar(d, i)); - } - /* the ROM slot has a specific enable bit */ - if (i == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) - goto no_mem_map; - new_addr = new_addr & ~(r->size - 1); - last_addr = new_addr + r->size - 1; - /* NOTE: we do not support wrapping */ - /* XXX: as we cannot support really dynamic - mappings, we handle specific values as invalid - mappings. */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr == PCI_BAR_UNMAPPED || - - /* Now pcibus_t is 64bit. - * Check if 32 bit BAR wrap around explicitly. - * Without this, PC ide doesn't work well. - * TODO: remove this work around. - */ - (!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) && - last_addr >= UINT32_MAX) || - - /* - * OS is allowed to set BAR beyond its addressable - * bits. For example, 32 bit OS can set 64bit bar - * to >4G. Check it. - */ - last_addr >= TARGET_PHYS_ADDR_MAX) { - new_addr = PCI_BAR_UNMAPPED; - } - } else { - no_mem_map: - new_addr = PCI_BAR_UNMAPPED; - } - } + new_addr = pci_bar_address(d, i, r->type, r->size); /* bridge filtering */ filtered_size = r->size; -- cgit 1.4.1 From b47b0706f15f9427ffc48b0db61f1b6e52b98b2a Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:45 +0900 Subject: pci: remove magic number, 256 in pci.c This patch replaces magic number, 256, with ARRAY_SIZE(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index 49d06489e0..6d94286a46 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -487,7 +487,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, uint8_t header_type) { if (devfn < 0) { - for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { + for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); + devfn += 8) { if (!bus->devices[devfn]) goto found; } @@ -1035,7 +1036,7 @@ static void pci_for_each_device_under_bus(PCIBus *bus, PCIDevice *d; int devfn; - for(devfn = 0; devfn < 256; devfn++) { + for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { d = bus->devices[devfn]; if (d) fn(bus, d); -- cgit 1.4.1 From 10c9c329da60fe64ad24dba6f81044559ff15f9b Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:46 +0900 Subject: pci: fix pci_config_get_io_base(). fix typo in pci_config_get_io_base(). Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index 6d94286a46..bc566e5945 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -630,7 +630,7 @@ static uint32_t pci_config_get_io_base(PCIDevice *d, 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 + PCI_IO_BASE_UPPER16) << 16; + val |= (uint32_t)pci_get_word(d->config + base_upper16) << 16; } return val; } -- cgit 1.4.1 From d46636b88339ecc2cb8d10113f45ada164817773 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 12 Nov 2009 14:58:47 +0900 Subject: pci: pci bridge related clean up. - fix bridge prefetchable memory accesser to check 64bit or not. - use pcibus_t consistently instead mixing pcibus_t and uint64_t. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 18 +++++++++++------- hw/pci.h | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index bc566e5945..e26b3d0341 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -635,19 +635,23 @@ static uint32_t pci_config_get_io_base(PCIDevice *d, return val; } -static uint64_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) +static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) { - return ((uint64_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) + return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) << 16; } -static uint64_t pci_config_get_pref_base(PCIDevice *d, +static pcibus_t pci_config_get_pref_base(PCIDevice *d, uint32_t base, uint32_t upper) { - uint64_t val; - val = ((uint64_t)pci_get_word(d->config + base) & - PCI_PREF_RANGE_MASK) << 16; - val |= (uint64_t)pci_get_long(d->config + upper) << 32; + 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; } diff --git a/hw/pci.h b/hw/pci.h index 6a868f95de..0baf69bd5d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -131,6 +131,7 @@ typedef struct PCIIORegion { #define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ #define PCI_PREF_MEMORY_LIMIT 0x26 #define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_RANGE_TYPE_64 0x01 #define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ #define PCI_PREF_LIMIT_UPPER32 0x2c #define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */ -- cgit 1.4.1 From 88a9556430df57cbe7666e4e4cf78c3bd3bc8220 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 12 Nov 2009 13:54:31 +0200 Subject: pci: convert goto into scope in bridge_filter goto into scope is evil. rearrange pci_bridge_filter so that we always go to end of function on error. Signed-off-by: Michael S. Tsirkin Acked-by: Isaku Yamahata --- hw/pci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'hw/pci.c') diff --git a/hw/pci.c b/hw/pci.c index e26b3d0341..8cf008d31d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -717,13 +717,14 @@ static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, } if (base > limit) { - no_map: - *addr = PCI_BAR_UNMAPPED; - *size = 0; - } else { - *addr = base; - *size = limit - base + 1; + 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, -- cgit 1.4.1