Esempio n. 1
0
static int multi_serial_pci_init(PCIDevice *dev)
{
    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
    SerialState *s;
    int i;

    switch (pc->device_id) {
    case 0x0003:
        pci->ports = 2;
        break;
    case 0x0004:
        pci->ports = 4;
        break;
    }
    assert(pci->ports > 0);
    assert(pci->ports <= PCI_SERIAL_MAX_PORTS);

    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
    memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports);
    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
                                   pci->ports);

    for (i = 0; i < pci->ports; i++) {
        s = pci->state + i;
        s->baudbase = 115200;
        serial_init_core(s);
        s->irq = pci->irqs[i];
        pci->name[i] = g_strdup_printf("uart #%d", i+1);
        memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8);
        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
    }
    return 0;
}
Esempio n. 2
0
static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
{
    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
    SerialState *s;
    Error *err = NULL;
    int i, nr_ports = 0;

    switch (pc->device_id) {
    case 0x0003:
        nr_ports = 2;
        break;
    case 0x0004:
        nr_ports = 4;
        break;
    }
    assert(nr_ports > 0);
    assert(nr_ports <= PCI_SERIAL_MAX_PORTS);

    pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
    memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
                                   nr_ports);

    for (i = 0; i < nr_ports; i++) {
        s = pci->state + i;
        s->baudbase = 115200;
        serial_realize_core(s, &err);
        if (err != NULL) {
            error_propagate(errp, err);
            multi_serial_pci_exit(dev);
            return;
        }
        s->irq = pci->irqs[i];
        pci->name[i] = g_strdup_printf("uart #%d", i+1);
        memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
                              pci->name[i], 8);
        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
        pci->ports++;
    }
}
static void build_pci_bus_end(PCIBus *bus, void *bus_state)
{
    AcpiBuildPciBusHotplugState *child = bus_state;
    AcpiBuildPciBusHotplugState *parent = child->parent;
    GArray *bus_table = build_alloc_array();
    DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX);
    DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX);
    DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX);
    DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX);
    DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX);
    uint8_t op;
    int i;
    QObject *bsel;
    GArray *method;
    bool bus_hotplug_support = false;

    if (bus->parent_dev) {
        op = 0x82; /* DeviceOp */
        build_append_nameseg(bus_table, "S%.02X_",
                             bus->parent_dev->devfn);
        build_append_byte(bus_table, 0x08); /* NameOp */
        build_append_nameseg(bus_table, "_SUN");
        build_append_value(bus_table, PCI_SLOT(bus->parent_dev->devfn), 1);
        build_append_byte(bus_table, 0x08); /* NameOp */
        build_append_nameseg(bus_table, "_ADR");
        build_append_value(bus_table, (PCI_SLOT(bus->parent_dev->devfn) << 16) |
                           PCI_FUNC(bus->parent_dev->devfn), 4);
    } else {
        op = 0x10; /* ScopeOp */;
        build_append_nameseg(bus_table, "PCI0");
    }

    bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
    if (bsel) {
        build_append_byte(bus_table, 0x08); /* NameOp */
        build_append_nameseg(bus_table, "BSEL");
        build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel)));
        memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable);
    } else {
        /* No bsel - no slots are hot-pluggable */
        memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable);
    }

    memset(slot_device_present, 0x00, sizeof slot_device_present);
    memset(slot_device_system, 0x00, sizeof slot_device_present);
    memset(slot_device_vga, 0x00, sizeof slot_device_vga);
    memset(slot_device_qxl, 0x00, sizeof slot_device_qxl);

    for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
        DeviceClass *dc;
        PCIDeviceClass *pc;
        PCIDevice *pdev = bus->devices[i];
        int slot = PCI_SLOT(i);

        if (!pdev) {
            continue;
        }

        set_bit(slot, slot_device_present);
        pc = PCI_DEVICE_GET_CLASS(pdev);
        dc = DEVICE_GET_CLASS(pdev);

        if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
            set_bit(slot, slot_device_system);
        }

        if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
            set_bit(slot, slot_device_vga);

            if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) {
                set_bit(slot, slot_device_qxl);
            }
        }

        if (!dc->hotpluggable || pc->is_bridge) {
            clear_bit(slot, slot_hotplug_enable);
        }
    }

    /* Append Device object for each slot */
    for (i = 0; i < PCI_SLOT_MAX; i++) {
        bool can_eject = test_bit(i, slot_hotplug_enable);
        bool present = test_bit(i, slot_device_present);
        bool vga = test_bit(i, slot_device_vga);
        bool qxl = test_bit(i, slot_device_qxl);
        bool system = test_bit(i, slot_device_system);
        if (can_eject) {
            void *pcihp = acpi_data_push(bus_table,
                                         ACPI_PCIHP_SIZEOF);
            memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF);
            patch_pcihp(i, pcihp);
            bus_hotplug_support = true;
        } else if (qxl) {
            void *pcihp = acpi_data_push(bus_table,
                                         ACPI_PCIQXL_SIZEOF);
            memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF);
            patch_pciqxl(i, pcihp);
        } else if (vga) {
            void *pcihp = acpi_data_push(bus_table,
                                         ACPI_PCIVGA_SIZEOF);
            memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF);
            patch_pcivga(i, pcihp);
        } else if (system) {
            /* Nothing to do: system devices are in DSDT. */
        } else if (present) {
            void *pcihp = acpi_data_push(bus_table,
                                         ACPI_PCINOHP_SIZEOF);
            memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF);
            patch_pcinohp(i, pcihp);
        }
    }

    if (bsel) {
        method = build_alloc_method("DVNT", 2);

        for (i = 0; i < PCI_SLOT_MAX; i++) {
            GArray *notify;
            uint8_t op;

            if (!test_bit(i, slot_hotplug_enable)) {
                continue;
            }

            notify = build_alloc_array();
            op = 0xA0; /* IfOp */

            build_append_byte(notify, 0x7B); /* AndOp */
            build_append_byte(notify, 0x68); /* Arg0Op */
            build_append_int(notify, 0x1 << i);
            build_append_byte(notify, 0x00); /* NullName */
            build_append_byte(notify, 0x86); /* NotifyOp */
            build_append_nameseg(notify, "S%.02X_", PCI_DEVFN(i, 0));
            build_append_byte(notify, 0x69); /* Arg1Op */

            /* Pack it up */
            build_package(notify, op, 0);

            build_append_array(method, notify);

            build_free_array(notify);
        }

        build_append_and_cleanup_method(bus_table, method);
    }

    /* Append PCNT method to notify about events on local and child buses.
     * Add unconditionally for root since DSDT expects it.
     */
    if (bus_hotplug_support || child->notify_table->len || !bus->parent_dev) {
        method = build_alloc_method("PCNT", 0);

        /* If bus supports hotplug select it and notify about local events */
        if (bsel) {
            build_append_byte(method, 0x70); /* StoreOp */
            build_append_int(method, qint_get_int(qobject_to_qint(bsel)));
            build_append_nameseg(method, "BNUM");
            build_append_nameseg(method, "DVNT");
            build_append_nameseg(method, "PCIU");
            build_append_int(method, 1); /* Device Check */
            build_append_nameseg(method, "DVNT");
            build_append_nameseg(method, "PCID");
            build_append_int(method, 3); /* Eject Request */
        }

        /* Notify about child bus events in any case */
        build_append_array(method, child->notify_table);

        build_append_and_cleanup_method(bus_table, method);

        /* Append description of child buses */
        build_append_array(bus_table, child->device_table);

        /* Pack it up */
        if (bus->parent_dev) {
            build_extop_package(bus_table, op);
        } else {
            build_package(bus_table, op, 0);
        }

        /* Append our bus description to parent table */
        build_append_array(parent->device_table, bus_table);

        /* Also tell parent how to notify us, invoking PCNT method.
         * At the moment this is not needed for root as we have a single root.
         */
        if (bus->parent_dev) {
            build_append_byte(parent->notify_table, '^'); /* ParentPrefixChar */
            build_append_byte(parent->notify_table, 0x2E); /* DualNamePrefix */
            build_append_nameseg(parent->notify_table, "S%.02X_",
                                 bus->parent_dev->devfn);
            build_append_nameseg(parent->notify_table, "PCNT");
        }
    }

    build_free_array(bus_table);
    build_pci_bus_state_cleanup(child);
    g_free(child);
}
Esempio n. 4
0
static void rp_realize(PCIDevice *d, Error **errp)
{
    PCIEPort *p = PCIE_PORT(d);
    PCIESlot *s = PCIE_SLOT(d);
    PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d);
    PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
    int rc;

    pci_config_set_interrupt_pin(d->config, 1);
    pci_bridge_initfn(d, TYPE_PCIE_BUS);
    pcie_port_init_reg(d);

    rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id,
                               rpc->ssid, errp);
    if (rc < 0) {
        error_append_hint(errp, "Can't init SSV ID, error %d\n", rc);
        goto err_bridge;
    }

    if (rpc->interrupts_init) {
        rc = rpc->interrupts_init(d, errp);
        if (rc < 0) {
            goto err_bridge;
        }
    }

    rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT,
                       p->port, errp);
    if (rc < 0) {
        error_append_hint(errp, "Can't add Root Port capability, "
                          "error %d\n", rc);
        goto err_int;
    }

    pcie_cap_arifwd_init(d);
    pcie_cap_deverr_init(d);
    pcie_cap_slot_init(d, s->slot);
    pcie_cap_root_init(d);

    pcie_chassis_create(s->chassis);
    rc = pcie_chassis_add_slot(s);
    if (rc < 0) {
        error_setg(errp, "Can't add chassis slot, error %d", rc);
        goto err_pcie_cap;
    }

    rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset,
                       PCI_ERR_SIZEOF, errp);
    if (rc < 0) {
        goto err;
    }
    pcie_aer_root_init(d);
    rp_aer_vector_update(d);

    return;

err:
    pcie_chassis_del_slot(s);
err_pcie_cap:
    pcie_cap_exit(d);
err_int:
    if (rpc->interrupts_uninit) {
        rpc->interrupts_uninit(d);
    }
err_bridge:
    pci_bridge_exitfn(d);
}