From patchwork Thu Jul 22 21:54:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Blue Swirl X-Patchwork-Id: 59699 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 0D50EB70E6 for ; Fri, 23 Jul 2010 09:24:47 +1000 (EST) Received: from localhost ([127.0.0.1]:39764 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Oc4m7-0002QG-AJ for incoming@patchwork.ozlabs.org; Thu, 22 Jul 2010 19:01:59 -0400 Received: from [140.186.70.92] (port=42696 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Oc3xU-00030V-K3 for qemu-devel@nongnu.org; Thu, 22 Jul 2010 18:09:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1Oc3jP-0002KG-AM for qemu-devel@nongnu.org; Thu, 22 Jul 2010 17:55:10 -0400 Received: from mail-gx0-f173.google.com ([209.85.161.173]:39217) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Oc3jP-0002KA-5g for qemu-devel@nongnu.org; Thu, 22 Jul 2010 17:55:07 -0400 Received: by gxk19 with SMTP id 19so5306201gxk.4 for ; Thu, 22 Jul 2010 14:55:06 -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=HlIIC4tMH67mspHSWpWnRjQYkWoB4jC/U7/rBPhH0uA=; b=e79K1+3dpr9cxeO1+fKRZvhrYW3OhukzokbKBBmNu8N0hCpQLm0A8CHWPz2QCQA8d6 Bx7ESqGPF0d6Xk+tCjvW7JGPDNzrwuagYj/MCSKJPoh/Nif6PvE3S2cbuWTcXKhGE3Br N+lrCHy9t3JtAQBrEjXwuSl1h6xU1Y2hl1II4= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; b=mtObM99i8s9IRKvQj8ZNdGxZBOymR0elSo3PtnRdzOxryOAAgLC0TQ0pLXLviW4eju bNibA1JEwlQhnSvj23QsWuBayXx2HIPfW6Rf07FOb0sh9DLwN5WX45f6z8l2oPMqZvqK 8rLSGmnvor/ar4zjU4ygp8YeZNm//j6uHGYMI= Received: by 10.100.197.4 with SMTP id u4mr3058265anf.17.1279835706270; Thu, 22 Jul 2010 14:55:06 -0700 (PDT) MIME-Version: 1.0 Received: by 10.229.185.146 with HTTP; Thu, 22 Jul 2010 14:54:46 -0700 (PDT) From: Blue Swirl Date: Thu, 22 Jul 2010 21:54:46 +0000 Message-ID: To: qemu-devel X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: [Qemu-devel] [PATCH 02/34] 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 | 167 ++++++++++++++++++++++++++++++++++++++++--------------------- hw/pci.h | 14 +++++- 2 files changed, 122 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 a98d6f3..49f03fb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -744,19 +744,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); + } } } } @@ -798,7 +807,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; @@ -817,6 +825,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, @@ -991,8 +1018,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]; @@ -1001,54 +1029,82 @@ 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 && + s->ix >= 0) { + /* + * 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; } } @@ -1791,11 +1847,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) { @@ -1848,8 +1899,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;