Skip to content

Commit

Permalink
pci_bridge: introduce pci bridge library.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Isaku Yamahata authored and mstsirkin committed Sep 7, 2010
1 parent 51a9233 commit 68f7999
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 84 deletions.
55 changes: 42 additions & 13 deletions hw/apb_pci.c
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand All @@ -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,
Expand All @@ -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");
Expand All @@ -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);

*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, 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);

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;
}
Expand Down Expand Up @@ -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 changes: 36 additions & 9 deletions hw/dec_pci.c
Expand Up @@ -28,6 +28,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pci_bridge.h"
#include "pci_internals.h"

/* debug DEC */
//#define DEBUG_DEC
Expand All @@ -49,18 +50,43 @@ 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(PCIDevice *dev)
{
DeviceState *dev;
PCIBus *ret;
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;
}

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");
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)
{
PCIDevice *dev;
PCIBridge *br;

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)
Expand Down Expand Up @@ -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 changes: 69 additions & 53 deletions hw/pci_bridge.c
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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)
{
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;

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)
{
PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
pci_bridge_reset_reg(dev);
}

pci_config_set_vendor_id(s->dev.config, s->vid);
pci_config_set_device_id(s->dev.config, s->did);
/* 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);
Expand All @@ -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)
{
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;
}

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)
/*
* 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)
{
pci_qdev_register(&bridge_info);
br->map_irq = map_irq;
br->bus_name = bus_name;
}

device_init(pci_register_devices)
24 changes: 19 additions & 5 deletions hw/pci_bridge.h
Expand Up @@ -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 */
/*
Expand Down

0 comments on commit 68f7999

Please sign in to comment.