Example #1
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 #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
/*
 * Sync the PCIe Link Status negotiated speed and width of a bridge with the
 * downstream device.  If downstream device is not present, re-write with the
 * Link Capability fields.  If downstream device reports invalid width or
 * speed, replace with minimum values (LnkSta fields are RsvdZ on VFs but such
 * values interfere with PCIe native hotplug detecting new devices).  Limit
 * width and speed to bridge capabilities for compatibility.  Use config_read
 * to access the downstream device since it could be an assigned device with
 * volatile link information.
 */
void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
{
    PCIBridge *br = PCI_BRIDGE(bridge_dev);
    PCIBus *bus = pci_bridge_get_sec_bus(br);
    PCIDevice *target = bus->devices[0];
    uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
    uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);

    if (!target || !target->exp.exp_cap) {
        lnksta = lnkcap;
    } else {
        lnksta = target->config_read(target,
                                     target->exp.exp_cap + PCI_EXP_LNKSTA,
                                     sizeof(lnksta));

        if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
            lnksta &= ~PCI_EXP_LNKSTA_NLW;
            lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
        } else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
            lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
        }

        if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
            lnksta &= ~PCI_EXP_LNKSTA_CLS;
            lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
        } else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
            lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
        }
    }

    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
                                 PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
    pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
                               (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
}
Example #4
0
File: pcie.c Project: Aakriti/qemu
void pcie_cap_slot_reset(PCIDevice *dev)
{
    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;

    PCIE_DEV_PRINTF(dev, "reset\n");

    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
                                 PCI_EXP_SLTCTL_EIC |
                                 PCI_EXP_SLTCTL_PIC |
                                 PCI_EXP_SLTCTL_AIC |
                                 PCI_EXP_SLTCTL_HPIE |
                                 PCI_EXP_SLTCTL_CCIE |
                                 PCI_EXP_SLTCTL_PDCE |
                                 PCI_EXP_SLTCTL_ABPE);
    pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
                               PCI_EXP_SLTCTL_PIC_OFF |
                               PCI_EXP_SLTCTL_AIC_OFF);

    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
                                 PCI_EXP_SLTSTA_EIS |/* on reset,
                                                        the lock is released */
                                 PCI_EXP_SLTSTA_CC |
                                 PCI_EXP_SLTSTA_PDC |
                                 PCI_EXP_SLTSTA_ABP);

    hotplug_event_update_event_status(dev);
}
Example #5
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 #6
0
File: shpc.c Project: CTU-IIG/qemu
static void shpc_set_status(SHPCDevice *shpc,
                            int slot, uint8_t value, uint16_t msk)
{
    uint8_t *status = shpc->config + SHPC_SLOT_STATUS(slot);
    pci_word_test_and_clear_mask(status, msk);
    pci_word_test_and_set_mask(status, value << ctz32(msk));
}
Example #7
0
/*
 * return value:
 * true: error message needs to be sent up
 * false: error message is masked
 *
 * 6.2.6 Error Message Control
 * Figure 6-3
 * all pci express devices part
 */
