pci_bridge: introduce pci bridge library.

introduce pci bridge library.
convert apb bridge and dec p2p bridge to use new pci bridge library.
save/restore is supported as a side effect.
This is also preparation for pci express root/upstream/downstream port.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Isaku Yamahata 2010-07-13 13:01:42 +09:00 committed by Michael S. Tsirkin
parent 51a92333f8
commit 68f799944b
6 changed files with 177 additions and 83 deletions

View File

@ -30,6 +30,7 @@
#include "pci.h" #include "pci.h"
#include "pci_host.h" #include "pci_host.h"
#include "pci_bridge.h" #include "pci_bridge.h"
#include "pci_internals.h"
#include "rwhandler.h" #include "rwhandler.h"
#include "apb_pci.h" #include "apb_pci.h"
#include "sysemu.h" #include "sysemu.h"
@ -294,9 +295,17 @@ 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_initfn(PCIDevice *dev)
{ {
PCIDevice *dev = pci_bridge_get_device(b); int rc;
rc = pci_bridge_initfn(dev);
if (rc < 0) {
return rc;
}
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: * command register:
@ -313,6 +322,7 @@ static void apb_pci_bridge_init(PCIBus *b)
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM); PCI_STATUS_DEVSEL_MEDIUM);
pci_set_byte(dev->config + PCI_REVISION_ID, 0x11); pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
return 0;
} }
PCIBus *pci_apb_init(target_phys_addr_t special_base, PCIBus *pci_apb_init(target_phys_addr_t special_base,
@ -323,6 +333,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
SysBusDevice *s; SysBusDevice *s;
APBState *d; APBState *d;
unsigned int i; unsigned int i;
PCIDevice *pci_dev;
PCIBridge *br;
/* Ultrasparc PBM main bus */ /* Ultrasparc PBM main bus */
dev = qdev_create(NULL, "pbm"); dev = qdev_create(NULL, "pbm");
@ -348,17 +360,21 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
pci_create_simple(d->bus, 0, "pbm"); pci_create_simple(d->bus, 0, "pbm");
/* APB secondary busses */ /* APB secondary busses */
*bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0), true, pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, "pbm-bridge");
pci_apb_map_irq, br = DO_UPCAST(PCIBridge, dev, pci_dev);
"Advanced PCI Bus secondary bridge 1"); pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
apb_pci_bridge_init(*bus2); pci_apb_map_irq);
qdev_init_nofail(&pci_dev->qdev);
*bus2 = pci_bridge_get_sec_bus(br);
*bus3 = pci_bridge_init(d->bus, PCI_DEVFN(1, 1), true, pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA, "pbm-bridge");
pci_apb_map_irq, br = DO_UPCAST(PCIBridge, dev, pci_dev);
"Advanced PCI Bus secondary bridge 2"); pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
apb_pci_bridge_init(*bus3); pci_apb_map_irq);
qdev_init_nofail(&pci_dev->qdev);
*bus3 = pci_bridge_get_sec_bus(br);
return d->bus; return d->bus;
} }
@ -441,10 +457,23 @@ static SysBusDeviceInfo pbm_host_info = {
.qdev.reset = pci_pbm_reset, .qdev.reset = pci_pbm_reset,
.init = pci_pbm_init_device, .init = pci_pbm_init_device,
}; };
static PCIDeviceInfo pbm_pci_bridge_info = {
.qdev.name = "pbm-bridge",
.qdev.size = sizeof(PCIBridge),
.qdev.vmsd = &vmstate_pci_device,
.qdev.reset = pci_bridge_reset,
.init = apb_pci_bridge_initfn,
.exit = pci_bridge_exitfn,
.config_write = pci_bridge_write_config,
.is_bridge = 1,
};
static void pbm_register_devices(void) static void pbm_register_devices(void)
{ {
sysbus_register_withprop(&pbm_host_info); sysbus_register_withprop(&pbm_host_info);
pci_qdev_register(&pbm_pci_host_info); pci_qdev_register(&pbm_pci_host_info);
pci_qdev_register(&pbm_pci_bridge_info);
} }
device_init(pbm_register_devices) device_init(pbm_register_devices)

View File

