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_host.h"
#include "pci_bridge.h"
#include "pci_internals.h"
#include "rwhandler.h"
#include "apb_pci.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:
@ -313,6 +322,7 @@ static void apb_pci_bridge_init(PCIBus *b)
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
pci_set_byte(dev->config + PCI_REVISION_ID, 0x11);
return 0;
}
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;
APBState *d;
unsigned int i;
PCIDevice *pci_dev;
PCIBridge *br;
/* Ultrasparc PBM main bus */
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");
/* APB secondary busses */
*bus2 = pci_bridge_init(d->bus, PCI_DEVFN(1, 0), true,
PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 1");
apb_pci_bridge_init(*bus2);
pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
"pbm-bridge");
br = DO_UPCAST(PCIBridge, dev, pci_dev);
pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
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_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_SIMBA,
pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 2");
apb_pci_bridge_init(*bus3);
pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
"pbm-bridge");
br = DO_UPCAST(PCIBridge, dev, pci_dev);
pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
pci_apb_map_irq);
qdev_init_nofail(&pci_dev->qdev);
*bus3 = pci_bridge_get_sec_bus(br);
return d->bus;
}
@ -441,10 +457,23 @@ static SysBusDeviceInfo pbm_host_info = {
.qdev.reset = pci_pbm_reset,
.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)
{
sysbus_register_withprop(&pbm_host_info);
pci_qdev_register(&pbm_pci_host_info);
pci_qdev_register(&pbm_pci_bridge_info);
}
device_init(pbm_register_devices)

View File

@ -28,6 +28,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pci_bridge.h"
#include "pci_internals.h"
/* debug DEC */
//#define DEBUG_DEC
@ -49,18 +50,43 @@ static int dec_map_irq(PCIDevice *pci_dev, int 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)
{
DeviceState *dev;
PCIBus *ret;
PCIDevice *dev;
PCIBridge *br;
dev = qdev_create(NULL, "dec-21154");
qdev_init_nofail(dev);
ret = pci_bridge_init(parent_bus, devfn, false,
PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21154,
dec_map_irq, "DEC 21154 PCI-PCI bridge");
return ret;
dev = pci_create_multifunction(parent_bus, devfn, false,
"dec-21154-p2p-bridge");
br = DO_UPCAST(PCIBridge, dev, dev);
pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
qdev_init_nofail(&dev->qdev);
return pci_bridge_get_sec_bus(br);
}
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),
pci_dec_21154_init_device);
pci_qdev_register(&dec_21154_pci_host_info);
pci_qdev_register(&dec_21154_pci_bridge_info);
}
device_init(dec_register_devices)

View File

@ -32,12 +32,19 @@
#include "pci_bridge.h"
#include "pci_internals.h"
/* Accessor function to get parent bridge device from pci bus. */
PCIDevice *pci_bridge_get_device(PCIBus *bus)
{
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 val;
@ -49,13 +56,13 @@ static uint32_t pci_config_get_io_base(PCIDevice *d,
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)
<< 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)
{
pcibus_t tmp;
@ -69,7 +76,8 @@ static pcibus_t pci_config_get_pref_base(PCIDevice *d,
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;
if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@ -87,7 +95,8 @@ pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
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;
if (type & PCI_BASE_ADDRESS_SPACE_IO) {
@ -106,7 +115,8 @@ pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
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)
{
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);
pci_config_set_device_id(s->dev.config, s->did);
conf[PCI_PRIMARY_BUS] = 0;
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_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
@ -137,58 +176,35 @@ static int pci_bridge_initfn(PCIDevice *dev)
PCI_HEADER_TYPE_BRIDGE;
pci_set_word(dev->config + PCI_SEC_STATUS,
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;
}
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);
assert(QLIST_EMPTY(&s->sec_bus.child));
QLIST_REMOVE(&s->sec_bus, sibling);
/* qbus_free() is called automatically by qdev_free() */
return 0;
}
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, bool multifunction,
uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name)
/*
* 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)
{
PCIDevice *dev;
PCIBridge *s;
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;
br->map_irq = map_irq;
br->bus_name = bus_name;
}
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"
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_limit(PCIDevice *bridge, uint8_t type);
pcibus_t pci_bridge_get_base(const 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,
uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name);
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);
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 */
/*

View File

@ -5,6 +5,11 @@
* This header files is private to pci.c and pci_bridge.c
* So following structures are opaque to others and shouldn't be
* 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;
@ -30,11 +35,13 @@ struct PCIBus {
int *irq_count;
};
typedef struct {
struct PCIBridge {
PCIDevice dev;
/* private member */
PCIBus sec_bus;
uint32_t vid;
uint32_t did;
} PCIBridge;
pci_map_irq_fn map_irq;
const char *bus_name;
};
#endif /* QEMU_PCI_INTERNALS_H */

View File

@ -219,6 +219,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;