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