@ -28,6 +28,7 @@
#include "pci.h" #include "pci.h"
#include "pci_host.h" #include "pci_host.h"
#include "pci_bridge.h" #include "pci_bridge.h"
#include "pci_internals.h"
/* debug DEC */ /* debug DEC */
//#define DEBUG_DEC //#define DEBUG_DEC
@ -49,18 +50,43 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num; return irq_num;
} }
static int dec_21154_initfn(PCIDevice *dev)
{
int rc;
rc = pci_bridge_initfn(dev);
if (rc < 0) {
return rc;
}
pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_DEC);
pci_config_set_device_id(dev->config, PCI_DEVICE_ID_DEC_21154);
return 0;
}
static PCIDeviceInfo dec_21154_pci_bridge_info = {
.qdev.name = "dec-21154-p2p-bridge",
.qdev.desc = "DEC 21154 PCI-PCI bridge",
.qdev.size = sizeof(PCIBridge),
.qdev.vmsd = &vmstate_pci_device,
.qdev.reset = pci_bridge_reset,
.init = dec_21154_initfn,
.exit = pci_bridge_exitfn,
.config_write = pci_bridge_write_config,
.is_bridge = 1,
};
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
{ {
DeviceState *dev; PCIDevice *dev;
PCIBus *ret; PCIBridge *br;
dev = qdev_create(NULL, "dec-21154"); dev = pci_create_multifunction(parent_bus, devfn, false,
qdev_init_nofail(dev); "dec-21154-p2p-bridge");
ret = pci_bridge_init(parent_bus, devfn, false, br = DO_UPCAST(PCIBridge, dev, dev);
PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154, pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
dec_map_irq, "DEC 21154 PCI-PCI bridge"); qdev_init_nofail(&dev->qdev);
return pci_bridge_get_sec_bus(br);
return ret;
} }
static int pci_dec_21154_init_device(SysBusDevice *dev) static int pci_dec_21154_init_device(SysBusDevice *dev)
@ -99,6 +125,7 @@ static void dec_register_devices(void)
sysbus_register_dev("dec-21154", sizeof(DECState), sysbus_register_dev("dec-21154", sizeof(DECState),
pci_dec_21154_init_device); pci_dec_21154_init_device);
pci_qdev_register(&dec_21154_pci_host_info); pci_qdev_register(&dec_21154_pci_host_info);
pci_qdev_register(&dec_21154_pci_bridge_info);
} }
device_init(dec_register_devices) device_init(dec_register_devices)

View File

@ -32,12 +32,19 @@
#include "pci_bridge.h" #include "pci_bridge.h"
#include "pci_internals.h" #include "pci_internals.h"
/* Accessor function to get parent bridge device from pci bus. */
PCIDevice *pci_bridge_get_device(PCIBus *bus) PCIDevice *pci_bridge_get_device(PCIBus *bus)
{ {
return bus->parent_dev; return bus->parent_dev;
} }
static uint32_t pci_config_get_io_base(PCIDevice *d, /* Accessor function to get secondary bus from pci-to-pci bridge device */
PCIBus *pci_bridge_get_sec_bus(PCIBridge *br)
{
return &br->sec_bus;
}
static uint32_t pci_config_get_io_base(const PCIDevice *d,
uint32_t base, uint32_t base_upper16) uint32_t base, uint32_t base_upper16)
{ {
uint32_t val; uint32_t val;
@ -49,13 +56,13 @@ static uint32_t pci_config_get_io_base(PCIDevice *d,
return val; return val;
} }
static pcibus_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) static pcibus_t pci_config_get_memory_base(const PCIDevice *d, uint32_t base)
{ {
return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) return ((pcibus_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
<< 16; << 16;
} }
static pcibus_t pci_config_get_pref_base(PCIDevice *d, static pcibus_t pci_config_get_pref_base(const PCIDevice *d,
uint32_t base, uint32_t upper) uint32_t base, uint32_t upper)
{ {
pcibus_t tmp; pcibus_t tmp;
@ -69,7 +76,8 @@ static pcibus_t pci_config_get_pref_base(PCIDevice *d,
return val; return val;
} }
pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type) /* accessor function to get bridge filtering base address */
pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type)
{ {
pcibus_t base; pcibus_t base;
if (type & PCI_BASE_ADDRESS_SPACE_IO) { if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@ -87,7 +95,8 @@ pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
return base; return base;
} }
pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type) /* accessor funciton to get bridge filtering limit */
pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
{ {
pcibus_t limit; pcibus_t limit;
if (type & PCI_BASE_ADDRESS_SPACE_IO) { if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@ -106,7 +115,8 @@ pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
return limit; return limit;
} }
static void pci_bridge_write_config(PCIDevice *d, /* default write_config function for PCI-to-PCI bridge */
void pci_bridge_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len) uint32_t address, uint32_t val, int len)
{ {
pci_default_write_config(d, address, val, len); pci_default_write_config(d, address, val, len);
@ -122,12 +132,41 @@ static void pci_bridge_write_config(PCIDevice *d,
} }
} }
static int pci_bridge_initfn(PCIDevice *dev) /* reset bridge specific configuration registers */
void pci_bridge_reset_reg(PCIDevice *dev)
{ {
PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev); uint8_t *conf = dev->config;
pci_config_set_vendor_id(s->dev.config, s->vid); conf[PCI_PRIMARY_BUS] = 0;
pci_config_set_device_id(s->dev.config, s->did); conf[PCI_SECONDARY_BUS] = 0;
conf[PCI_SUBORDINATE_BUS] = 0;
conf[PCI_SEC_LATENCY_TIMER] = 0;
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);
}
/* default reset function for PCI-to-PCI bridge */
void pci_bridge_reset(DeviceState *qdev)
{
PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
pci_bridge_reset_reg(dev);
}
/* default qdev initialization function for PCI-to-PCI bridge */
int pci_bridge_initfn(PCIDevice *dev)
{
PCIBus *parent = dev->bus;
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
PCIBus *sec_bus = &br->sec_bus;
pci_set_word(dev->config + PCI_STATUS, pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
@ -137,58 +176,35 @@ static int pci_bridge_initfn(PCIDevice *dev)
PCI_HEADER_TYPE_BRIDGE; PCI_HEADER_TYPE_BRIDGE;
pci_set_word(dev->config + PCI_SEC_STATUS, pci_set_word(dev->config + PCI_SEC_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
br->bus_name);
sec_bus->parent_dev = dev;
sec_bus->map_irq = br->map_irq;
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
return 0; return 0;
} }
static int pci_bridge_exitfn(PCIDevice *pci_dev) /* default qdev clean up function for PCI-to-PCI bridge */
int pci_bridge_exitfn(PCIDevice *pci_dev)
{ {
PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
assert(QLIST_EMPTY(&s->sec_bus.child)); assert(QLIST_EMPTY(&s->sec_bus.child));
QLIST_REMOVE(&s->sec_bus, sibling); QLIST_REMOVE(&s->sec_bus, sibling);
/* qbus_free() is called automatically by qdev_free() */
return 0; return 0;
} }
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction, /*
uint16_t vid, uint16_t did, * before qdev initialization(qdev_init()), this function sets bus_name and
pci_map_irq_fn map_irq, const char *name) * map_irq callback which are necessry for pci_bridge_initfn() to
* initialize bus.
*/
void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
pci_map_irq_fn map_irq)
{ {
PCIDevice *dev; br->map_irq = map_irq;
PCIBridge *s; br->bus_name = bus_name;
PCIBus *sec_bus;
dev = pci_create_multifunction(bus, devfn, multifunction, "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);
sec_bus = &s->sec_bus;
qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev, name);
sec_bus->parent_dev = dev;
sec_bus->map_irq = map_irq;
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&bus->child, sec_bus, sibling);
return &s->sec_bus;
} }
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,
.is_bridge = 1,
.qdev.props = (Property[]) {
DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
DEFINE_PROP_END_OF_LIST(),
}
};
static void pci_register_devices(void)
{
pci_qdev_register(&bridge_info);
}
device_init(pci_register_devices)

