From patchwork Wed Dec 22 10:54:49 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 76383 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 8FC1AB70A3 for ; Wed, 22 Dec 2010 21:58:18 +1100 (EST) Received: from localhost ([127.0.0.1]:51826 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PVMOc-0003i6-CD for incoming@patchwork.ozlabs.org; Wed, 22 Dec 2010 05:58:14 -0500 Received: from [140.186.70.92] (port=56323 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PVMLR-0002JJ-S2 for qemu-devel@nongnu.org; Wed, 22 Dec 2010 05:54:59 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PVMLP-0006YK-Ul for qemu-devel@nongnu.org; Wed, 22 Dec 2010 05:54:57 -0500 Received: from mail.valinux.co.jp ([210.128.90.3]:34230) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PVMLP-0006Xe-DT for qemu-devel@nongnu.org; Wed, 22 Dec 2010 05:54:55 -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 40B0428040; Wed, 22 Dec 2010 19:54:52 +0900 (JST) Received: (nullmailer pid 26810 invoked by uid 1000); Wed, 22 Dec 2010 10:54:50 -0000 From: Isaku Yamahata To: qemu-devel@nongnu.org Date: Wed, 22 Dec 2010 19:54:49 +0900 Message-Id: X-Mailer: git-send-email 1.7.1.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: yamahata@valinux.co.jp, mst@redhat.com Subject: [Qemu-devel] [PATCH 2/3] pci: introduce a parser for fw device path to pci device 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 Introduce a function to parse fw device path to pci device. the format is /pci@{, }/[]@,/.../[]@, = "i" = = slot number in hex = func number in hex Signed-off-by: Isaku Yamahata --- hw/pci.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci.h | 2 + 2 files changed, 130 insertions(+), 0 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index eb21848..a52a323 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -2027,3 +2027,131 @@ static char *pcibus_get_dev_path(DeviceState *dev) return strdup(path); } +/* + * Parse format and get PCIDevice + * return 0 on success + * <0 on error: format is invalid or device isn't found. + * + * Format: + * /pci@{, }/[]@,/... + * .../[]@, + * + * = "i" + * = + * = slot number in hex + * = func number in hex + * + */ +int pci_parse_fw_dev_path(const char *path, PCIDevice **pdev) +{ + const char *p = path; + char *e; + size_t len; + PCIBus *bus; + struct PCIHostBus *host; + + if (*p != '/') { + return -EINVAL; + } + e = strchr(p + 1, '/'); + if (e == NULL) { + return -EINVAL; + } + len = e - p; + p = e + 1; + + bus = NULL; + QLIST_FOREACH(host, &host_buses, next) { + DeviceState *qdev = host->bus->qbus.parent; + if (qdev) { + char *devpath = qdev_get_fw_dev_path(qdev); + + if (len == strlen(devpath) && !strncmp(devpath, path, len)) { + bus = host->bus; + qemu_free(devpath); + break; + } + qemu_free(devpath); + } else { + /* This pci bus doesn't have host-to-pci bridge device. + * Check only if the path is pci ignoring other parameters. */ +#define PCI_FW_PATH "/pci@" + if (strncmp(path, PCI_FW_PATH, strlen(PCI_FW_PATH))) { + return -EINVAL; + } + bus = host->bus; + break; + } + } + + for (;;) { + char *at; + char *comma; + unsigned long slot; + unsigned long func; + PCIDevice *dev; + PCIBus *child_bus; + + if (!bus) { + return -ENODEV; + } + if (*p == '\0') { + return -EINVAL; + } + + at = strchr(p, '@'); + if (at == NULL) { + return -EINVAL; + } + slot = strtoul(at + 1, &e, 16); + if (e == at + 1 || *e != ',') { + return -EINVAL; + } + if (slot >= PCI_SLOT_MAX) { + return -EINVAL; + } + + comma = e; + func = strtoul(comma + 1, &e, 16); + if (e == comma + 1 || (*e != '/' && *e != '\0')) { + return -EINVAL; + } + if (func >= PCI_FUNC_MAX) { + return -EINVAL; + } + + len = e - p; + dev = bus->devices[PCI_DEVFN(slot, func)]; + if (!dev) { + return -ENODEV; + } + if (at != p) { + /* fw_name is specified. */ + char *fw_dev_path = pcibus_get_fw_dev_path(&dev->qdev); + if (strncmp(p, fw_dev_path, len)) { + qemu_free(fw_dev_path); + return -EINVAL; + } + qemu_free(fw_dev_path); + } + + if (*e == '\0') { + *pdev = dev; + return 0; + } + + /* + * descending down pci-to-pci bridge. + * At the moment, there is no way to safely determine if the given + * pci device is really pci-to-pci device. + */ + p = e; + QLIST_FOREACH(child_bus, &bus->child, sibling) { + if (child_bus->parent_dev == dev) { + bus = child_bus; + continue; + } + } + bus = NULL; + } +} diff --git a/hw/pci.h b/hw/pci.h index 6e80b08..96f8d52 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -16,6 +16,7 @@ #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) +#define PCI_SLOT_MAX 32 #define PCI_FUNC_MAX 8 /* Class, Vendor and Device IDs from Linux's pci_ids.h */ @@ -258,6 +259,7 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned int *slotp, unsigned int *funcp); int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, unsigned *slotp); +int pci_parse_fw_dev_path(const char *path, PCIDevice **pdev); void do_pci_info_print(Monitor *mon, const QObject *data); void do_pci_info(Monitor *mon, QObject **ret_data);