Example #1
0
File: pcie.c Project: THanwa/qemu
void pcie_cap_slot_write_config(PCIDevice *dev,
                                uint32_t addr, uint32_t val, int len)
{
    uint32_t pos = dev->exp.exp_cap;
    uint8_t *exp_cap = dev->config + pos;
    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);

    if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
        hotplug_event_clear(dev);
    }

    if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
        return;
    }

    if (pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
                                     PCI_EXP_SLTCTL_EIC)) {
        sltsta ^= PCI_EXP_SLTSTA_EIS; /* toggle PCI_EXP_SLTSTA_EIS bit */
        pci_set_word(exp_cap + PCI_EXP_SLTSTA, sltsta);
        PCIE_DEV_PRINTF(dev, "PCI_EXP_SLTCTL_EIC: "
                        "sltsta -> 0x%02"PRIx16"\n",
                        sltsta);
    }

    /*
     * If the slot is polulated, power indicator is off and power
     * controller is off, it is safe to detach the devices.
     */
    if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
        ((val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF)) {
            PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
            pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
                                pcie_unplug_device, NULL);

            pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
                                         PCI_EXP_SLTSTA_PDS);
            pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                       PCI_EXP_SLTSTA_PDC);
    }

    hotplug_event_notify(dev);

    /* 
     * 6.7.3.2 Command Completed Events
     *
     * Software issues a command to a hot-plug capable Downstream Port by
     * issuing a write transaction that targets any portion of the Port’s Slot
     * Control register. A single write to the Slot Control register is
     * considered to be a single command, even if the write affects more than
     * one field in the Slot Control register. In response to this transaction,
     * the Port must carry out the requested actions and then set the
     * associated status field for the command completed event. */

    /* Real hardware might take a while to complete requested command because
     * physical movement would be involved like locking the electromechanical
     * lock.  However in our case, command is completed instantaneously above,
     * so send a command completion event right now.
     */
    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_CCI);
}
Example #2
0
void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
                           Error **errp)
{
    PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
    uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
    PCIDevice *pci_dev = PCI_DEVICE(dev);

    /* Don't send event when device is enabled during qemu machine creation:
     * it is present on boot, no hotplug event is necessary. We do send an
     * event when the device is disabled later. */
    if (!dev->hotplugged) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                   PCI_EXP_SLTSTA_PDS);
        if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
            pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
                                       PCI_EXP_LNKSTA_DLLLA);
        }
        return;
    }

    /* To enable multifunction hot-plug, we just ensure the function
     * 0 added last. When function 0 is added, we set the sltsta and
     * inform OS via event notification.
     */
    if (pci_get_function_0(pci_dev)) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                   PCI_EXP_SLTSTA_PDS);
        if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
            pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
                                       PCI_EXP_LNKSTA_DLLLA);
        }
        pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
                            PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
    }
}
Example #3
0
File: pcie.c Project: THanwa/qemu
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
                              Error **errp)
{
    uint8_t *exp_cap;
    PCIDevice *pci_dev = PCI_DEVICE(dev);

    pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);

    /* Don't send event when device is enabled during qemu machine creation:
     * it is present on boot, no hotplug event is necessary. We do send an
     * event when the device is disabled later. */
    if (!dev->hotplugged) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                   PCI_EXP_SLTSTA_PDS);
        return;
    }

    /* TODO: multifunction hot-plug.
     * Right now, only a device of function = 0 is allowed to be
     * hot plugged/unplugged.
     */
    assert(PCI_FUNC(pci_dev->devfn) == 0);

    pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                               PCI_EXP_SLTSTA_PDS);
    pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
                        PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
}
Example #4
0
File: pcie.c Project: Aakriti/qemu
static int pcie_cap_slot_hotplug(DeviceState *qdev,
                                 PCIDevice *pci_dev, PCIHotplugState state)
{
    PCIDevice *d = PCI_DEVICE(qdev);
    uint8_t *exp_cap = d->config + d->exp.exp_cap;
    uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);

    /* Don't send event when device is enabled during qemu machine creation:
     * it is present on boot, no hotplug event is necessary. We do send an
     * event when the device is disabled later. */
    if (state == PCI_COLDPLUG_ENABLED) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                   PCI_EXP_SLTSTA_PDS);
        return 0;
    }

    PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
    if (sltsta & PCI_EXP_SLTSTA_EIS) {
        /* the slot is electromechanically locked.
         * This error is propagated up to qdev and then to HMP/QMP.
         */
        return -EBUSY;
    }

    /* TODO: multifunction hot-plug.
     * Right now, only a device of function = 0 is allowed to be
     * hot plugged/unplugged.
     */
    assert(PCI_FUNC(pci_dev->devfn) == 0);

    if (state == PCI_HOTPLUG_ENABLED) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
                                   PCI_EXP_SLTSTA_PDS);
        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
    } else {
        object_unparent(OBJECT(pci_dev));
        pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
                                     PCI_EXP_SLTSTA_PDS);
        pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
    }
    return 0;
}
Example #5
0
File: pcie.c Project: THanwa/qemu
void pcie_cap_slot_push_attention_button(PCIDevice *dev)
{
    pcie_cap_slot_event(dev, PCI_EXP_HP_EV_ABP);
}