static bool
pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
{
    if (!(pcie_aer_msg_is_uncor(msg) &&
          (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
        return false;
    }

    /* Signaled System Error
     *
     * 7.5.1.1 Command register
     * Bit 8 SERR# Enable
     *
     * When Set, this bit enables reporting of Non-fatal and Fatal
     * errors detected by the Function to the Root Complex. Note that
     * errors are reported if enabled either through this bit or through
     * the PCI Express specific bits in the Device Control register (see
     * Section 7.8.4).
     */
    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
                               PCI_STATUS_SIG_SYSTEM_ERROR);

    if (!(msg->severity &
          pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) {
        return false;
    }

    /* send up error message */
    return true;
}
Example #8
0
File: pcie.c Project: THanwa/qemu
void pcie_cap_slot_reset(PCIDevice *dev)
{
    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
    uint8_t port_type = pcie_cap_get_type(dev);

    assert(port_type == PCI_EXP_TYPE_DOWNSTREAM ||
           port_type == PCI_EXP_TYPE_ROOT_PORT);

    PCIE_DEV_PRINTF(dev, "reset\n");

    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
                                 PCI_EXP_SLTCTL_EIC |
                                 PCI_EXP_SLTCTL_PIC |
                                 PCI_EXP_SLTCTL_AIC |
                                 PCI_EXP_SLTCTL_HPIE |
                                 PCI_EXP_SLTCTL_CCIE |
                                 PCI_EXP_SLTCTL_PDCE |
                                 PCI_EXP_SLTCTL_ABPE);
    pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
                               PCI_EXP_SLTCTL_AIC_OFF);

    if (dev->cap_present & QEMU_PCIE_SLTCAP_PCP) {
        /* Downstream ports enforce device number 0. */
        bool populated = pci_bridge_get_sec_bus(PCI_BRIDGE(dev))->devices[0];
        uint16_t pic;

        if (populated) {
            pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTCTL,
                                         PCI_EXP_SLTCTL_PCC);
        } else {
            pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL,
                                       PCI_EXP_SLTCTL_PCC);
        }

        pic = populated ? PCI_EXP_SLTCTL_PIC_ON : PCI_EXP_SLTCTL_PIC_OFF;
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTCTL, pic);
    }

    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
                                 PCI_EXP_SLTSTA_EIS |/* on reset,
                                                        the lock is released */
                                 PCI_EXP_SLTSTA_CC |
                                 PCI_EXP_SLTSTA_PDC |
                                 PCI_EXP_SLTSTA_ABP);

    hotplug_event_update_event_status(dev);
}
Example #9
0
File: pcie.c Project: Aakriti/qemu
/* pci express slot for pci express root/downstream port
   PCI express capability slot registers */
void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
{
    uint32_t pos = dev->exp.exp_cap;

    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_FLAGS,
                               PCI_EXP_FLAGS_SLOT);

    pci_long_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCAP,
                                 ~PCI_EXP_SLTCAP_PSN);
    pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
                               (slot << PCI_EXP_SLTCAP_PSN_SHIFT) |
                               PCI_EXP_SLTCAP_EIP |
                               PCI_EXP_SLTCAP_HPS |
                               PCI_EXP_SLTCAP_HPC |
                               PCI_EXP_SLTCAP_PIP |
                               PCI_EXP_SLTCAP_AIP |
                               PCI_EXP_SLTCAP_ABP);

    pci_word_test_and_clear_mask(dev->config + pos + PCI_EXP_SLTCTL,
                                 PCI_EXP_SLTCTL_PIC |
                                 PCI_EXP_SLTCTL_AIC);
    pci_word_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCTL,
                               PCI_EXP_SLTCTL_PIC_OFF |
                               PCI_EXP_SLTCTL_AIC_OFF);
    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
                               PCI_EXP_SLTCTL_PIC |
                               PCI_EXP_SLTCTL_AIC |
                               PCI_EXP_SLTCTL_HPIE |
                               PCI_EXP_SLTCTL_CCIE |
                               PCI_EXP_SLTCTL_PDCE |
                               PCI_EXP_SLTCTL_ABPE);
    /* Although reading PCI_EXP_SLTCTL_EIC returns always 0,
     * make the bit writable here in order to detect 1b is written.
     * pcie_cap_slot_write_config() test-and-clear the bit, so
     * this bit always returns 0 to the guest.
     */
    pci_word_test_and_set_mask(dev->wmask + pos + PCI_EXP_SLTCTL,
                               PCI_EXP_SLTCTL_EIC);

    pci_word_test_and_set_mask(dev->w1cmask + pos + PCI_EXP_SLTSTA,
                               PCI_EXP_HP_EV_SUPPORTED);

    dev->exp.hpev_notified = false;

    pci_bus_hotplug(pci_bridge_get_sec_bus(PCI_BRIDGE(dev)),
                    pcie_cap_slot_hotplug, &dev->qdev);
}
Example #10
0
File: pcie.c Project: THanwa/qemu
/* 7.8.2 PCI Express Capabilities Register: Interrupt Message Number */
void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector)
{
    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
    assert(vector < 32);
    pci_word_test_and_clear_mask(exp_cap + PCI_EXP_FLAGS, PCI_EXP_FLAGS_IRQ);
    pci_word_test_and_set_mask(exp_cap + PCI_EXP_FLAGS,
                               vector << PCI_EXP_FLAGS_IRQ_SHIFT);
}
Example #11
0
File: pcie.c Project: THanwa/qemu
/*
 * A PCI Express Hot-Plug Event has occurred, so update slot status register
 * and notify OS of the event if necessary.
 *
 * 6.7.3 PCI Express Hot-Plug Events
 * 6.7.3.4 Software Notification of Hot-Plug Events
 */
