⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pt-msi.c

📁 xen虚拟机源代码安装包
💻 C
字号:
/* * Copyright (c) 2007, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Jiang Yunhong <yunhong.jiang@intel.com> * * This file implements direct PCI assignment to a HVM guest */#include "pt-msi.h"#include <sys/mman.h>/* MSI virtuailization functions *//* * setup physical msi, but didn't enable it */int pt_msi_setup(struct pt_dev *dev){    int pirq = -1;    if ( !(dev->msi->flags & MSI_FLAG_UNINIT) )    {        PT_LOG("setup physical after initialized?? \n");        return -1;    }    if ( xc_physdev_map_pirq_msi(xc_handle, domid, AUTO_ASSIGN, &pirq,                                 dev->pci_dev->dev << 3 | dev->pci_dev->func,                                 dev->pci_dev->bus, 0, 0) )    {        PT_LOG("error map msi\n");        return -1;    }    if ( pirq < 0 )    {        PT_LOG("invalid pirq number\n");        return -1;    }    dev->msi->pirq = pirq;    PT_LOG("msi mapped with pirq %x\n", pirq);    return 0;}uint32_t __get_msi_gflags(uint32_t data, uint64_t addr){    uint32_t result = 0;    int rh, dm, dest_id, deliv_mode, trig_mode;    rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;    dm = (addr >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;    dest_id = (addr >> MSI_TARGET_CPU_SHIFT) & 0xff;    deliv_mode = (data >> MSI_DATA_DELIVERY_SHIFT) & 0x7;    trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;    result |= dest_id | (rh << GFLAGS_SHIFT_RH) | (dm << GFLAGS_SHIFT_DM) | \                (deliv_mode << GLFAGS_SHIFT_DELIV_MODE) |                (trig_mode << GLFAGS_SHIFT_TRG_MODE);    return result;}/* * Update msi mapping, usually called when MSI enabled, * except the first time */int pt_msi_update(struct pt_dev *d){    uint8_t gvec = 0;    uint32_t gflags = 0;    uint64_t addr = 0;        /* get vector, address, flags info, etc. */    gvec = d->msi->data & 0xFF;    addr = (uint64_t)d->msi->addr_hi << 32 | d->msi->addr_lo;    gflags = __get_msi_gflags(d->msi->data, addr);        PT_LOG("now update msi with pirq %x gvec %x\n", d->msi->pirq, gvec);    return xc_domain_update_msi_irq(xc_handle, domid, gvec,                                     d->msi->pirq, gflags);}/* MSI-X virtulization functions */static void mask_physical_msix_entry(struct pt_dev *dev, int entry_nr, int mask){    void *phys_off;    phys_off = dev->msix->phys_iomem_base + 16 * entry_nr + 12;    *(uint32_t *)phys_off = mask;}static int pt_msix_update_one(struct pt_dev *dev, int entry_nr){    struct msix_entry_info *entry = &dev->msix->msix_entry[entry_nr];    int pirq = entry->pirq;    int gvec = entry->io_mem[2] & 0xff;    uint64_t gaddr = *(uint64_t *)&entry->io_mem[0];    uint32_t gflags = __get_msi_gflags(entry->io_mem[2], gaddr);    int ret;    if ( !entry->flags )        return 0;    /* Check if this entry is already mapped */    if ( entry->pirq == -1 )    {        ret = xc_physdev_map_pirq_msi(xc_handle, domid, AUTO_ASSIGN, &pirq,                                dev->pci_dev->dev << 3 | dev->pci_dev->func,                                dev->pci_dev->bus, entry_nr,                                dev->msix->table_base);        if ( ret )        {            PT_LOG("error map msix entry %x\n", entry_nr);            return ret;        }        entry->pirq = pirq;    }    PT_LOG("now update msix entry %x with pirq %x gvec %x\n",            entry_nr, pirq, gvec);    ret = xc_domain_update_msi_irq(xc_handle, domid, gvec, pirq, gflags);    if ( ret )    {        PT_LOG("error update msix irq info for entry %d\n", entry_nr);        return ret;    }    entry->flags = 0;    return 0;}int pt_msix_update(struct pt_dev *dev){    struct pt_msix_info *msix = dev->msix;    int i;    for ( i = 0; i < msix->total_entries; i++ )    {        pt_msix_update_one(dev, i);    }    return 0;}static void pci_msix_invalid_write(void *opaque, target_phys_addr_t addr,                                   uint32_t val){    PT_LOG("invalid write to MSI-X table, \            only dword access is allowed.\n");}static void pci_msix_writel(void *opaque, target_phys_addr_t addr, uint32_t val){    struct pt_dev *dev = (struct pt_dev *)opaque;    struct pt_msix_info *msix = dev->msix;    struct msix_entry_info *entry;    int entry_nr, offset;    if ( addr % 4 )    {        PT_LOG("unaligned dword access to MSI-X table, addr %016lx\n",                addr);        return;    }    entry_nr = (addr - msix->mmio_base_addr) / 16;    entry = &msix->msix_entry[entry_nr];    offset = ((addr - msix->mmio_base_addr) % 16) / 4;    if ( offset != 3 && msix->enabled && !(entry->io_mem[3] & 0x1) )    {        PT_LOG("can not update msix entry %d since MSI-X is already \                function now.\n", entry_nr);        return;    }    if ( offset != 3 && entry->io_mem[offset] != val )        entry->flags = 1;    entry->io_mem[offset] = val;    if ( offset == 3 )    {        if ( msix->enabled && !(val & 0x1) )            pt_msix_update_one(dev, entry_nr);        mask_physical_msix_entry(dev, entry_nr, entry->io_mem[3] & 0x1);    }}static CPUWriteMemoryFunc *pci_msix_write[] = {    pci_msix_invalid_write,    pci_msix_invalid_write,    pci_msix_writel};static uint32_t pci_msix_invalid_read(void *opaque, target_phys_addr_t addr){    PT_LOG("invalid read to MSI-X table, \            only dword access is allowed.\n");    return 0;}static uint32_t pci_msix_readl(void *opaque, target_phys_addr_t addr){    struct pt_dev *dev = (struct pt_dev *)opaque;    struct pt_msix_info *msix = dev->msix;    int entry_nr, offset;    if ( addr % 4 )    {        PT_LOG("unaligned dword access to MSI-X table, addr %016lx\n",                addr);        return 0;    }    entry_nr = (addr - msix->mmio_base_addr) / 16;    offset = ((addr - msix->mmio_base_addr) % 16) / 4;    return msix->msix_entry[entry_nr].io_mem[offset];}static CPUReadMemoryFunc *pci_msix_read[] = {    pci_msix_invalid_read,    pci_msix_invalid_read,    pci_msix_readl};int add_msix_mapping(struct pt_dev *dev, int bar_index){    if ( !(dev->msix && dev->msix->bar_index == bar_index) )        return 0;    return xc_domain_memory_mapping(xc_handle, domid,                dev->msix->mmio_base_addr >> XC_PAGE_SHIFT,                (dev->bases[bar_index].access.maddr                + dev->msix->table_off) >> XC_PAGE_SHIFT,                (dev->msix->total_entries * 16                + XC_PAGE_SIZE -1) >> XC_PAGE_SHIFT,                DPCI_ADD_MAPPING);}int remove_msix_mapping(struct pt_dev *dev, int bar_index){    if ( !(dev->msix && dev->msix->bar_index == bar_index) )        return 0;    dev->msix->mmio_base_addr = dev->bases[bar_index].e_physbase                                + dev->msix->table_off;    cpu_register_physical_memory(dev->msix->mmio_base_addr,                                 dev->msix->total_entries * 16,                                 dev->msix->mmio_index);    return xc_domain_memory_mapping(xc_handle, domid,                dev->msix->mmio_base_addr >> XC_PAGE_SHIFT,                (dev->bases[bar_index].access.maddr                + dev->msix->table_off) >> XC_PAGE_SHIFT,                (dev->msix->total_entries * 16                + XC_PAGE_SIZE -1) >> XC_PAGE_SHIFT,                DPCI_REMOVE_MAPPING);}int pt_msix_init(struct pt_dev *dev, int pos){    uint8_t id;    uint16_t control;    int i, total_entries, table_off, bar_index;    struct pci_dev *pd = dev->pci_dev;    id = pci_read_byte(pd, pos + PCI_CAP_LIST_ID);    if ( id != PCI_CAP_ID_MSIX )    {        PT_LOG("error id %x pos %x\n", id, pos);        return -1;    }    control = pci_read_word(pd, pos + 2);    total_entries = control & 0x7ff;    total_entries += 1;    dev->msix = malloc(sizeof(struct pt_msix_info)                       + total_entries*sizeof(struct msix_entry_info));    if ( !dev->msix )    {        PT_LOG("error allocation pt_msix_info\n");        return -1;    }    memset(dev->msix, 0, sizeof(struct pt_msix_info)                         + total_entries*sizeof(struct msix_entry_info));    dev->msix->total_entries = total_entries;    for ( i = 0; i < total_entries; i++ )        dev->msix->msix_entry[i].pirq = -1;    dev->msix->mmio_index =        cpu_register_io_memory(0, pci_msix_read, pci_msix_write, dev);    table_off = pci_read_long(pd, pos + PCI_MSIX_TABLE);    bar_index = dev->msix->bar_index = table_off & PCI_MSIX_BIR;    table_off &= table_off & ~PCI_MSIX_BIR;    dev->msix->table_base = dev->pci_dev->base_addr[bar_index];    PT_LOG("get MSI-X table bar base %llx\n",           (unsigned long long)dev->msix->table_base);    dev->msix->fd = open("/dev/mem", O_RDWR);    dev->msix->phys_iomem_base = mmap(0, total_entries * 16,                          PROT_WRITE | PROT_READ, MAP_SHARED | MAP_LOCKED,                          dev->msix->fd, dev->msix->table_base + table_off);    PT_LOG("mapping physical MSI-X table to %lx\n",           (unsigned long)dev->msix->phys_iomem_base);    return 0;}void pt_msix_delete(struct pt_dev *dev){    /* unmap the MSI-X memory mapped register area */    if (dev->msix->phys_iomem_base)    {        PT_LOG("unmapping physical MSI-X table from %lx\n",           (unsigned long)dev->msix->phys_iomem_base);        munmap(dev->msix->phys_iomem_base, dev->msix->total_entries * 16);    }    free(dev->msix);}

⌨️ 快捷键说明

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