msi.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 769 行 · 第 1/2 页

C
769
字号
static void msi_free_vector(int vector){    struct msi_desc *entry;    ASSERT(spin_is_locked(&irq_desc[vector].lock));    entry = irq_desc[vector].msi_desc;    teardown_msi_vector(vector);    if ( entry->msi_attrib.type == PCI_CAP_ID_MSIX )    {        unsigned long start;        writel(1, entry->mask_base + entry->msi_attrib.entry_nr              * PCI_MSIX_ENTRY_SIZE              + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);        start = (unsigned long)entry->mask_base & ~(PAGE_SIZE - 1);        msix_fixmap_free(virt_to_fix(start));        destroy_xen_mappings(start, start + PAGE_SIZE);    }    list_del(&entry->list);    xfree(entry);}static struct msi_desc *find_msi_entry(struct pci_dev *dev,                                       int vector, int cap_id){    struct msi_desc *entry;    list_for_each_entry( entry, &dev->msi_list, list )    {        if ( entry->msi_attrib.type == cap_id &&             (vector == -1 || entry->vector == vector) )            return entry;    }    return NULL;}/** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function * * Setup the MSI capability structure of device function with a single * MSI irq, regardless of device function is capable of handling * multiple messages. A return of zero indicates the successful setup * of an entry zero with the new MSI irq or non-zero for otherwise. **/static int msi_capability_init(struct pci_dev *dev, int vector){    struct msi_desc *entry;    int pos, ret;    u16 control;    u8 bus = dev->bus;    u8 slot = PCI_SLOT(dev->devfn);    u8 func = PCI_FUNC(dev->devfn);    pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSI);    control = pci_conf_read16(bus, slot, func, msi_control_reg(pos));    /* MSI Entry Initialization */    msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */    entry = alloc_msi_entry();    if ( !entry )        return -ENOMEM;    entry->msi_attrib.type = PCI_CAP_ID_MSI;    entry->msi_attrib.is_64 = is_64bit_address(control);    entry->msi_attrib.entry_nr = 0;    entry->msi_attrib.maskbit = is_mask_bit_support(control);    entry->msi_attrib.masked = 1;    entry->msi_attrib.pos = pos;    entry->vector = vector;    if ( is_mask_bit_support(control) )        entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,                is_64bit_address(control));    entry->dev = dev;    if ( entry->msi_attrib.maskbit )    {        unsigned int maskbits, temp;        /* All MSIs are unmasked by default, Mask them all */        maskbits = pci_conf_read32(bus, slot, func,                       msi_mask_bits_reg(pos, is_64bit_address(control)));        temp = (1 << multi_msi_capable(control));        temp = ((temp - 1) & ~temp);        maskbits |= temp;        pci_conf_write32(bus, slot, func,            msi_mask_bits_reg(pos, is_64bit_address(control)),            maskbits);    }    list_add_tail(&entry->list, &dev->msi_list);    /* Configure MSI capability structure */    ret = setup_msi_irq(dev, entry);    if ( ret )    {        msi_free_vector(vector);        return ret;    }    /* Restore the original MSI enabled bits  */    pci_conf_write16(bus, slot, func, msi_control_reg(pos), control);    return 0;}/** * msix_capability_init - configure device's MSI-X capability * @dev: pointer to the pci_dev data structure of MSI-X device function * @entries: pointer to an array of struct msix_entry entries * @nvec: number of @entries * * Setup the MSI-X capability structure of device function with a * single MSI-X irq. A return of zero indicates the successful setup of * requested MSI-X entries with allocated irqs or non-zero for otherwise. **/static int msix_capability_init(struct pci_dev *dev, struct msi_info *msi){    struct msi_desc *entry;    int pos;    u16 control;    unsigned long phys_addr;    u32 table_offset;    u8 bir;    void __iomem *base;    int idx;    u8 bus = dev->bus;    u8 slot = PCI_SLOT(dev->devfn);    u8 func = PCI_FUNC(dev->devfn);    pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSIX);    control = pci_conf_read16(bus, slot, func, msix_control_reg(pos));    msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */    /* MSI-X Table Initialization */    entry = alloc_msi_entry();    if ( !entry )        return -ENOMEM;    /* Request & Map MSI-X table region */    table_offset = pci_conf_read32(bus, slot, func, msix_table_offset_reg(pos));    bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);    table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;    phys_addr = msi->table_base + table_offset;    idx = msix_fixmap_alloc();    if ( idx < 0 )    {        xfree(entry);        return -ENOMEM;    }    set_fixmap_nocache(idx, phys_addr);    base = (void *)(fix_to_virt(idx) + (phys_addr & ((1UL << PAGE_SHIFT) - 1)));    entry->msi_attrib.type = PCI_CAP_ID_MSIX;    entry->msi_attrib.is_64 = 1;    entry->msi_attrib.entry_nr = msi->entry_nr;    entry->msi_attrib.maskbit = 1;    entry->msi_attrib.masked = 1;    entry->msi_attrib.pos = pos;    entry->vector = msi->vector;    entry->dev = dev;    entry->mask_base = base;    list_add_tail(&entry->list, &dev->msi_list);    setup_msi_irq(dev, entry);    /* Set MSI-X enabled bits */    pci_conf_write16(bus, slot, func, msix_control_reg(pos), control);    return 0;}/** * pci_enable_msi - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function * * Setup the MSI capability structure of device function with * a single MSI irq upon its software driver call to request for * MSI mode enabled on its hardware device function. A return of zero * indicates the successful setup of an entry zero with the new MSI * irq or non-zero for otherwise. **/static int __pci_enable_msi(struct msi_info *msi){    int status;    struct pci_dev *pdev;    pdev = pci_lock_pdev(msi->bus, msi->devfn);    if ( !pdev )	return -ENODEV;    if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSI) )    {	spin_unlock(&pdev->lock);        dprintk(XENLOG_WARNING, "vector %d has already mapped to MSI on "            "device %02x:%02x.%01x.\n", msi->vector, msi->bus,            PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));        return 0;    }    status = msi_capability_init(pdev, msi->vector);    spin_unlock(&pdev->lock);    return status;}static void __pci_disable_msi(int vector){    struct msi_desc *entry;    struct pci_dev *dev;    int pos;    u16 control;    u8 bus, slot, func;    entry = irq_desc[vector].msi_desc;    if ( !entry )	return;    /*     * Lock here is safe.  msi_desc can not be removed without holding     * both irq_desc[].lock (which we do) and pdev->lock.     */    spin_lock(&entry->dev->lock);    dev = entry->dev;    bus = dev->bus;    slot = PCI_SLOT(dev->devfn);    func = PCI_FUNC(dev->devfn);    pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSI);    control = pci_conf_read16(bus, slot, func, msi_control_reg(pos));    msi_set_enable(dev, 0);    BUG_ON(list_empty(&dev->msi_list));    msi_free_vector(vector);    pci_conf_write16(bus, slot, func, msi_control_reg(pos), control);    spin_unlock(&dev->lock);}/** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function * @entries: pointer to an array of MSI-X entries * @nvec: number of MSI-X irqs requested for allocation by device driver * * Setup the MSI-X capability structure of device function with the number * of requested irqs upon its software driver call to request for * MSI-X mode enabled on its hardware device function. A return of zero * indicates the successful configuration of MSI-X capability structure * with new allocated MSI-X irqs. A return of < 0 indicates a failure. * Or a return of > 0 indicates that driver request is exceeding the number * of irqs available. Driver should use the returned value to re-send * its request. **/static int __pci_enable_msix(struct msi_info *msi){    int status, pos, nr_entries;    struct pci_dev *pdev;    u16 control;    u8 slot = PCI_SLOT(msi->devfn);    u8 func = PCI_FUNC(msi->devfn);    pdev = pci_lock_pdev(msi->bus, msi->devfn);    if ( !pdev )	return -ENODEV;    pos = pci_find_cap_offset(msi->bus, slot, func, PCI_CAP_ID_MSIX);    control = pci_conf_read16(msi->bus, slot, func, msi_control_reg(pos));    nr_entries = multi_msix_capable(control);    if (msi->entry_nr > nr_entries)    {	spin_unlock(&pdev->lock);        return -EINVAL;    }    if ( find_msi_entry(pdev, msi->vector, PCI_CAP_ID_MSIX) )    {	spin_unlock(&pdev->lock);        dprintk(XENLOG_WARNING, "vector %d has already mapped to MSIX on "                "device %02x:%02x.%01x.\n", msi->vector, msi->bus,                PCI_SLOT(msi->devfn), PCI_FUNC(msi->devfn));        return 0;    }    status = msix_capability_init(pdev, msi);    spin_unlock(&pdev->lock);    return status;}static void __pci_disable_msix(int vector){    struct msi_desc *entry;    struct pci_dev *dev;    int pos;    u16 control;    u8 bus, slot, func;    entry = irq_desc[vector].msi_desc;    if ( !entry )	return;    /*     * Lock here is safe.  msi_desc can not be removed without holding     * both irq_desc[].lock (which we do) and pdev->lock.     */    spin_lock(&entry->dev->lock);    dev = entry->dev;    bus = dev->bus;    slot = PCI_SLOT(dev->devfn);    func = PCI_FUNC(dev->devfn);    pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSIX);    control = pci_conf_read16(bus, slot, func, msix_control_reg(pos));    msi_set_enable(dev, 0);    BUG_ON(list_empty(&dev->msi_list));    msi_free_vector(vector);    pci_conf_write16(bus, slot, func, msix_control_reg(pos), control);    spin_unlock(&dev->lock);}int pci_enable_msi(struct msi_info *msi){    ASSERT(spin_is_locked(&irq_desc[msi->vector].lock));    return  msi->table_base ? __pci_enable_msix(msi) :                              __pci_enable_msi(msi);}void pci_disable_msi(int vector){    irq_desc_t *desc = &irq_desc[vector];    ASSERT(spin_is_locked(&desc->lock));    if ( !desc->msi_desc )	return;    if ( desc->msi_desc->msi_attrib.type == PCI_CAP_ID_MSI )        __pci_disable_msi(vector);    else if ( desc->msi_desc->msi_attrib.type == PCI_CAP_ID_MSIX )        __pci_disable_msix(vector);}extern struct hw_interrupt_type pci_msi_type;static void msi_free_vectors(struct pci_dev* dev){    struct msi_desc *entry, *tmp;    irq_desc_t *desc;    unsigned long flags;retry:    list_for_each_entry_safe( entry, tmp, &dev->msi_list, list )    {        desc = &irq_desc[entry->vector];        local_irq_save(flags);        if ( !spin_trylock(&desc->lock) )        {             local_irq_restore(flags);            goto retry;        }        if ( desc->handler == &pci_msi_type )        {            /* MSI is not shared, so should be released already */            BUG_ON(desc->status & IRQ_GUEST);            desc->handler = &no_irq_type;        }        msi_free_vector(entry->vector);        spin_unlock_irqrestore(&desc->lock, flags);    }}void pci_cleanup_msi(struct pci_dev *pdev){    /* Disable MSI and/or MSI-X */    msi_set_enable(pdev, 0);    msix_set_enable(pdev, 0);    msi_free_vectors(pdev);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?