From patchwork Wed Mar 16 09:29:18 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 87210 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 889D9B6F9A for ; Wed, 16 Mar 2011 21:04:12 +1100 (EST) Received: from localhost ([127.0.0.1]:55936 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PznaC-0004gd-1v for incoming@patchwork.ozlabs.org; Wed, 16 Mar 2011 06:04:00 -0400 Received: from [140.186.70.92] (port=34437 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Pzn35-0006Fn-Hy for qemu-devel@nongnu.org; Wed, 16 Mar 2011 05:29:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Pzn2z-0006CJ-Td for qemu-devel@nongnu.org; Wed, 16 Mar 2011 05:29:47 -0400 Received: from mail.valinux.co.jp ([210.128.90.3]:37355) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Pzn2z-0006BU-7e for qemu-devel@nongnu.org; Wed, 16 Mar 2011 05:29:41 -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 967861892A; Wed, 16 Mar 2011 18:29:38 +0900 (JST) Received: (nullmailer pid 18348 invoked by uid 1000); Wed, 16 Mar 2011 09:29:37 -0000 From: Isaku Yamahata To: qemu-devel@nongnu.org Date: Wed, 16 Mar 2011 18:29:18 +0900 Message-Id: <392c8eaaeb8f0729ab39b261d0dda21208c05ea6.1300266238.git.yamahata@valinux.co.jp> 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) X-Received-From: 210.128.90.3 Cc: yamahata@valinux.co.jp, "Michael S. Tsirkin" Subject: [Qemu-devel] [PATCH 07/26] pci/p2pbr: generic pci p2p bridge 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 Create generic pci p2p bridge device which can be customized via properties like vendor id/device id and so on. With this, we can avoid to create many pci p2p bridge which only differs in those ids. Cc: Michael S. Tsirkin Signed-off-by: Isaku Yamahata --- Makefile.objs | 2 +- hw/pci_p2pbr.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci_p2pbr.h | 61 +++++++++++++++++++++++ 3 files changed, 213 insertions(+), 1 deletions(-) create mode 100644 hw/pci_p2pbr.c create mode 100644 hw/pci_p2pbr.h diff --git a/Makefile.objs b/Makefile.objs index a52f42f..5cb7010 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -171,7 +171,7 @@ hw-obj-y = hw-obj-y += vl.o loader.o hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o hw-obj-y += fw_cfg.o -hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o +hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_p2pbr.o hw-obj-$(CONFIG_PCI) += msix.o msi.o hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o diff --git a/hw/pci_p2pbr.c b/hw/pci_p2pbr.c new file mode 100644 index 0000000..e5b03e2 --- /dev/null +++ b/hw/pci_p2pbr.c @@ -0,0 +1,151 @@ +/* + * QEMU PCI P2P generic bridge. + * In order to avoid create many P2P bridge device which only differs + * in vendor id/device id and so on. + * + * Copyright (c) 2011 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "pci_bridge.h" +#include "pci_internals.h" +#include "pci_p2pbr.h" + +typedef struct PCIP2PBridge { + struct PCIBridge br; + + /* device specific initialization */ + pci_p2pbr_init_fn initfn; + + /* properties */ + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision_id; + uint8_t prog_interface; + + uint8_t ssvid_cap; + uint16_t svid; + uint16_t ssid; +} PCIP2PBridge; + +static int pci_p2pbr_initfn(PCIDevice *d) +{ + PCIBridge *br = DO_UPCAST(PCIBridge, dev, d); + PCIP2PBridge *p2pbr = DO_UPCAST(PCIP2PBridge, br, br); + uint8_t *config = d->config; + int rc; + + rc = pci_bridge_initfn(d); + if (rc < 0) { + return rc; + } + + pci_config_set_vendor_id(config, p2pbr->vendor_id); + pci_config_set_device_id(config, p2pbr->device_id); + pci_config_set_revision(config, p2pbr->revision_id); + pci_config_set_prog_interface(config, p2pbr->prog_interface); + + if (p2pbr->ssvid_cap > 0) { + rc = pci_bridge_ssvid_init(d, p2pbr->ssvid_cap, + p2pbr->svid, p2pbr->ssid); + if (rc < 0) { + return rc; + } + } + + if (p2pbr->initfn) { + return p2pbr->initfn(d); + } + + return 0; +} + +#define PCI_P2P_BRIDGE "PCI P2P bridge" + +static PCIDeviceInfo pci_p2pbr_info = { + .qdev.name = PCI_P2P_BRIDGE, + .qdev.desc = "PCI PCI-to-PCI bridge", + .qdev.size = sizeof(PCIP2PBridge), + .qdev.reset = pci_bridge_reset, + .qdev.vmsd = &vmstate_pci_device, + + .is_bridge = 1, + .init = pci_p2pbr_initfn, + .exit = pci_bridge_exitfn, + .config_write = pci_bridge_write_config, + + .qdev.props = (Property[]) { + DEFINE_PROP_UINT16("vendor_id", PCIP2PBridge, vendor_id, 0), + DEFINE_PROP_UINT16("device_id", PCIP2PBridge, device_id, 0), + DEFINE_PROP_UINT8("revision_id", PCIP2PBridge, revision_id, 0), + DEFINE_PROP_UINT8("prog_interface", PCIP2PBridge, prog_interface, 0), + + DEFINE_PROP_UINT8("ssvid_cap", PCIP2PBridge, ssvid_cap, 0), + DEFINE_PROP_UINT16("svid", PCIP2PBridge, svid, 0), + DEFINE_PROP_UINT16("ssid", PCIP2PBridge, ssid, 0), + + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void pci_p2pbr_register(void) +{ + pci_qdev_register(&pci_p2pbr_info); +} + +device_init(pci_p2pbr_register); + +PCIBridge *pci_p2pbr_create(const PCIP2PBridgeInit *init) +{ + PCIDevice *d; + PCIBridge *br; + PCIP2PBridge *p2pbr; + + d = pci_create_multifunction(init->bus, init->devfn, init->multifunction, + PCI_P2P_BRIDGE); + + br = DO_UPCAST(PCIBridge, dev, d); + pci_bridge_map_irq(br, init->bus_name, init->map_irq); + + p2pbr = DO_UPCAST(PCIP2PBridge, br, br); + p2pbr->initfn = init->initfn; + + return br; +} + +void pci_p2pbr_prop_set(PCIBridge *br, const PCIP2PBridgeProp *prop) +{ + DeviceState *qdev = &br->dev.qdev; + + qdev_prop_set_uint16(qdev, "vendor_id", prop->vendor_id); + qdev_prop_set_uint16(qdev, "device_id", prop->device_id); + qdev_prop_set_uint8(qdev, "revision_id", prop->revision_id); + qdev_prop_set_uint8(qdev, "prog_interface", prop->prog_interface); + + qdev_prop_set_uint8(qdev, "ssvid_cap", prop->ssvid_cap); + qdev_prop_set_uint16(qdev, "svid", prop->svid); + qdev_prop_set_uint16(qdev, "ssid", prop->ssid); +} + +/* convenience function to create pci p2p bridge */ +PCIBridge *pci_p2pbr_create_simple(const PCIP2PBridgeInit *init, + const PCIP2PBridgeProp *prop) +{ + PCIBridge *br = pci_p2pbr_create(init); + pci_p2pbr_prop_set(br, prop); + qdev_init_nofail(&br->dev.qdev); + return br; +} diff --git a/hw/pci_p2pbr.h b/hw/pci_p2pbr.h new file mode 100644 index 0000000..ee23ebb --- /dev/null +++ b/hw/pci_p2pbr.h @@ -0,0 +1,61 @@ +/* + * QEMU PCI P2P generic bridge. + * In order to avoid create many P2P bridge device which only differs + * in vendor id/device id and so on. + * + * Copyright (c) 2011 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_PCI_P2PBR_H +#define QEMU_PCI_P2PBR_H + +#include "qdev.h" + +typedef int (*pci_p2pbr_init_fn)(PCIDevice *d); + +typedef struct PCIP2PBridgeInit +{ + PCIBus *bus; + uint8_t devfn; + bool multifunction; + + const char* bus_name; + pci_map_irq_fn map_irq; + + pci_p2pbr_init_fn initfn; +} PCIP2PBridgeInit; + +typedef struct PCIP2PBridgeProp +{ + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision_id; + uint8_t prog_interface; + + uint8_t ssvid_cap; + uint8_t svid; + uint8_t ssid; +} PCIP2PBridgeProp; + +/* When setting PCIP2PBridgeProb, zero clear it for future compatibility */ +PCIBridge *pci_p2pbr_create(const PCIP2PBridgeInit *init); +void pci_p2pbr_prop_set(PCIBridge *br, const PCIP2PBridgeProp *prop); + +PCIBridge *pci_p2pbr_create_simple(const PCIP2PBridgeInit *init, + const PCIP2PBridgeProp *prop); + +#endif /* QEMU_PCI_P2PBR_H */