[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 04/10] pci_bridge: introduce pci bridge layer.
From: |
Michael S. Tsirkin |
Subject: |
[Qemu-devel] Re: [PATCH 04/10] pci_bridge: introduce pci bridge layer. |
Date: |
Thu, 17 Jun 2010 12:52:46 +0300 |
User-agent: |
Mutt/1.5.19 (2009-01-05) |
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 <address@hidden>
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
- [Qemu-devel] [PATCH 00/10] pci: pci to pci bridge clean up and enhancement, Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 07/10] pci: fix pci domain registering., Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 05/10] pci bridge: add helper function for ssvid capability., Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 08/10] pci: remove PCIDeviceInfo::header_type, Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 04/10] pci_bridge: introduce pci bridge layer., Isaku Yamahata, 2010/06/17
- [Qemu-devel] Re: [PATCH 04/10] pci_bridge: introduce pci bridge layer.,
Michael S. Tsirkin <=
- [Qemu-devel] [PATCH 03/10] pci: fix pci_bus_reset() with 64bit BAR and several clean ups., Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 01/10] pci_bridge: split out pci bridge code into pci_bridge.c from pci.c, Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 02/10] qdev: export qdev_reset() for later use., Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 06/10] pci: eliminate work around in pci_device_reset()., Isaku Yamahata, 2010/06/17
- [Qemu-devel] [PATCH 09/10] pci: set PCI multi-function bit appropriately., Isaku Yamahata, 2010/06/17