[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 02/15] pci: handle BAR mapping at PCI level
From: |
Blue Swirl |
Subject: |
[Qemu-devel] [PATCH 02/15] pci: handle BAR mapping at PCI level |
Date: |
Mon, 12 Jul 2010 18:40:00 +0000 |
Move IOIO and MMIO BAR mapping to pci.c.
Signed-off-by: Blue Swirl <address@hidden>
---
hw/pci.c | 166 ++++++++++++++++++++++++++++++++++++++++----------------------
hw/pci.h | 14 +++++-
2 files changed, 121 insertions(+), 59 deletions(-)
diff --git a/hw/pci.c b/hw/pci.c
index a3c2873..2234717 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -735,19 +735,28 @@ static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
static void pci_unregister_io_regions(PCIDevice *pci_dev)
{
PCIIORegion *r;
- int i;
+ PCIIOSubRegion *s;
+ int i, j;
for(i = 0; i < PCI_NUM_REGIONS; i++) {
r = &pci_dev->io_regions[i];
if (!r->size || r->addr == PCI_BAR_UNMAPPED)
continue;
- if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
- 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);
+
+ for (j = 0; j < PCI_NUM_SUBREGIONS; j++) {
+ s = &r->subregions[j];
+
+ if (!s->size) {
+ continue;
+ }
+ if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
+ isa_unassign_ioport(r->addr + s->offset, s->filtered_size);
+ } else {
+ cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
+ r->addr + s->offset),
+ s->filtered_size,
+ IO_MEM_UNASSIGNED);
+ }
}
}
}
@@ -789,7 +798,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
r = &pci_dev->io_regions[region_num];
r->addr = PCI_BAR_UNMAPPED;
r->size = size;
- r->filtered_size = size;
r->type = type;
r->map_func = map_func;
@@ -808,6 +816,25 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
pci_set_long(pci_dev->cmask + addr, 0xffffffff);
}
+ pci_bar_map(pci_dev, region_num, 0, 0, size, -1);
+}
+
+void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
+ pcibus_t offset, pcibus_t size, int ix)
+{
+ PCIIOSubRegion *s;
+
+ if ((unsigned int)region_num >= PCI_NUM_REGIONS ||
+ (unsigned int)subregion_num >= PCI_NUM_SUBREGIONS) {
+ return;
+ }
+
+ s = &pci_dev->io_regions[region_num].subregions[subregion_num];
+
+ s->offset = offset;
+ s->size = size;
+ s->filtered_size = size;
+ s->ix = ix;
}
static uint32_t pci_config_get_io_base(PCIDevice *d,
@@ -982,8 +1009,9 @@ static pcibus_t pci_bar_address(PCIDevice *d,
static void pci_update_mappings(PCIDevice *d)
{
PCIIORegion *r;
- int i;
- pcibus_t new_addr, filtered_size;
+ PCIIOSubRegion *s;
+ int i, j;
+ pcibus_t bar_addr, new_addr, filtered_size;
for(i = 0; i < PCI_NUM_REGIONS; i++) {
r = &d->io_regions[i];
@@ -992,54 +1020,81 @@ static void pci_update_mappings(PCIDevice *d)
if (!r->size)
continue;
- new_addr = pci_bar_address(d, i, r->type, r->size);
+ bar_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);
- }
+ for (j = 0; j < PCI_NUM_SUBREGIONS; j++) {
+ s = &r->subregions[j];
- /* This bar isn't changed */
- if (new_addr == r->addr && filtered_size == r->filtered_size)
- continue;
+ /* this subregion isn't registered */
+ if (!s->size) {
+ continue;
+ }
+
+ new_addr = bar_addr + s->offset;
- /* now do the real mapping */
- if (r->addr != PCI_BAR_UNMAPPED) {
- if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
- 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);
+ /* bridge filtering */
+ filtered_size = s->size;
+ if (bar_addr != PCI_BAR_UNMAPPED) {
+ pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
+ }
+
+ /* this subregion hasn't changed */
+ if (bar_addr == r->addr && new_addr == bar_addr + s->offset &&
+ filtered_size == s->filtered_size) {
+ continue;
+ }
+ /* now do the real mapping */
+ if (r->addr != PCI_BAR_UNMAPPED) {
+ if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+ 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 + s->offset + 2, 1);
+ } else {
+ isa_unassign_ioport(r->addr + s->offset,
+ s->filtered_size);
+ }
} else {
- isa_unassign_ioport(r->addr, r->filtered_size);
+ cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+ r->addr +
+ s->offset),
+ s->filtered_size,
+ IO_MEM_UNASSIGNED);
+ qemu_unregister_coalesced_mmio(r->addr + s->offset,
+ s->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->filtered_size = filtered_size;
- if (r->addr != PCI_BAR_UNMAPPED) {
- /*
- * TODO: currently almost all the map funcions assumes
- * 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);
+ s->filtered_size = filtered_size;
+ if (bar_addr != PCI_BAR_UNMAPPED && new_addr != PCI_BAR_UNMAPPED) {
+ /*
+ * TODO: currently almost all the map funcions assumes
+ * 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) {
+ if (r->map_func) {
+ r->map_func(d, i, new_addr, s->filtered_size, r->type);
+ } else {
+ cpu_map_io(new_addr, s->ix);
+ }
+ } else {
+ if (r->map_func) {
+ r->map_func(d, i, pci_to_cpu_addr(d->bus, new_addr),
+ s->filtered_size, r->type);
+ } else {
+ cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+ new_addr),
+ s->filtered_size,
+ s->ix);
+ }
+ }
}
}
+ r->addr = bar_addr;
}
}
@@ -1775,11 +1830,6 @@ static uint8_t
pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
return next;
}
-static void pci_map_option_rom(PCIDevice *pdev, int region_num,
pcibus_t addr, pcibus_t size, int type)
-{
- cpu_register_physical_memory(addr, size, pdev->rom_offset);
-}
-
/* Add an option rom for the device */
static int pci_add_option_rom(PCIDevice *pdev)
{
@@ -1832,8 +1882,8 @@ static int pci_add_option_rom(PCIDevice *pdev)
load_image(path, ptr);
qemu_free(path);
- pci_register_bar(pdev, PCI_ROM_SLOT, size,
- 0, pci_map_option_rom);
+ pci_register_bar(pdev, PCI_ROM_SLOT, size, 0, NULL);
+ pci_bar_map(pdev, PCI_ROM_SLOT, 0, 0, size, pdev->rom_offset);
return 0;
}
diff --git a/hw/pci.h b/hw/pci.h
index 1eab7e7..b518b3f 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -81,13 +81,22 @@ typedef void PCIMapIORegionFunc(PCIDevice
*pci_dev, int region_num,
pcibus_t addr, pcibus_t size, int type);
typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
+typedef struct PCIIOSubRegion {
+ pcibus_t offset; /* offset to BAR start. -1 means not mapped */
+ pcibus_t size;
+ pcibus_t filtered_size;
+ int ix;
+} PCIIOSubRegion;
+
+#define PCI_NUM_SUBREGIONS 16
+
typedef struct PCIIORegion {
pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
pcibus_t size;
- pcibus_t filtered_size;
uint8_t type;
PCIMapIORegionFunc *map_func;
+ PCIIOSubRegion subregions[PCI_NUM_SUBREGIONS];
} PCIIORegion;
#define PCI_ROM_SLOT 6
@@ -183,6 +192,9 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size, int type,
PCIMapIORegionFunc *map_func);
+void pci_bar_map(PCIDevice *pci_dev, int region_num, int subregion_num,
+ pcibus_t offset, pcibus_t size, int ix);
+
int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
int pci_add_capability_at_offset(PCIDevice *pci_dev, uint8_t cap_id,
uint8_t cap_offset, uint8_t cap_size);
--
1.7.1
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH 02/15] pci: handle BAR mapping at PCI level,
Blue Swirl <=