View File

@ -29,13 +29,27 @@
#include "pci.h" #include "pci.h"
PCIDevice *pci_bridge_get_device(PCIBus *bus); PCIDevice *pci_bridge_get_device(PCIBus *bus);
PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type); pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type); pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction, void pci_bridge_write_config(PCIDevice *d,
uint16_t vid, uint16_t did, uint32_t address, uint32_t val, int len);
pci_map_irq_fn map_irq, const char *name); void pci_bridge_reset_reg(PCIDevice *dev);
void pci_bridge_reset(DeviceState *qdev);
int pci_bridge_initfn(PCIDevice *pci_dev);
int pci_bridge_exitfn(PCIDevice *pci_dev);
/*
* before qdev initialization(qdev_init()), this function sets bus_name and
* map_irq callback which are necessry for pci_bridge_initfn() to
* initialize bus.
*/
void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
pci_map_irq_fn map_irq);
#endif /* QEMU_PCI_BRIDGE_H */ #endif /* QEMU_PCI_BRIDGE_H */
/* /*

View File

@ -5,6 +5,11 @@
* This header files is private to pci.c and pci_bridge.c * This header files is private to pci.c and pci_bridge.c
* So following structures are opaque to others and shouldn't be * So following structures are opaque to others and shouldn't be
* accessed. * accessed.
*
* For pci-to-pci bridge needs to include this header file to embed
* PCIBridge in its structure or to get sizeof(PCIBridge),
* However, they shouldn't access those following members directly.
* Use accessor function in pci.h, pci_bridge.h
*/ */
extern struct BusInfo pci_bus_info; extern struct BusInfo pci_bus_info;
@ -30,11 +35,13 @@ struct PCIBus {
int *irq_count; int *irq_count;
}; };
typedef struct { struct PCIBridge {
PCIDevice dev; PCIDevice dev;
/* private member */
PCIBus sec_bus; PCIBus sec_bus;
uint32_t vid; pci_map_irq_fn map_irq;
uint32_t did; const char *bus_name;
} PCIBridge; };
#endif /* QEMU_PCI_INTERNALS_H */ #endif /* QEMU_PCI_INTERNALS_H */

View File

@ -219,6 +219,7 @@ typedef struct PCIHostState PCIHostState;
typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIExpressHost PCIExpressHost;
typedef struct PCIBus PCIBus; typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice; typedef struct PCIDevice PCIDevice;
typedef struct PCIBridge PCIBridge;
typedef struct SerialState SerialState; typedef struct SerialState SerialState;
typedef struct IRQState *qemu_irq; typedef struct IRQState *qemu_irq;
typedef struct PCMCIACardState PCMCIACardState; typedef struct PCMCIACardState PCMCIACardState;