From: "Michael S. Tsirkin" <mst@redhat.com>
To: Isaku Yamahata <yamahata@valinux.co.jp>
Cc: stefano.stabellini@eu.citrix.com, jan.kiszka@siemens.com,
allen.m.kay@intel.com, qemu-devel@nongnu.org,
blauwirbel@gmail.com, kraxel@redhat.com, jean.guyader@gmail.com
Subject: [Qemu-devel] Re: [PATCH 04/10] pci_bridge: introduce pci bridge layer.
Date: Thu, 17 Jun 2010 12:52:46 +0300 [thread overview]
Message-ID: <20100617095246.GD7912@redhat.com> (raw)
In-Reply-To: <c5935a9c12aa282e39bb5960a5db3a8e5d95e446.1276755023.git.yamahata@valinux.co.jp>
On Thu, Jun 17, 2010 at 03:15:46PM +0900, Isaku Yamahata wrote:
> introduce pci bridge layer.
> export pci_bridge_write_config() for generic use.
> support device reset and bus reset of bridge control.
> convert apb bridge and dec p2p bridge to use new pci bridge layer.
> save/restore is supported as a side effect.
>
> This might be a bit over engineering, but this is also preparation
> for pci express root/upstream/downstream port.
>
> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Well, preparations are easier to judge with patches that use them.
> ---
> hw/apb_pci.c | 38 +++++++++-----
> hw/dec_pci.c | 28 +++++++---
> hw/pci_bridge.c | 146 +++++++++++++++++++++++++++++++++++++------------------
> hw/pci_bridge.h | 35 ++++++++++++-
> qemu-common.h | 1 +
> 5 files changed, 177 insertions(+), 71 deletions(-)
>
> diff --git a/hw/apb_pci.c b/hw/apb_pci.c
> index c11d9b5..cb9051b 100644
> --- a/hw/apb_pci.c
> +++ b/hw/apb_pci.c
> @@ -31,6 +31,7 @@
> #include "pci_host.h"
> #include "pci_bridge.h"
> #include "rwhandler.h"
> +#include "pci_bridge.h"
> #include "apb_pci.h"
> #include "sysemu.h"
>
> @@ -294,9 +295,12 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
> }
> }
>
> -static void apb_pci_bridge_init(PCIBus *b)
> +static int apb_pci_bridge_init(PCIBridge *br)
> {
> - PCIDevice *dev = pci_bridge_get_device(b);
> + PCIDevice *dev = &br->dev;
> +
> + pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_SUN);
> + pci_config_set_device_id(dev->config, PCI_DEVICE_ID_SUN_SIMBA);
>
> /*
> * command register:
> @@ -316,6 +320,8 @@ static void apb_pci_bridge_init(PCIBus *b)
> pci_set_byte(dev->config + PCI_HEADER_TYPE,
> pci_get_byte(dev->config + PCI_HEADER_TYPE) |
> PCI_HEADER_TYPE_MULTI_FUNCTION);
> +
> + return 0;
> }
>
> PCIBus *pci_apb_init(target_phys_addr_t special_base,
> @@ -326,6 +332,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
> SysBusDevice *s;
> APBState *d;
> unsigned int i;
> + PCIBridge *br;
>
> /* Ultrasparc PBM main bus */
> dev = qdev_create(NULL, "pbm");
> @@ -351,17 +358,13 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
> pci_create_simple(d->bus, 0, "pbm");
>
> /* APB secondary busses */
> - *bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0),
> - PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
> - pci_apb_map_irq,
> - "Advanced PCI Bus secondary bridge 1");
> - apb_pci_bridge_init(*bus2);
> -
> - *bus3 = pci_bridge_init(d->bus, PCI_DEVFN(1, 1),
> - PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
> - pci_apb_map_irq,
> - "Advanced PCI Bus secondary bridge 2");
> - apb_pci_bridge_init(*bus3);
> + br = pci_bridge_create_simple(d->bus, PCI_DEVFN(1, 0), "pbm-bridge",
> + "Advanced PCI Bus secondary bridge 1");
> + *bus2 = pci_bridge_get_sec_bus(br);
> +
> + br = pci_bridge_create_simple(d->bus, PCI_DEVFN(1, 1), "pbm-bridge",
> + "Advanced PCI Bus secondary bridge 2");
> + *bus3 = pci_bridge_get_sec_bus(br);
>
> return d->bus;
> }
> @@ -446,10 +449,19 @@ static SysBusDeviceInfo pbm_host_info = {
> .qdev.reset = pci_pbm_reset,
> .init = pci_pbm_init_device,
> };
> +
> +static PCIBridgeInfo pbm_pci_bridge_info = {
> + .pci.qdev.name = "pbm-bridge",
> + .pci.qdev.vmsd = &vmstate_pci_device,
> + .init = apb_pci_bridge_init,
> + .map_irq = pci_apb_map_irq,
> +};
> +
> static void pbm_register_devices(void)
> {
> sysbus_register_withprop(&pbm_host_info);
> pci_qdev_register(&pbm_pci_host_info);
> + pci_bridge_qdev_register(&pbm_pci_bridge_info);
> }
>
> device_init(pbm_register_devices)
> diff --git a/hw/dec_pci.c b/hw/dec_pci.c
> index b2759dd..45b5c28 100644
> --- a/hw/dec_pci.c
> +++ b/hw/dec_pci.c
> @@ -49,18 +49,27 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
> return irq_num;
> }
>
> -PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
> +static int dec_21154_initfn(PCIBridge *br)
> {
> - DeviceState *dev;
> - PCIBus *ret;
> + pci_config_set_vendor_id(br->dev.config, PCI_VENDOR_ID_DEC);
> + pci_config_set_device_id(br->dev.config, PCI_DEVICE_ID_DEC_21154);
> + return 0;
> +}
>
> - dev = qdev_create(NULL, "dec-21154");
> - qdev_init_nofail(dev);
> - ret = pci_bridge_init(parent_bus, devfn,
> - PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154,
> - dec_map_irq, "DEC 21154 PCI-PCI bridge");
> +static PCIBridgeInfo dec_21154_pci_bridge_info = {
> + .pci.qdev.name = "dec-21154-p2p-bridge",
> + .pci.qdev.desc = "DEC 21154 PCI-PCI bridge",
> + .pci.qdev.vmsd = &vmstate_pci_device,
> + .init = dec_21154_initfn,
> + .map_irq = dec_map_irq,
> +};
>
> - return ret;
> +PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
> +{
> + PCIBridge *br;
> + br = pci_bridge_create_simple(parent_bus, devfn, "dec-21154-p2p-bridge",
> + "DEC 21154 PCI-PCI bridge");
> + return pci_bridge_get_sec_bus(br);
> }
>
> static int pci_dec_21154_init_device(SysBusDevice *dev)
> @@ -99,6 +108,7 @@ static void dec_register_devices(void)
> sysbus_register_dev("dec-21154", sizeof(DECState),
> pci_dec_21154_init_device);
> pci_qdev_register(&dec_21154_pci_host_info);
> + pci_bridge_qdev_register(&dec_21154_pci_bridge_info);
> }
>
> device_init(dec_register_devices)
Please document the APIs. For example, what is
pci_bridge_create_simple and how does it differ
from pci_bridge_create?
> diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
> index bf746f1..43c21d4 100644
> --- a/hw/pci_bridge.c
> +++ b/hw/pci_bridge.c
> @@ -29,16 +29,10 @@
>
> #include "pci_bridge.h"
>
> -typedef struct {
> - PCIDevice dev;
> - PCIBus *bus;
> - uint32_t vid;
> - uint32_t did;
> -} PCIBridge;
> -
> -static void pci_bridge_write_config(PCIDevice *d,
> - uint32_t address, uint32_t val, int len)
> +void pci_bridge_write_config(PCIDevice *d,
> + uint32_t address, uint32_t val, int len)
> {
> + uint16_t bridge_control = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> pci_default_write_config(d, address, val, len);
>
> if (/* io base/limit */
> @@ -49,64 +43,122 @@ static void pci_bridge_write_config(PCIDevice *d,
> ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
> pci_bridge_update_mappings(d->bus);
> }
> +
> + if (ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) {
> + uint16_t new = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
> + if (!(bridge_control & PCI_BRIDGE_CTL_BUS_RESET) &&
> + (new & PCI_BRIDGE_CTL_BUS_RESET)) {
> + /* 0 -> 1 */
> + PCIBridge *br = DO_UPCAST(PCIBridge, dev, d);
> + pci_bus_reset(br->bus);
> + }
> + }
> }
>
> -static int pci_bridge_initfn(PCIDevice *dev)
> +void pci_bridge_reset_reg(PCIDevice *dev)
> {
> - PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
> + uint8_t *conf = dev->config;
> +
> + conf[PCI_PRIMARY_BUS] = 0;
> + conf[PCI_SECONDARY_BUS] = 0;
> + conf[PCI_SUBORDINATE_BUS] = 0;
> + conf[PCI_SEC_LATENCY_TIMER] = 0;
>
> - pci_config_set_vendor_id(s->dev.config, s->vid);
> - pci_config_set_device_id(s->dev.config, s->did);
> + conf[PCI_IO_BASE] = 0;
> + conf[PCI_IO_LIMIT] = 0;
> + pci_set_word(conf + PCI_MEMORY_BASE, 0);
> + pci_set_word(conf + PCI_MEMORY_LIMIT, 0);
> + pci_set_word(conf + PCI_PREF_MEMORY_BASE, 0);
> + pci_set_word(conf + PCI_PREF_MEMORY_LIMIT, 0);
> + pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
> + pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
> +
> + pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
> +}
> +
> +void pci_bridge_reset(DeviceState *qdev)
> +{
> + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
> + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
> +
> + pci_bus_reset(br->bus);
> + pci_bridge_reset_reg(dev);
> + pci_device_reset_default(dev);
> +}
> +
> +static int pci_bridge_initfn(PCIDevice *dev)
> +{
> + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
> + PCIDeviceInfo *pci_info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
> + PCIBridgeInfo *info = DO_UPCAST(PCIBridgeInfo, pci, pci_info);
> + int rc = 0;
>
> pci_set_word(dev->config + PCI_STATUS,
> PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
> - dev->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE;
> pci_set_word(dev->config + PCI_SEC_STATUS,
> PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
> - return 0;
> +
> + br->bus = pci_register_secondary_bus(dev->bus, dev,
> + info->map_irq, br->bus_name);
> + if (!br->bus) {
> + return -1;
> + }
> + if (info->init) {
> + rc = info->init(br);
> + }
> + return rc;
> }
>
> -static int pci_bridge_exitfn(PCIDevice *pci_dev)
> +static int pci_bridge_exitfn(PCIDevice *dev)
> {
> - PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
> - pci_unregister_secondary_bus(s->bus);
> + PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
> + PCIDeviceInfo *pci_info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
> + PCIBridgeInfo *info = DO_UPCAST(PCIBridgeInfo, pci, pci_info);
> +
> + if (info->exit) {
> + int rc = info->exit(br);
> + if (rc){
> + return rc;
> + }
> + }
> + pci_unregister_secondary_bus(br->bus);
> return 0;
> }
>
> -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
> - pci_map_irq_fn map_irq, const char *name)
> +void pci_bridge_qdev_register(PCIBridgeInfo *info)
> {
> - PCIDevice *dev;
> - PCIBridge *s;
> -
> - dev = pci_create(bus, devfn, "pci-bridge");
> - qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
> - qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
> - qdev_init_nofail(&dev->qdev);
> -
> - s = DO_UPCAST(PCIBridge, dev, dev);
> - s->bus = pci_register_secondary_bus(bus, &s->dev, map_irq, name);
> - return s->bus;
> + if (!info->pci.qdev.size) {
> + info->pci.qdev.size = sizeof(PCIBridge);
> + }
> + info->pci.init = pci_bridge_initfn;
> + info->pci.exit = pci_bridge_exitfn;
> + info->pci.header_type = PCI_HEADER_TYPE_BRIDGE;
> + if (!info->pci.config_write) {
> + info->pci.config_write = pci_bridge_write_config;
> + }
> + if (!info->pci.qdev.reset) {
> + info->pci.qdev.reset = pci_bridge_reset;
> + }
> + pci_qdev_register(&info->pci);
> }
>
> -static PCIDeviceInfo bridge_info = {
> - .qdev.name = "pci-bridge",
> - .qdev.size = sizeof(PCIBridge),
> - .init = pci_bridge_initfn,
> - .exit = pci_bridge_exitfn,
> - .config_write = pci_bridge_write_config,
> - .header_type = PCI_HEADER_TYPE_BRIDGE,
> - .qdev.props = (Property[]) {
> - DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
> - DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
> - DEFINE_PROP_END_OF_LIST(),
> - }
> -};
> +PCIBridge *pci_bridge_create(PCIBus *bus, int devfn, const char *name)
> +{
> + PCIDevice *dev = pci_create(bus, devfn, name);
> + return DO_UPCAST(PCIBridge, dev, dev);
> +}
>
> -static void pci_register_devices(void)
> +void pci_bridge_set_bus_name(PCIBridge *br, const char *bus_name)
> {
> - pci_qdev_register(&bridge_info);
> + br->bus_name = bus_name;
> }
>
> -device_init(pci_register_devices)
> +PCIBridge *pci_bridge_create_simple(PCIBus *bus, int devfn,
> + const char *name, const char *bus_name)
> +{
> + PCIBridge *br = pci_bridge_create(bus, devfn, name);
> + pci_bridge_set_bus_name(br, bus_name);
> + qdev_init_nofail(&br->dev.qdev);
> + return br;
> +}
> diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
> index 1d46abf..2747e7f 100644
> --- a/hw/pci_bridge.h
> +++ b/hw/pci_bridge.h
> @@ -23,8 +23,39 @@
>
> #include "pci.h"
>
> -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
> - pci_map_irq_fn map_irq, const char *name);
> +struct PCIBridge {
> + PCIDevice dev;
> +
> + /* private member */
> + PCIBus *bus;
> + const char *bus_name;
> +};
> +
> +static inline PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
> +{
> + return br->bus;
> +}
> +
> +void pci_bridge_write_config(PCIDevice *d,
> + uint32_t address, uint32_t val, int len);
> +void pci_bridge_reset_reg(PCIDevice *dev);
> +void pci_bridge_reset(DeviceState *qdev);
> +
> +typedef int (*pci_bridge_qdev_initfn)(PCIBridge *br);
> +typedef int (*pci_bridge_qdev_exitfn)(PCIBridge *br);
> +typedef struct
struct PCIBridgeInfo, so we can later forward declare if we need to.
> +{
> + PCIDeviceInfo pci;
> + pci_bridge_qdev_initfn init;
> + pci_bridge_qdev_exitfn exit;
> + pci_map_irq_fn map_irq;
> +} PCIBridgeInfo;
> +
> +void pci_bridge_qdev_register(PCIBridgeInfo *info);
> +PCIBridge *pci_bridge_create(PCIBus *bus, int devfn, const char *name);
> +void pci_bridge_set_bus_name(PCIBridge *br, const char *bus_name);
> +PCIBridge *pci_bridge_create_simple(PCIBus *bus, int devfn,
> + const char *name, const char *bus_name);
>
> #endif /* QEMU_PCI_BRIDGE_H */
> /*
> diff --git a/qemu-common.h b/qemu-common.h
> index d133f35..8257311 100644
> --- a/qemu-common.h
> +++ b/qemu-common.h
> @@ -221,6 +221,7 @@ typedef struct PCIHostState PCIHostState;
> typedef struct PCIExpressHost PCIExpressHost;
> typedef struct PCIBus PCIBus;
> typedef struct PCIDevice PCIDevice;
> +typedef struct PCIBridge PCIBridge;
> typedef struct SerialState SerialState;
> typedef struct IRQState *qemu_irq;
> typedef struct PCMCIACardState PCMCIACardState;
> --
> 1.6.6.1
next prev parent reply other threads:[~2010-06-17 9:57 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-17 6:15 [Qemu-devel] [PATCH 00/10] pci: pci to pci bridge clean up and enhancement Isaku Yamahata
2010-06-17 6:15 ` [Qemu-devel] [PATCH 01/10] pci_bridge: split out pci bridge code into pci_bridge.c from pci.c Isaku Yamahata
2010-06-17 6:15 ` [Qemu-devel] [PATCH 02/10] qdev: export qdev_reset() for later use Isaku Yamahata
2010-06-17 7:01 ` Markus Armbruster
2010-06-17 10:05 ` [Qemu-devel] " Michael S. Tsirkin
2010-06-17 6:15 ` [Qemu-devel] [PATCH 03/10] pci: fix pci_bus_reset() with 64bit BAR and several clean ups Isaku Yamahata
2010-06-17 10:58 ` [Qemu-devel] " Michael S. Tsirkin
2010-06-17 6:15 ` [Qemu-devel] [PATCH 04/10] pci_bridge: introduce pci bridge layer Isaku Yamahata
2010-06-17 9:52 ` Michael S. Tsirkin [this message]
2010-06-17 6:15 ` [Qemu-devel] [PATCH 05/10] pci bridge: add helper function for ssvid capability Isaku Yamahata
2010-06-17 10:01 ` [Qemu-devel] " Michael S. Tsirkin
2010-06-17 6:15 ` [Qemu-devel] [PATCH 06/10] pci: eliminate work around in pci_device_reset() Isaku Yamahata
2010-06-17 6:15 ` [Qemu-devel] [PATCH 07/10] pci: fix pci domain registering Isaku Yamahata
2010-06-17 6:15 ` [Qemu-devel] [PATCH 08/10] pci: remove PCIDeviceInfo::header_type Isaku Yamahata
2010-06-17 6:15 ` [Qemu-devel] [PATCH 09/10] pci: set PCI multi-function bit appropriately Isaku Yamahata
2010-06-17 9:37 ` [Qemu-devel] " Michael S. Tsirkin
2010-06-18 2:40 ` Isaku Yamahata
2010-06-18 12:44 ` Michael S. Tsirkin
2010-06-18 13:38 ` Isaku Yamahata
2010-06-18 14:59 ` Michael S. Tsirkin
2010-06-18 15:22 ` Jamie Lokier
2010-06-20 10:03 ` Michael S. Tsirkin
2010-06-17 6:15 ` [Qemu-devel] [PATCH 10/10] pci: don't overwrite multi functio bit in pci header type Isaku Yamahata
2010-06-17 9:41 ` [Qemu-devel] " Michael S. Tsirkin
2010-06-17 10:02 ` [Qemu-devel] Re: [PATCH 00/10] pci: pci to pci bridge clean up and enhancement Michael S. Tsirkin
2010-06-17 11:57 ` Michael S. Tsirkin
2010-06-18 3:26 ` Isaku Yamahata
2010-06-18 12:46 ` Michael S. Tsirkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100617095246.GD7912@redhat.com \
--to=mst@redhat.com \
--cc=allen.m.kay@intel.com \
--cc=blauwirbel@gmail.com \
--cc=jan.kiszka@siemens.com \
--cc=jean.guyader@gmail.com \
--cc=kraxel@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefano.stabellini@eu.citrix.com \
--cc=yamahata@valinux.co.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.