From patchwork Mon Jun 21 06:03:58 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 56291 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 0D5D4B7D5E for ; Mon, 21 Jun 2010 16:17:28 +1000 (EST) Received: from localhost ([127.0.0.1]:34169 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OQaJx-0007GC-CY for incoming@patchwork.ozlabs.org; Mon, 21 Jun 2010 02:17:25 -0400 Received: from [140.186.70.92] (port=33973 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OQaAl-0002Pu-AA for qemu-devel@nongnu.org; Mon, 21 Jun 2010 02:07:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OQaAh-0000nl-2A for qemu-devel@nongnu.org; Mon, 21 Jun 2010 02:07:55 -0400 Received: from mail.valinux.co.jp ([210.128.90.3]:46876) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OQaAg-0000nX-IV for qemu-devel@nongnu.org; Mon, 21 Jun 2010 02:07:51 -0400 Received: from ps.local.valinux.co.jp (vagw.valinux.co.jp [210.128.90.14]) by mail.valinux.co.jp (Postfix) with SMTP id EB290107403; Mon, 21 Jun 2010 15:07:45 +0900 (JST) Received: (nullmailer pid 18095 invoked by uid 1000); Mon, 21 Jun 2010 06:04:01 -0000 From: Isaku Yamahata To: qemu-devel@nongnu.org Date: Mon, 21 Jun 2010 15:03:58 +0900 Message-Id: <99d849f1b4eeb12893447e78a6950c26a32088ac.1277100005.git.yamahata@valinux.co.jp> X-Mailer: git-send-email 1.6.6.1 In-Reply-To: References: In-Reply-To: References: X-Virus-Scanned: clamav-milter 0.95.2 at va-mail.local.valinux.co.jp X-Virus-Status: Clean X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: yu.liu@freescale.com, mst@redhat.com, blauwirbel@gmail.com, yamahata@valinux.co.jp, paul@codesourcery.com, aurelien@aurel32.net Subject: [Qemu-devel] [PATCH v4 3/6] pci: set PCI multi-function bit appropriately. 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 Set PCI multi-function bit according to multifunction property. PCI address, devfn ,is exported to users as addr property, so users can populate pci function(PCIDevice in qemu) at arbitrary devfn. It means each function(PCIDevice) don't know whether pci device (PCIDevice[8]) is multi function or not. So this patch allows user to set multifunction bit via property and checks whether multifunction bit is set correctly. Signed-off-by: Isaku Yamahata --- changes v3 -> v4: - introduce multifunction property. changes v2 -> v3: - introduce PCI_FUNC_MAX - more commit log changes v1 -> v2: --- hw/pci.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/pci.h | 4 ++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index b6c0a10..abc3c1d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -67,6 +67,7 @@ static struct BusInfo pci_bus_info = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), DEFINE_PROP_STRING("romfile", PCIDevice, romfile), DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1), + DEFINE_PROP_UINT8("multifunction", PCIDevice, mf, 0), DEFINE_PROP_END_OF_LIST() } }; @@ -575,6 +576,44 @@ static void pci_init_wmask_bridge(PCIDevice *d) pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff); } +static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) +{ + uint8_t slot = PCI_SLOT(dev->devfn); + uint8_t func = PCI_FUNC(dev->devfn); + + /* we are here before bus->devices[dev->devfn] = dev */ + assert(!bus->devices[dev->devfn]); + + if (dev->mf) { + dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + if (func) { + PCIDevice *d = bus->devices[PCI_DEVFN(slot, 0)]; + if (d && !d->mf) { + /* function 0 should set multifunction bit */ + error_report("PCI: single function device can't be populated " + "in function %x.%x", slot, func); + return -1; + } + return 0; + } + + if (dev->mf) { + return 0; + } + /* function 0 indicates single function, so function > 0 must be NULL */ + for (func = 1; func < PCI_FUNC_MAX; ++func) { + if (bus->devices[PCI_DEVFN(slot, func)]) { + error_report("PCI: %x.0 indicates single function, " + "but %x.%x is already populated.", + slot, slot, func); + return -1; + } + } + return 0; +} + static void pci_config_alloc(PCIDevice *pci_dev) { int config_size = pci_config_size(pci_dev); @@ -629,6 +668,9 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, if (is_bridge) { pci_init_wmask_bridge(pci_dev); } + if (pci_init_multifunction(bus, pci_dev)) { + return NULL; + } if (!config_read) config_read = pci_default_read_config; @@ -1652,22 +1694,34 @@ void pci_qdev_register_many(PCIDeviceInfo *info) } } -PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) +PCIDevice *pci_create_mf(PCIBus *bus, int devfn, uint8_t mf, const char *name) { DeviceState *dev; dev = qdev_create(&bus->qbus, name); qdev_prop_set_uint32(dev, "addr", devfn); + qdev_prop_set_uint8(dev, "multifunction", mf); return DO_UPCAST(PCIDevice, qdev, dev); } -PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) +PCIDevice *pci_create_simple_mf(PCIBus *bus, int devfn, uint8_t mf, + const char *name) { - PCIDevice *dev = pci_create(bus, devfn, name); + PCIDevice *dev = pci_create_mf(bus, devfn, mf, name); qdev_init_nofail(&dev->qdev); return dev; } +PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name) +{ + return pci_create_mf(bus, devfn, 0, name); +} + +PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) +{ + return pci_create_simple_mf(bus, devfn, 0, name); +} + static int pci_find_space(PCIDevice *pdev, uint8_t size) { int config_size = pci_config_size(pdev); diff --git a/hw/pci.h b/hw/pci.h index 76adc66..685fd44 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -131,6 +131,7 @@ struct PCIDevice { /* the following fields are read only */ PCIBus *bus; uint32_t devfn; + uint8_t mf; /* multi function capabile device */ char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; @@ -343,6 +344,9 @@ typedef struct { void pci_qdev_register(PCIDeviceInfo *info); void pci_qdev_register_many(PCIDeviceInfo *info); +PCIDevice *pci_create_mf(PCIBus *bus, int devfn, uint8_t mf, const char *name); +PCIDevice *pci_create_simple_mf(PCIBus *bus, int devfn, uint8_t mf, + const char *name); PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);