msi.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 769 行 · 第 1/2 页
C
769 行
/* * File: msi.c * Purpose: PCI Message Signaled Interrupt (MSI) * * Copyright (C) 2003-2004 Intel * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) */#include <xen/config.h>#include <xen/lib.h>#include <xen/init.h>#include <xen/irq.h>#include <xen/delay.h>#include <xen/sched.h>#include <xen/acpi.h>#include <xen/errno.h>#include <xen/pci.h>#include <xen/pci_regs.h>#include <xen/keyhandler.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/desc.h>#include <asm/msi.h>#include <asm/fixmap.h>#include <mach_apic.h>#include <io_ports.h>#include <public/physdev.h>#include <xen/iommu.h>/* bitmap indicate which fixed map is free */DEFINE_SPINLOCK(msix_fixmap_lock);DECLARE_BITMAP(msix_fixmap_pages, MAX_MSIX_PAGES);static int msix_fixmap_alloc(void){ int i; int rc = -1; spin_lock(&msix_fixmap_lock); for ( i = 0; i < MAX_MSIX_PAGES; i++ ) if ( !test_bit(i, &msix_fixmap_pages) ) break; if ( i == MAX_MSIX_PAGES ) goto out; rc = FIX_MSIX_IO_RESERV_BASE + i; set_bit(i, &msix_fixmap_pages); out: spin_unlock(&msix_fixmap_lock); return rc;}static void msix_fixmap_free(int idx){ if ( idx < FIX_MSIX_IO_RESERV_BASE ) return; spin_lock(&msix_fixmap_lock); clear_bit(idx - FIX_MSIX_IO_RESERV_BASE, &msix_fixmap_pages); spin_unlock(&msix_fixmap_lock);}/* * MSI message composition */static void msi_compose_msg(struct pci_dev *pdev, int vector, struct msi_msg *msg){ unsigned dest; cpumask_t tmp; tmp = TARGET_CPUS; if ( vector ) { dest = cpu_mask_to_apicid(tmp); msg->address_hi = MSI_ADDR_BASE_HI; msg->address_lo = MSI_ADDR_BASE_LO | ((INT_DEST_MODE == 0) ? MSI_ADDR_DESTMODE_PHYS: MSI_ADDR_DESTMODE_LOGIC) | ((INT_DELIVERY_MODE != dest_LowestPrio) ? MSI_ADDR_REDIRECTION_CPU: MSI_ADDR_REDIRECTION_LOWPRI) | MSI_ADDR_DEST_ID(dest); msg->data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | ((INT_DELIVERY_MODE != dest_LowestPrio) ? MSI_DATA_DELIVERY_FIXED: MSI_DATA_DELIVERY_LOWPRI) | MSI_DATA_VECTOR(vector); }}static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg){ switch ( entry->msi_attrib.type ) { case PCI_CAP_ID_MSI: { struct pci_dev *dev = entry->dev; int pos = entry->msi_attrib.pos; u16 data; u8 bus = dev->bus; u8 slot = PCI_SLOT(dev->devfn); u8 func = PCI_FUNC(dev->devfn); msg->address_lo = pci_conf_read32(bus, slot, func, msi_lower_address_reg(pos)); if ( entry->msi_attrib.is_64 ) { msg->address_hi = pci_conf_read32(bus, slot, func, msi_upper_address_reg(pos)); data = pci_conf_read16(bus, slot, func, msi_data_reg(pos, 1)); } else { msg->address_hi = 0; data = pci_conf_read16(bus, slot, func, msi_data_reg(pos, 0)); } msg->data = data; break; } case PCI_CAP_ID_MSIX: { void __iomem *base; base = entry->mask_base + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); break; } default: BUG(); } if ( vtd_enabled ) msi_msg_read_remap_rte(entry, msg);}static int set_vector_msi(struct msi_desc *entry){ if ( entry->vector >= NR_VECTORS ) { dprintk(XENLOG_ERR, "Trying to install msi data for Vector %d\n", entry->vector); return -EINVAL; } irq_desc[entry->vector].msi_desc = entry; return 0;}static int unset_vector_msi(int vector){ if ( vector >= NR_VECTORS ) { dprintk(XENLOG_ERR, "Trying to uninstall msi data for Vector %d\n", vector); return -EINVAL; } irq_desc[vector].msi_desc = NULL; return 0;}static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg){ if ( iommu_enabled ) iommu_update_ire_from_msi(entry, msg); switch ( entry->msi_attrib.type ) { case PCI_CAP_ID_MSI: { struct pci_dev *dev = entry->dev; int pos = entry->msi_attrib.pos; u8 bus = dev->bus; u8 slot = PCI_SLOT(dev->devfn); u8 func = PCI_FUNC(dev->devfn); pci_conf_write32(bus, slot, func, msi_lower_address_reg(pos), msg->address_lo); if ( entry->msi_attrib.is_64 ) { pci_conf_write32(bus, slot, func, msi_upper_address_reg(pos), msg->address_hi); pci_conf_write16(bus, slot, func, msi_data_reg(pos, 1), msg->data); } else pci_conf_write16(bus, slot, func, msi_data_reg(pos, 0), msg->data); break; } case PCI_CAP_ID_MSIX: { void __iomem *base; base = entry->mask_base + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); break; } default: BUG(); } entry->msg = *msg;}void set_msi_irq_affinity(unsigned int irq, cpumask_t mask){ struct msi_desc *desc = irq_desc[irq].msi_desc; struct msi_msg msg; unsigned int dest; memset(&msg, 0, sizeof(msg)); cpus_and(mask, mask, cpu_online_map); if ( cpus_empty(mask) ) mask = TARGET_CPUS; dest = cpu_mask_to_apicid(mask); if ( !desc ) return; ASSERT(spin_is_locked(&irq_desc[irq].lock)); spin_lock(&desc->dev->lock); read_msi_msg(desc, &msg); msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; msg.address_lo |= MSI_ADDR_DEST_ID(dest); write_msi_msg(desc, &msg); spin_unlock(&desc->dev->lock);}static void msi_set_enable(struct pci_dev *dev, int enable){ int pos; 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); if ( pos ) { control = pci_conf_read16(bus, slot, func, pos + PCI_MSI_FLAGS); control &= ~PCI_MSI_FLAGS_ENABLE; if ( enable ) control |= PCI_MSI_FLAGS_ENABLE; pci_conf_write16(bus, slot, func, pos + PCI_MSI_FLAGS, control); }}static void msix_set_enable(struct pci_dev *dev, int enable){ int pos; 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_MSIX); if ( pos ) { control = pci_conf_read16(bus, slot, func, pos + PCI_MSIX_FLAGS); control &= ~PCI_MSIX_FLAGS_ENABLE; if ( enable ) control |= PCI_MSIX_FLAGS_ENABLE; pci_conf_write16(bus, slot, func, pos + PCI_MSIX_FLAGS, control); }}static void msix_flush_writes(unsigned int irq){ struct msi_desc *entry = irq_desc[irq].msi_desc; BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: /* nothing to do */ break; case PCI_CAP_ID_MSIX: { int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; readl(entry->mask_base + offset); break; } default: BUG(); break; }}static void msi_set_mask_bit(unsigned int irq, int flag){ struct msi_desc *entry = irq_desc[irq].msi_desc; ASSERT(spin_is_locked(&irq_desc[irq].lock)); BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: if (entry->msi_attrib.maskbit) { int pos; u32 mask_bits; u8 bus = entry->dev->bus; u8 slot = PCI_SLOT(entry->dev->devfn); u8 func = PCI_FUNC(entry->dev->devfn); pos = (long)entry->mask_base; mask_bits = pci_conf_read32(bus, slot, func, pos); mask_bits &= ~(1); mask_bits |= flag; pci_conf_write32(bus, slot, func, pos, mask_bits); } else { msi_set_enable(entry->dev, !flag); } break; case PCI_CAP_ID_MSIX: { int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; writel(flag, entry->mask_base + offset); readl(entry->mask_base + offset); break; } default: BUG(); break; } entry->msi_attrib.masked = !!flag;}void mask_msi_irq(unsigned int irq){ msi_set_mask_bit(irq, 1); msix_flush_writes(irq);}void unmask_msi_irq(unsigned int irq){ msi_set_mask_bit(irq, 0); msix_flush_writes(irq);}static struct msi_desc* alloc_msi_entry(void){ struct msi_desc *entry; entry = xmalloc(struct msi_desc); if ( !entry ) return NULL; INIT_LIST_HEAD(&entry->list); entry->dev = NULL; return entry;}static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc){ struct msi_msg msg; msi_compose_msg(dev, desc->vector, &msg); set_vector_msi(desc); write_msi_msg(irq_desc[desc->vector].msi_desc, &msg); return 0;}static void teardown_msi_vector(int vector){ unset_vector_msi(vector);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?