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 + -
显示快捷键?