static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
{
    /* Minor optimization: if nothing changed - no event is needed. */
    if (pci_word_test_and_set_mask(dev->config + dev->exp.exp_cap +
                                   PCI_EXP_SLTSTA, event)) {
        return;
    }
    hotplug_event_notify(dev);
}
Example #12
0
/* log an event trying to access command buffer
 *   @addr : address that couldn't be accessed
 */
static void amdvi_log_command_error(AMDVIState *s, hwaddr addr)
{
    uint64_t evt[4], info = AMDVI_EVENT_COMMAND_HW_ERROR;

    amdvi_encode_event(evt, 0, addr, info);
    amdvi_log_event(s, evt);
    pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
            PCI_STATUS_SIG_TARGET_ABORT);
}
Example #13
0
void pci_bridge_disable_base_limit(PCIDevice *dev)
{
    uint8_t *conf = dev->config;

    pci_byte_test_and_set_mask(conf + PCI_IO_BASE,
                               PCI_IO_RANGE_MASK & 0xff);
    pci_byte_test_and_clear_mask(conf + PCI_IO_LIMIT,
                                 PCI_IO_RANGE_MASK & 0xff);
    pci_word_test_and_set_mask(conf + PCI_MEMORY_BASE,
                               PCI_MEMORY_RANGE_MASK & 0xffff);
    pci_word_test_and_clear_mask(conf + PCI_MEMORY_LIMIT,
                                 PCI_MEMORY_RANGE_MASK & 0xffff);
    pci_word_test_and_set_mask(conf + PCI_PREF_MEMORY_BASE,
                               PCI_PREF_RANGE_MASK & 0xffff);
    pci_word_test_and_clear_mask(conf + PCI_PREF_MEMORY_LIMIT,
                                 PCI_PREF_RANGE_MASK & 0xffff);
    pci_set_word(conf + PCI_PREF_BASE_UPPER32, 0);
    pci_set_word(conf + PCI_PREF_LIMIT_UPPER32, 0);
}
Example #14
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 #15
0
/* log an error accessing a PTE entry
 * @addr : address that couldn't be accessed
 */
static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid,
                                    hwaddr addr, uint16_t info)
{
    uint64_t evt[4];

    info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR;
    amdvi_encode_event(evt, devid, addr, info);
    amdvi_log_event(s, evt);
    pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
             PCI_STATUS_SIG_TARGET_ABORT);
}
Example #16
0
/* log an error encountered during a page walk
 *
 * @addr: virtual address in translation request
 */
static void amdvi_page_fault(AMDVIState *s, uint16_t devid,
                             hwaddr addr, uint16_t info)
{
    uint64_t evt[4];

    info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF;
    amdvi_encode_event(evt, devid, addr, info);
    amdvi_log_event(s, evt);
    pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS,
            PCI_STATUS_SIG_TARGET_ABORT);
}
Example #17
0
File: shpc.c Project: CTU-IIG/qemu
static void shpc_set_sec_bus_speed(SHPCDevice *shpc, uint8_t speed)
{
    switch (speed) {
    case SHPC_SEC_BUS_33:
        shpc->config[SHPC_SEC_BUS] &= ~SHPC_SEC_BUS_MASK;
        shpc->config[SHPC_SEC_BUS] |= speed;
        break;
    default:
        pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
                                   SHPC_CMD_STATUS_INVALID_MODE);
    }
}
Example #18
0
File: pcie.c Project: THanwa/qemu
/* function level reset(FLR) */
void pcie_cap_flr_init(PCIDevice *dev)
{
    pci_long_test_and_set_mask(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCAP,
                               PCI_EXP_DEVCAP_FLR);

    /* Although reading BCR_FLR returns always 0,
     * the bit is made writable here in order to detect the 1b is written
     * pcie_cap_flr_write_config() test-and-clear the bit, so
     * this bit always returns 0 to the guest.
     */
    pci_word_test_and_set_mask(dev->wmask + dev->exp.exp_cap + PCI_EXP_DEVCTL,
                               PCI_EXP_DEVCTL_BCR_FLR);
}
Example #19
0
/*
 * return value:
 * true: error message is sent up
 * false: error message is masked
 *
 * 6.2.6 Error Message Control
 * Figure 6-3
 * virtual pci bridge part
 */
