[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 6/7] pci/brdige qdevfy.
From: |
Isaku Yamahata |
Subject: |
[Qemu-devel] [PATCH 6/7] pci/brdige qdevfy. |
Date: |
Tue, 2 Jun 2009 15:42:49 +0900 |
pci/brdige qdevfy.
Signed-off-by: Isaku Yamahata <address@hidden>
---
hw/apb_pci.c | 12 +++---
hw/pci.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++---------
hw/pci.h | 15 ++++++--
hw/pci_ids.h | 2 +
4 files changed, 109 insertions(+), 26 deletions(-)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index dac5cd3..e85e28c 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -266,11 +266,11 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
/* APB secondary busses */
- *bus2 = pci_bridge_init(s->bus, 8, PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 1");
- *bus3 = pci_bridge_init(s->bus, 9, PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 2");
+ *bus2 = pci_bridge_create_simple(s->bus, 8, PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
+ "Advanced PCI Bus secondary bridge 1");
+ *bus3 = pci_bridge_create_simple(s->bus, 9, PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
+ "Advanced PCI Bus secondary bridge 2");
return s->bus;
}
diff --git a/hw/pci.c b/hw/pci.c
index 602eeb0..0ffdfef 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -129,25 +129,29 @@ PCIBus *pci_register_bus(DeviceState *parent, const char
*name,
return bus;
}
-static PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn
map_irq)
+/* XXX qemu_irq, nirq */
+static PCIBus *pci_register_secondary_bus(PCIDevice *dev,
+ int bus_num, int devfn_min, int nirq)
{
PCIBus *bus;
PCIBus *parent_bus;
- int devfn_min = qdev_get_prop_int(&dev->qdev, "devfn_min", 0);
- int nirq = qdev_get_prop_int(&dev->qdev, "nirq", 0);
bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI,
sizeof(PCIBus) + (nirq * sizeof(int)),
&dev->qdev, "pci"));
- bus->map_irq = map_irq;
+ bus->bus_num = bus_num;
bus->devfn_min = devfn_min;
- bus->nirq = nirq;
parent_bus = pci_get_parent_bus(dev);
LIST_INSERT_AFTER(parent_bus, bus, next);
return bus;
}
+void pci_bridge_set_map_irq(PCIBus *bus, pci_map_irq_fn map_irq)
+{
+ bus->map_irq = map_irq;
+}
+
int pci_bus_num(PCIBus *s)
{
return s->bus_num;
@@ -1052,20 +1056,31 @@ static void pci_conf_init_type_01_default(struct
PCIConfigReg *config_regs)
pci_conf_initb(config_regs, addr, NULL, ~0);
}
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name)
+typedef struct {
+ DeviceInfo qdev;
+ pci_qdev_initfn init;
+} PCIBridgeInfo;
+
+static void pci_bridge_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
- PCIDevice *d;
- uint8_t *pci_conf;
+ PCIDevice *pci_dev = qdev_to_pcidev(qdev);
+ PCIBridgeInfo *info = container_of(base, PCIBridgeInfo, qdev);
- d = pci_register_device_confreg(bus, name, sizeof(PCIDevice),
- devfn, NULL, NULL,
- pci_conf_init_type_01_default);
+ int devfn = qdev_get_prop_int(qdev, "devfn", -1);
+ int sec_bus = qdev_get_prop_int(qdev, "sec_bus", 0);
+ int sub_bus = qdev_get_prop_int(qdev, "sub_bus", sec_bus);
+ int devfn_min = qdev_get_prop_int(qdev, "devfn_min", 0);
+ int nirq = qdev_get_prop_int(qdev, "nirq", 0);
+ char *pci_name = qdev_get_prop_ptr(qdev, "pci_name");
- pci_conf = d->config;
- pci_config_set_vendor_id(pci_conf, vid);
- pci_config_set_device_id(pci_conf, did);
+ uint8_t *pci_conf;
+
+ assert(sec_bus <= sub_bus);
+ pci_dev = do_pci_register_device(pci_dev, pci_get_parent_bus(pci_dev),
+ pci_name, devfn, NULL, NULL,
+ pci_conf_init_type_01_default);
+ pci_conf = pci_dev->config;
pci_conf[0x04] = 0x06; // command = bus master, pci mem
pci_conf[0x05] = 0x00;
pci_conf[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
@@ -1076,9 +1091,68 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t
vid, uint16_t did,
pci_conf[0x0D] = 0x10; // latency_timer
pci_conf[PCI_HEADER_TYPE] =
PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
+ pci_conf[0x18] = pci_get_parent_bus(pci_dev)->bus_num;// primary bus number
+ pci_conf[0x19] = sec_bus; // secondary bus number
+ pci_conf[0x1A] = sub_bus; // subordinate bus number
pci_conf[0x1E] = 0xa0; // secondary status
- return pci_register_secondary_bus(d, map_irq);
+ pci_register_secondary_bus(pci_dev, sec_bus, devfn_min, nirq);
+
+ /* vid/did, map_irq will be set */
+ info->init(pci_dev);
+}
+
+void pci_bridge_qdev_register(const char* name, int size, pci_qdev_initfn init)
+{
+ PCIBridgeInfo *info;
+
+ info = qemu_mallocz(sizeof(*info));
+ info->init = init;
+ info->qdev.init = pci_bridge_qdev_init;
+ info->qdev.bus_type = BUS_TYPE_PCI;
+
+ qdev_register(name, size, &info->qdev);
+}
+
+/* for compat */
+#define PCI_BRIDGE_DEFAULT "default PCI to PCI bridge"
+static void pci_bridge_default_qdev_init(PCIDevice *dev)
+{
+ /* nothing */
+}
+
+static void pci_brdige_register_device(void)
+{
+ pci_bridge_qdev_register(PCI_BRIDGE_DEFAULT,
+ sizeof(PCIDevice), pci_bridge_default_qdev_init);
+}
+device_init(pci_brdige_register_device);
+
+PCIBus *pci_bridge_create_simple(PCIBus *bus, int devfn, uint16_t vid,
+ uint16_t did, pci_map_irq_fn map_irq,
+ const char *pci_name)
+{
+ DeviceState *qdev;
+ uint8_t* pci_conf;
+ PCIDevice *d;
+ PCIBus *b;
+ char *pci_name_dup = qemu_strdup(pci_name); /* XXX:leak */
+
+ qdev = qdev_create(&bus->qbus, PCI_BRIDGE_DEFAULT);
+
+ qdev_set_prop_int(qdev, "devfn", devfn);
+ qdev_set_prop_ptr(qdev, "pci_name", pci_name_dup);
+
+ qdev_init(qdev);
+
+ d = qdev_to_pcidev(qdev);
+ pci_conf = d->config;
+ pci_config_set_vendor_id(pci_conf, vid);
+ pci_config_set_device_id(pci_conf, did);
+
+ b = pci_get_parent_bus(d);
+ pci_bridge_set_map_irq(b, map_irq);
+ return b;
}
typedef struct {
diff --git a/hw/pci.h b/hw/pci.h
index c649442..76f3f28 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -306,15 +306,13 @@ int pci_bus_num(PCIBus *s);
void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d));
PCIBus *pci_find_bus(int bus_num);
PCIDevice *pci_find_device(int bus_num, int slot, int function);
+PCIBus *pci_get_parent_bus(PCIDevice *dev);
+PCIDevice *pci_bus_to_dev(PCIBus *bus);
int pci_read_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp);
int pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned
*slotp);
void pci_info(Monitor *mon);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name);
-PCIBus *pci_get_parent_bus(PCIDevice *dev);
-PCIDevice *pci_bus_to_dev(PCIBus *bus);
static inline void
pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
@@ -339,6 +337,15 @@ void pci_qdev_register(const char *name, int size,
pci_qdev_initfn init);
PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
+void pci_bridge_qdev_register(const char* name, int size,
+ pci_qdev_initfn init);
+
+void pci_bridge_set_map_irq(PCIBus *bus, pci_map_irq_fn map_irq);
+
+PCIBus *pci_bridge_create_simple(PCIBus *bus, int devfn, uint16_t vid,
+ uint16_t did, pci_map_irq_fn map_irq,
+ const char *pci_name);
+
/* lsi53c895a.c */
#define LSI_MAX_DEVS 7
void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id);
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 427fcd5..7bc4853 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -93,3 +93,5 @@
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+
+#define PCI_VENDOR_ID_INVALID 0xffff
--
1.6.0.2