From patchwork Fri Feb 12 02:31:34 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 45176 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 34B93B7CEE for ; Fri, 12 Feb 2010 13:39:29 +1100 (EST) Received: from localhost ([127.0.0.1]:39213 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NflKQ-00019H-LB for incoming@patchwork.ozlabs.org; Thu, 11 Feb 2010 21:32:22 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NflJ9-00018Q-RG for qemu-devel@nongnu.org; Thu, 11 Feb 2010 21:31:03 -0500 Received: from [199.232.76.173] (port=42715 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NflJ8-000183-Ff for qemu-devel@nongnu.org; Thu, 11 Feb 2010 21:31:02 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1NflJ7-0004FQ-IH for qemu-devel@nongnu.org; Thu, 11 Feb 2010 21:31:02 -0500 Received: from mail.valinux.co.jp ([210.128.90.3]:40931) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NflJ6-0004FI-Sb for qemu-devel@nongnu.org; Thu, 11 Feb 2010 21:31:01 -0500 Received: from ps.local.valinux.co.jp (vagw.valinux.co.jp [210.128.90.14]) by mail.valinux.co.jp (Postfix) with SMTP id 511B348A6E; Fri, 12 Feb 2010 11:30:56 +0900 (JST) Received: (nullmailer pid 32675 invoked by uid 1000); Fri, 12 Feb 2010 02:31:34 -0000 Date: Fri, 12 Feb 2010 11:31:34 +0900 From: Isaku Yamahata To: qemu-devel@nongnu.org Message-ID: <20100212023134.GC11930@valinux.co.jp> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.19 (2009-01-05) X-Virus-Scanned: clamav-milter 0.95.2 at va-mail.local.valinux.co.jp X-Virus-Status: Clean X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: Blue Swirl , "Michael S. Tsirkin" Subject: [Qemu-devel] [PATCH] pci: introduce get_info_quirk callback. 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 This patch fixes 525e05147d5a3bdc08caa422d108c1ef71b584b5 by introducing device specific get_info_quirk callback. It wrongly assumes that pci host bridge class device has header type of pci-pci bridge. But this isn't always true. In fact i440fx pci host bridge has header type of normal device, hence it breaks i440fx and other pci host bridges. The right fix is that header type should be checked, instead of device class. The change set's purpose is to show PBM pci host bridge info which doesn't conform to PCI specification. So introduce get_info_quirk callback and use it for PBM. Cc: Blue Swirl Cc: "Michael S. Tsirkin" Signed-off-by: Isaku Yamahata --- hw/apb_pci.c | 1 + hw/pci.c | 79 ++++++++++++++++++++++++++++++++------------------------- hw/pci.h | 3 ++ 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 46d5b0e..a557469 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -479,6 +479,7 @@ static PCIDeviceInfo pbm_pci_host_info = { .qdev.name = "pbm", .qdev.size = sizeof(PCIDevice), .init = pbm_pci_host_init, + .get_info_quirk = pci_bridge_get_info, .header_type = PCI_HEADER_TYPE_BRIDGE, }; diff --git a/hw/pci.c b/hw/pci.c index 9ad63dd..1e2bde8 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1271,10 +1271,44 @@ static QObject *pci_get_regions_list(const PCIDevice *dev) static QObject *pci_get_devices_list(PCIBus *bus, int bus_num); +void pci_bridge_get_info(PCIDevice *dev, PCIBus *bus, QDict *qdict) +{ + QObject *pci_bridge; + + pci_bridge = qobject_from_jsonf("{ 'bus': " + "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, " + "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " + "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " + "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }", + dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS], + dev->config[PCI_SUBORDINATE_BUS], + pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO), + pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO), + pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), + pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), + pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH), + pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH)); + + if (dev->config[PCI_SECONDARY_BUS] != 0) { + PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]); + if (child_bus) { + qdict_put_obj(qobject_to_qdict(pci_bridge), "devices", + pci_get_devices_list(child_bus, + dev->config[PCI_SECONDARY_BUS])); + } + } + + qdict_put_obj(qdict, "pci_bridge", pci_bridge); +} + static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num) { - int class; + PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info); QObject *obj; + QDict *qdict; + uint8_t type; obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d," "'class_info': %p, 'id': %p, 'regions': %p," " 'qdev_id': %s }", @@ -1283,45 +1317,20 @@ static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num) pci_get_dev_class(dev), pci_get_dev_id(dev), pci_get_regions_list(dev), dev->qdev.id ? dev->qdev.id : ""); + qdict = qobject_to_qdict(obj); if (dev->config[PCI_INTERRUPT_PIN] != 0) { - QDict *qdict = qobject_to_qdict(obj); qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE])); } - class = pci_get_word(dev->config + PCI_CLASS_DEVICE); - if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_BRIDGE_PCI) { - QDict *qdict; - QObject *pci_bridge; - - pci_bridge = qobject_from_jsonf("{ 'bus': " - "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, " - "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " - "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, " - "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }", - dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS], - dev->config[PCI_SUBORDINATE_BUS], - pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO), - pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO), - pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), - pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY), - pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_PREFETCH), - pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_PREFETCH)); - - if (dev->config[PCI_SECONDARY_BUS] != 0) { - PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]); - - if (child_bus) { - qdict = qobject_to_qdict(pci_bridge); - qdict_put_obj(qdict, "devices", - pci_get_devices_list(child_bus, - dev->config[PCI_SECONDARY_BUS])); - } - } - qdict = qobject_to_qdict(obj); - qdict_put_obj(qdict, "pci_bridge", pci_bridge); + type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION; + if (type == PCI_HEADER_TYPE_BRIDGE) { + pci_bridge_get_info(dev, bus, qdict); + } + + if (info /* not all pci device aren't converted qdev yet */ && + info->get_info_quirk) { + info->get_info_quirk(dev, bus, qdict); } return obj; diff --git a/hw/pci.h b/hw/pci.h index 8b511d2..5b87acd 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -80,6 +80,7 @@ typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type); typedef int PCIUnregisterFunc(PCIDevice *pci_dev); +typedef void PCIGetInfoQuirkFunc(PCIDevice *pci_dev, PCIBus *bus, QDict *qdict); typedef struct PCIIORegion { pcibus_t addr; /* current PCI mapping address. -1 means not mapped */ @@ -240,6 +241,7 @@ void do_pci_info(Monitor *mon, QObject **ret_data); PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, pci_map_irq_fn map_irq, const char *name); PCIDevice *pci_bridge_get_device(PCIBus *bus); +void pci_bridge_get_info(PCIDevice *dev, PCIBus *bus, QDict *qdict); static inline void pci_set_byte(uint8_t *config, uint8_t val) @@ -314,6 +316,7 @@ typedef struct { PCIUnregisterFunc *exit; PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + PCIGetInfoQuirkFunc *get_info_quirk; /* pci config header type */ uint8_t header_type;