static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg)
{
    uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL);

    if (pcie_aer_msg_is_uncor(msg)) {
        /* Received System Error */
        pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS,
                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
    }

    if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) {
        return false;
    }
    return true;
}
Example #20
0
static void
pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
{
    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
    uint8_t *cmask = dev->cmask + dev->exp.exp_cap;

    /* capability register
    interrupt message number defaults to 0 */
    pci_set_word(exp_cap + PCI_EXP_FLAGS,
                 ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) |
                 version);

    /* device capability register
     * table 7-12:
     * roll based error reporting bit must be set by all
     * Functions conforming to the ECN, PCI Express Base
     * Specification, Revision 1.1., or subsequent PCI Express Base
     * Specification revisions.
     */
    pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);

    pci_set_long(exp_cap + PCI_EXP_LNKCAP,
                 (port << PCI_EXP_LNKCAP_PN_SHIFT) |
                 PCI_EXP_LNKCAP_ASPMS_0S |
                 QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
                 QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));

    pci_set_word(exp_cap + PCI_EXP_LNKSTA,
                 QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
                 QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));

    if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
                                   PCI_EXP_LNKSTA_DLLLA);
    }

    /* We changed link status bits over time, and changing them across
     * migrations is generally fine as hardware changes them too.
     * Let's not bother checking.
     */
    pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
}
Example #21
0
/* 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_word_test_and_set_mask(dev->config + PCI_STATUS,
                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
    dev->config[PCI_HEADER_TYPE] =
        (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
        PCI_HEADER_TYPE_BRIDGE;
    pci_set_word(dev->config + PCI_SEC_STATUS,
                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);

    /*
     * If we don't specify the name, the bus will be addressed as <id>.0, where
     * id is the device id.
     * Since PCI Bridge devices have a single bus each, we don't need the index:
     * let users address the bus using the device name.
     */
    if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
	    br->bus_name = dev->qdev.id;
    }

    qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
                        br->bus_name);
    sec_bus->parent_dev = dev;
    sec_bus->map_irq = br->map_irq;
    sec_bus->address_space_mem = &br->address_space_mem;
    memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
    sec_bus->address_space_io = &br->address_space_io;
    memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
    pci_bridge_region_init(br);
    QLIST_INIT(&sec_bus->child);
    QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
    return 0;
}
Example #22
0
int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
                  uint16_t size, Error **errp)
{
    pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, cap_ver,
                        offset, size);
    dev->exp.aer_cap = offset;

    /* clip down the value to avoid unreasonable memory usage */
    if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
        error_setg(errp, "Invalid aer_log_max %d. The max number of aer log "
                "is %d", dev->exp.aer_log.log_max, PCIE_AER_LOG_MAX_LIMIT);
        return -EINVAL;
    }
    dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
                                        dev->exp.aer_log.log_max);

    pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
                 PCI_ERR_UNC_SUPPORTED);

    pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
                 PCI_ERR_UNC_SEVERITY_DEFAULT);
    pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
                 PCI_ERR_UNC_SUPPORTED);

    pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
                               PCI_ERR_COR_SUPPORTED);

    pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
                 PCI_ERR_COR_MASK_DEFAULT);
    pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
                 PCI_ERR_COR_SUPPORTED);

    /* capabilities and control. multiple header logging is supported */
    if (dev->exp.aer_log.log_max > 0) {
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
                     PCI_ERR_CAP_MHRC);
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
                     PCI_ERR_CAP_MHRE);
    } else {
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
    }

    switch (pcie_cap_get_type(dev)) {
    case PCI_EXP_TYPE_ROOT_PORT:
        /* this case will be set by pcie_aer_root_init() */
        /* fallthrough */
    case PCI_EXP_TYPE_DOWNSTREAM:
    case PCI_EXP_TYPE_UPSTREAM:
        pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
                                   PCI_BRIDGE_CTL_SERR);
        pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
        break;
    default:
        /* nothing */
        break;
    }
    return 0;
}
Example #23
0
File: shpc.c Project: CTU-IIG/qemu
static void shpc_invalid_command(SHPCDevice *shpc)
{
    pci_word_test_and_set_mask(shpc->config + SHPC_CMD_STATUS,
                               SHPC_CMD_STATUS_INVALID_CMD);
}
Example #24
0
static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
{
    PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
    uint8_t *exp_cap = dev->config + dev->exp.exp_cap;

    /* Skip anything that isn't a PCIESlot */
    if (!s) {
        return;
    }

    /* Clear and fill LNKCAP from what was configured above */
    pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
                                 PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
    pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
                               QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
                               QEMU_PCI_EXP_LNKCAP_MLS(s->speed));

    /*
     * Link bandwidth notification is required for all root ports and
     * downstream ports supporting links wider than x1 or multiple link
     * speeds.
     */
    if (s->width > QEMU_PCI_EXP_LNK_X1 ||
        s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
        pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
                                   PCI_EXP_LNKCAP_LBNC);
    }

    if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
        /*
         * Hot-plug capable downstream ports and downstream ports supporting
         * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
         * to 1b.  PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
         * we also hardwire to 1b here.  2.5GT/s hot-plug slots should also
         * technically implement this, but it's not done here for compatibility.
         */
        pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
                                   PCI_EXP_LNKCAP_DLLLARC);
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
                                   PCI_EXP_LNKSTA_DLLLA);

        /*
         * Target Link Speed defaults to the highest link speed supported by
         * the component.  2.5GT/s devices are permitted to hardwire to zero.
         */
        pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
                                     PCI_EXP_LNKCTL2_TLS);
        pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
                                   QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
                                   PCI_EXP_LNKCTL2_TLS);
    }

    /*
     * 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
     * actually a reference to the highest bit supported in this register.
     * We assume the device supports all link speeds.
     */
    if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
        pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
        pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
                                   PCI_EXP_LNKCAP2_SLS_2_5GB |
                                   PCI_EXP_LNKCAP2_SLS_5_0GB |
                                   PCI_EXP_LNKCAP2_SLS_8_0GB);
        if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
            pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
                                       PCI_EXP_LNKCAP2_SLS_16_0GB);
        }
    }
}
Example #25
0
int pcie_aer_init(PCIDevice *dev, uint16_t offset)
{
    PCIExpressDevice *exp;

    pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
                        offset, PCI_ERR_SIZEOF);
    exp = &dev->exp;
    exp->aer_cap = offset;

    /* log_max is property */
    if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
        dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
    }
    /* clip down the value to avoid unreasobale memory usage */
    if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
        return -EINVAL;
    }
    dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
                                        dev->exp.aer_log.log_max);

    pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
                 PCI_ERR_UNC_SUPPORTED);

    pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
                 PCI_ERR_UNC_SEVERITY_DEFAULT);
    pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER,
                 PCI_ERR_UNC_SUPPORTED);

    pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS,
                               PCI_ERR_COR_SUPPORTED);

    pci_set_long(dev->config + offset + PCI_ERR_COR_MASK,
                 PCI_ERR_COR_MASK_DEFAULT);
    pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK,
                 PCI_ERR_COR_SUPPORTED);

    /* capabilities and control. multiple header logging is supported */
    if (dev->exp.aer_log.log_max > 0) {
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC |
                     PCI_ERR_CAP_MHRC);
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE |
                     PCI_ERR_CAP_MHRE);
    } else {
        pci_set_long(dev->config + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC);
        pci_set_long(dev->wmask + offset + PCI_ERR_CAP,
                     PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
    }

    switch (pcie_cap_get_type(dev)) {
    case PCI_EXP_TYPE_ROOT_PORT:
        /* this case will be set by pcie_aer_root_init() */
        /* fallthrough */
    case PCI_EXP_TYPE_DOWNSTREAM:
    case PCI_EXP_TYPE_UPSTREAM:
        pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL,
                                   PCI_BRIDGE_CTL_SERR);
        pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS,
                                   PCI_SEC_STATUS_RCV_SYSTEM_ERROR);
        break;
    default:
        /* nothing */
        break;
    }
    return 0;
}