From patchwork Wed Sep 30 10:18:18 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 34578 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 D7D99B7BBA for ; Wed, 30 Sep 2009 23:09:13 +1000 (EST) Received: from localhost ([127.0.0.1]:46126 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Msyve-00020d-0V for incoming@patchwork.ozlabs.org; Wed, 30 Sep 2009 09:09:10 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MswIs-0004sh-Ck for qemu-devel@nongnu.org; Wed, 30 Sep 2009 06:20:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MswIQ-0004at-QO for qemu-devel@nongnu.org; Wed, 30 Sep 2009 06:20:52 -0400 Received: from [199.232.76.173] (port=43910 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MswIP-0004aZ-5B for qemu-devel@nongnu.org; Wed, 30 Sep 2009 06:20:29 -0400 Received: from mail.valinux.co.jp ([210.128.90.3]:55869) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MswIO-0005pj-8J for qemu-devel@nongnu.org; Wed, 30 Sep 2009 06:20:28 -0400 Received: from nm.local.valinux.co.jp (vagw.valinux.co.jp [210.128.90.14]) by mail.valinux.co.jp (Postfix) with ESMTP id B4AD649C30; Wed, 30 Sep 2009 19:20:17 +0900 (JST) Received: from yamahata by nm.local.valinux.co.jp with local (Exim 4.69) (envelope-from ) id 1MswGd-0003so-6i; Wed, 30 Sep 2009 19:18:39 +0900 From: Isaku Yamahata To: qemu-devel@nongnu.org, anthony@codemonkey.ws Date: Wed, 30 Sep 2009 19:18:18 +0900 Message-Id: <1254305917-14784-43-git-send-email-yamahata@valinux.co.jp> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: <1254305917-14784-1-git-send-email-yamahata@valinux.co.jp> References: <1254305917-14784-1-git-send-email-yamahata@valinux.co.jp> 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: yamahata@valinux.co.jp Subject: [Qemu-devel] [PATCH 42/61] pci/brdige: qdevfy and initialize secondary bus and subordinate bus. 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 qdevfy pci bridge, and initialize secondary bus and subordinate bus in configuration space. Signed-off-by: Isaku Yamahata --- hw/apb_pci.c | 10 +++-- hw/pci.c | 112 ++++++++++++++++++++++++++++++++++++++++++++-------------- hw/pci.h | 13 +++++++ 3 files changed, 104 insertions(+), 31 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index c2fe5bf..f679847 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -252,12 +252,14 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, 0, 32); pci_create_simple(d->host_state.bus, 0, "pbm"); /* APB secondary busses */ - *bus2 = pci_bridge_init(d->host_state.bus, 8, PCI_VENDOR_ID_SUN, + *bus2 = pci_bridge_init(d->host_state.bus, + PCI_DEVFN(1, 0), PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 1"); - *bus3 = pci_bridge_init(d->host_state.bus, 9, PCI_VENDOR_ID_SUN, + "Advanced PCI Bus Secondary bridge 1"); + *bus3 = pci_bridge_init(d->host_state.bus, + PCI_DEVFN(1, 1), PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq, - "Advanced PCI Bus secondary bridge 2"); + "Advanced PCI Bus Secondary bridge 2"); return d->host_state.bus; } diff --git a/hw/pci.c b/hw/pci.c index dc93b28..7a158db 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -129,12 +129,17 @@ static void pci_bus_reset(void *opaque) } } +static int pci_bus_get_instance_id(void) +{ + static int nbus = 0; + return nbus++; +} + PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int devfn_min, int nirq) { PCIBus *bus; - static int nbus = 0; bus = FROM_QBUS(PCIBus, qbus_create(&pci_bus_info, parent, name)); bus->set_irq = set_irq; @@ -144,20 +149,24 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, bus->nirq = nirq; bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0])); QLIST_INSERT_HEAD(&first_bus, bus, next); - vmstate_register(nbus++, &vmstate_pcibus, bus); + vmstate_register(pci_bus_get_instance_id(), &vmstate_pcibus, bus); qemu_register_reset(pci_bus_reset, bus); return bus; } -static PCIBus *pci_register_secondary_bus(PCIDevice *dev, - pci_map_irq_fn map_irq, - const char *name) +PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq, + const char* name, int devfn_min) { PCIBus *bus; bus = FROM_QBUS(PCIBus, qbus_create(&pci_bus_info, &dev->qdev, name)); + bus->map_irq = map_irq; - QLIST_INSERT_AFTER(dev->bus, bus, next); + bus->bus_num = dev->config[PCI_SECONDARY_BUS]; + bus->devfn_min = devfn_min; + + QLIST_INSERT_AFTER(pci_get_parent_bus(dev), bus, next); + vmstate_register(pci_bus_get_instance_id(), &vmstate_pcibus, bus); return bus; } @@ -1185,7 +1194,7 @@ static PCIBus *pci_bridge_get_secbus(PCIBridge *bridge) return qbus_to_pcibus(QLIST_FIRST(&bridge->dev.qdev.child_bus)); } -static void pci_bridge_write_config(PCIDevice *d, +void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config_common(d, address, val, len); @@ -1218,29 +1227,78 @@ PCIDevice *pci_find_device(int bus_num, int slot, int function) return bus->devices[PCI_DEVFN(slot, function)]; } -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, - pci_map_irq_fn map_irq, const char *name) +int pci_bridge_initfn(PCIDevice *pci_dev) { - PCIBridge *s; - s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), - devfn, NULL, pci_bridge_write_config); - - pci_config_set_vendor_id(s->dev.config, vid); - pci_config_set_device_id(s->dev.config, did); - - s->dev.config[0x04] = 0x06; // command = bus master, pci mem - s->dev.config[0x05] = 0x00; - s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error - s->dev.config[0x07] = 0x00; // status = fast devsel - s->dev.config[0x08] = 0x00; // revision - s->dev.config[0x09] = 0x00; // programming i/f - pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI); - s->dev.config[0x0D] = 0x10; // latency_timer - s->dev.config[PCI_HEADER_TYPE] = + uint8_t *pci_conf; + + pci_conf = pci_dev->config; + pci_conf[0x04] = 0x06; // command = bus master, pci mem + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + pci_conf[0x07] = 0x00; // status = fast devsel + pci_conf[0x08] = 0x00; // revision + pci_conf[0x09] = 0x00; // programming i/f + pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_PCI); + pci_conf[0x0D] = 0x10; // latency_timer + pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type - s->dev.config[0x1E] = 0xa0; // secondary status + pci_conf[0x18] = pci_get_parent_bus(pci_dev)->bus_num;// primary bus number + /* secondary bus and subordinate bus will be set by the caller */ + pci_conf[0x1E] = 0xa0; // secondary status + + /* vid/did will be set later */ + + return 0; +} + +#define PCI_BRIDGE_DEFAULT "default PCI to PCI bridge" +static PCIDeviceInfo pci_bridge_info_default = { + .qdev.name = PCI_BRIDGE_DEFAULT, + .qdev.size = sizeof(PCIBridge), + .config_write = pci_bridge_write_config, + .init = pci_bridge_initfn, + .pcie = 0, +}; - return pci_register_secondary_bus(&s->dev, map_irq, name); +static void pci_bridge_register_device(void) +{ + pci_qdev_register(&pci_bridge_info_default); +} +device_init(pci_bridge_register_device); + +PCIBus *pci_bridge_create_simple(PCIBus *bus, int devfn, uint16_t vid, + uint16_t did, int sec_bus, int sub_bus, + pci_map_irq_fn map_irq, const char *bus_name, + const char *name) +{ + DeviceState *qdev; + uint8_t* pci_conf; + PCIDevice *d; + + qdev = qdev_create(&bus->qbus, name); + + qdev_prop_set_uint32(qdev, "addr", devfn); + + qdev_init(qdev); + + d = qdev_to_pcidev(qdev); + pci_conf = d->config; + pci_config_set_vendor_id(pci_conf, vid); + pci_config_set_device_id(pci_conf, did); + + assert(sec_bus <= sub_bus); + pci_config_set_byte(d, PCI_SECONDARY_BUS, sec_bus); + pci_config_set_byte(d, PCI_SUBORDINATE_BUS, sub_bus); + + return pci_register_secondary_bus(d, map_irq, bus_name, 0); +} + +PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, + uint16_t did, + pci_map_irq_fn map_irq, const char *name) +{ + return pci_bridge_create_simple(bus, devfn, vid, did, 0, 0, + map_irq, name, PCI_BRIDGE_DEFAULT); } static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) diff --git a/hw/pci.h b/hw/pci.h index b279f2d..017ca07 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -172,6 +172,8 @@ static inline int pci_bar_is_64bit(const PCIIORegion *r) /* Header type 1 (PCI-to-PCI bridges) */ #define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ +#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ + /* Size of the standard PCI config header */ #define PCI_CONFIG_HEADER_SIZE 0x40 @@ -285,6 +287,8 @@ int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int devfn_min, int nirq); +PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq, + const char* name, int devfn_min); PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); @@ -307,6 +311,15 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, void pci_info(Monitor *mon); PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did, pci_map_irq_fn map_irq, const char *name); +PCIBus *pci_bridge_create_simple(PCIBus *bus, int devfn, uint16_t vid, + uint16_t did, int sec_bus, int sub_bus, + pci_map_irq_fn map_irq, const char *bus_name, + const char *name); +void pci_bridge_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +int pci_bridge_initfn(PCIDevice *pci_dev); +void pci_bridge_set_map_irq(PCIBus *bus, pci_map_irq_fn map_irq); + static inline void pci_set_byte(uint8_t *config, uint8_t val)