From patchwork Mon Jul 12 18:40:00 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Blue Swirl X-Patchwork-Id: 58646 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 02CF5B6F01 for ; Tue, 13 Jul 2010 04:45:44 +1000 (EST) Received: from localhost ([127.0.0.1]:58521 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OYO0X-0002hx-1u for incoming@patchwork.ozlabs.org; Mon, 12 Jul 2010 14:45:37 -0400 Received: from [140.186.70.92] (port=47319 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OYNvT-0000Ag-IC for qemu-devel@nongnu.org; Mon, 12 Jul 2010 14:40:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OYNvS-00065l-0J for qemu-devel@nongnu.org; Mon, 12 Jul 2010 14:40:23 -0400 Received: from mail-pz0-f45.google.com ([209.85.210.45]:50876) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OYNvR-00065a-Nh for qemu-devel@nongnu.org; Mon, 12 Jul 2010 14:40:21 -0400 Received: by pzk10 with SMTP id 10so1294765pzk.4 for ; Mon, 12 Jul 2010 11:40:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:mime-version:received:from:date :message-id:subject:to:content-type; bh=eUk5RJAkj1usvBFWHU0StGBvmoFxa6rcVxlbED3IJrg=; b=CP2HfAcR4db8uxKX9Ga7GKy6Zgohls4RUg/fZ4cjwp9TnnNfNUAQcYI2vpRjOCR8Lb J2wqhz5swA532dBCRjoCAeh0r9Lnu2VS0gpr8doskrbizDlw5mOb7RetELrShgrL4yYO 3OCwvzUnM4L52Qvf1DztC/pyFsPiZ5gsDCQFY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; b=vAmviW9oNjKavp5bSogl+Qew8A7SEVq6OIn1Ud9ur+yv0su3xtV+Qp3Sbo3yTOoBbl uThbH75L1zD9w61SltOPG6VXPajwbJmWi27XLwrQSH85L7EDP89Qtgnkz5VI7NU1vHIr JTtvMJdAZS517vT7abye3W9GiUwZYgHoalK2g= Received: by 10.142.132.12 with SMTP id f12mr17009376wfd.223.1278960020150; Mon, 12 Jul 2010 11:40:20 -0700 (PDT) MIME-Version: 1.0 Received: by 10.142.212.14 with HTTP; Mon, 12 Jul 2010 11:40:00 -0700 (PDT) From: Blue Swirl Date: Mon, 12 Jul 2010 18:40:00 +0000 Message-ID: To: qemu-devel , Anthony Liguori , "Michael S. Tsirkin" X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: Subject: [Qemu-devel] [PATCH 02/15] pci: handle BAR mapping at PCI level X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Move IOIO and MMIO BAR mapping to pci.c. Signed-off-by: Blue Swirl --- hw/pci.c | 166 ++++++++++++++++++++++++++++++++++++++++---------------------- hw/pci.h | 14 +++++- 2 files changed, 121 insertions(+), 59 deletions(-) #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); 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;