Exemple #1
0
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);
}
Exemple #2
0
/*
 * 6.2.6 Error Message Control Figure 6-3
 *
 * Walk up the bus tree from the device, propagate the error message.
 */
static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
{
    uint8_t type;

    while (dev) {
        if (!pci_is_express(dev)) {
            /* just ignore it */
            /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR?
             * Consider e.g. a PCI bridge above a PCI Express device. */
            return;
        }

        type = pcie_cap_get_type(dev);
        if ((type == PCI_EXP_TYPE_ROOT_PORT ||
            type == PCI_EXP_TYPE_UPSTREAM ||
            type == PCI_EXP_TYPE_DOWNSTREAM) &&
            !pcie_aer_msg_vbridge(dev, msg)) {
                return;
        }
        if (!pcie_aer_msg_alldev(dev, msg)) {
            return;
        }
        if (type == PCI_EXP_TYPE_ROOT_PORT) {
            pcie_aer_msg_root_port(dev, msg);
            /* Root port can notify system itself,
               or send the error message to root complex event collector. */
            /*
             * if root port is associated with an event collector,
             * return the root complex event collector here.
             * For now root complex event collector isn't supported.
             */
            return;
        }
        dev = pci_bridge_get_device(dev->bus);
    }
}
Exemple #3
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;
}
Exemple #4
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;
}