|
@@ -32,6 +32,7 @@
|
|
|
#include "qemu/osdep.h"
|
|
|
#include "qapi/error.h"
|
|
|
#include "hw/irq.h"
|
|
|
+#include "hw/pci/pci_bus.h"
|
|
|
#include "hw/pci-host/gpex.h"
|
|
|
#include "hw/qdev-properties.h"
|
|
|
#include "migration/vmstate.h"
|
|
@@ -41,20 +42,25 @@
|
|
|
* GPEX host
|
|
|
*/
|
|
|
|
|
|
+struct GPEXIrq {
|
|
|
+ qemu_irq irq;
|
|
|
+ int irq_num;
|
|
|
+};
|
|
|
+
|
|
|
static void gpex_set_irq(void *opaque, int irq_num, int level)
|
|
|
{
|
|
|
GPEXHost *s = opaque;
|
|
|
|
|
|
- qemu_set_irq(s->irq[irq_num], level);
|
|
|
+ qemu_set_irq(s->irq[irq_num].irq, level);
|
|
|
}
|
|
|
|
|
|
int gpex_set_irq_num(GPEXHost *s, int index, int gsi)
|
|
|
{
|
|
|
- if (index >= GPEX_NUM_IRQS) {
|
|
|
+ if (index >= s->num_irqs) {
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- s->irq_num[index] = gsi;
|
|
|
+ s->irq[index].irq_num = gsi;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -62,7 +68,7 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
|
|
|
{
|
|
|
PCIINTxRoute route;
|
|
|
GPEXHost *s = opaque;
|
|
|
- int gsi = s->irq_num[pin];
|
|
|
+ int gsi = s->irq[pin].irq_num;
|
|
|
|
|
|
route.irq = gsi;
|
|
|
if (gsi < 0) {
|
|
@@ -74,6 +80,13 @@ static PCIINTxRoute gpex_route_intx_pin_to_irq(void *opaque, int pin)
|
|
|
return route;
|
|
|
}
|
|
|
|
|
|
+static int gpex_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
|
|
|
+{
|
|
|
+ PCIBus *bus = pci_device_root_bus(pci_dev);
|
|
|
+
|
|
|
+ return (PCI_SLOT(pci_dev->devfn) + pin) % bus->nirq;
|
|
|
+}
|
|
|
+
|
|
|
static void gpex_host_realize(DeviceState *dev, Error **errp)
|
|
|
{
|
|
|
PCIHostState *pci = PCI_HOST_BRIDGE(dev);
|
|
@@ -82,6 +95,8 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
|
|
|
PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
|
|
|
int i;
|
|
|
|
|
|
+ s->irq = g_malloc0_n(s->num_irqs, sizeof(*s->irq));
|
|
|
+
|
|
|
pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
|
|
|
sysbus_init_mmio(sbd, &pex->mmio);
|
|
|
|
|
@@ -128,19 +143,27 @@ static void gpex_host_realize(DeviceState *dev, Error **errp)
|
|
|
sysbus_init_mmio(sbd, &s->io_ioport);
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
|
|
- sysbus_init_irq(sbd, &s->irq[i]);
|
|
|
- s->irq_num[i] = -1;
|
|
|
+ for (i = 0; i < s->num_irqs; i++) {
|
|
|
+ sysbus_init_irq(sbd, &s->irq[i].irq);
|
|
|
+ s->irq[i].irq_num = -1;
|
|
|
}
|
|
|
|
|
|
pci->bus = pci_register_root_bus(dev, "pcie.0", gpex_set_irq,
|
|
|
- pci_swizzle_map_irq_fn, s, &s->io_mmio,
|
|
|
- &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
|
|
|
+ gpex_swizzle_map_irq_fn,
|
|
|
+ s, &s->io_mmio, &s->io_ioport, 0,
|
|
|
+ s->num_irqs, TYPE_PCIE_BUS);
|
|
|
|
|
|
pci_bus_set_route_irq_fn(pci->bus, gpex_route_intx_pin_to_irq);
|
|
|
qdev_realize(DEVICE(&s->gpex_root), BUS(pci->bus), &error_fatal);
|
|
|
}
|
|
|
|
|
|
+static void gpex_host_unrealize(DeviceState *dev)
|
|
|
+{
|
|
|
+ GPEXHost *s = GPEX_HOST(dev);
|
|
|
+
|
|
|
+ g_free(s->irq);
|
|
|
+}
|
|
|
+
|
|
|
static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
|
|
|
PCIBus *rootbus)
|
|
|
{
|
|
@@ -166,6 +189,7 @@ static const Property gpex_host_properties[] = {
|
|
|
gpex_cfg.mmio64.base, 0),
|
|
|
DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost,
|
|
|
gpex_cfg.mmio64.size, 0),
|
|
|
+ DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS),
|
|
|
};
|
|
|
|
|
|
static void gpex_host_class_init(ObjectClass *klass, void *data)
|
|
@@ -175,6 +199,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data)
|
|
|
|
|
|
hc->root_bus_path = gpex_host_root_bus_path;
|
|
|
dc->realize = gpex_host_realize;
|
|
|
+ dc->unrealize = gpex_host_unrealize;
|
|
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
|
|
dc->fw_name = "pci";
|
|
|
device_class_set_props(dc, gpex_host_properties);
|