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:
parent
51a92333f8
commit
68f799944b
53
hw/apb_pci.c
53
hw/apb_pci.c
@ -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)
|
||||
|
45
hw/dec_pci.c
45
hw/dec_pci.c
@ -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)
|
||||
|
122
hw/pci_bridge.c
122
hw/pci_bridge.c
@ -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)
|
||||
|
@ -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 */
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user