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

📄 iommu_intr.c

📁 xen虚拟机源代码安装包
💻 C
字号:
/* * Copyright (C) 2007 Advanced Micro Devices, Inc. * Author: Wei Wang <wei.wang2@amd.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that 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 */#include <xen/sched.h>#include <xen/hvm/iommu.h>#include <asm/amd-iommu.h>#include <asm/hvm/svm/amd-iommu-proto.h>DEFINE_SPINLOCK(int_remap_table_lock);void *int_remap_table = NULL;static u8 *get_intremap_entry(u8 vector, u8 dm){    u8 *table;    int offset = 0;    table = (u8*)int_remap_table;    BUG_ON( !table );    offset = (dm << INT_REMAP_INDEX_DM_SHIFT) & INT_REMAP_INDEX_DM_MASK;    offset |= (vector << INT_REMAP_INDEX_VECTOR_SHIFT ) &         INT_REMAP_INDEX_VECTOR_MASK;    return (u8*) (table + offset);}static void update_intremap_entry(u32* entry, u8 vector, u8 int_type,    u8 dest_mode, u8 dest){    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,                            INT_REMAP_ENTRY_REMAPEN_MASK,                            INT_REMAP_ENTRY_REMAPEN_SHIFT, entry);    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, *entry,                            INT_REMAP_ENTRY_SUPIOPF_MASK,                            INT_REMAP_ENTRY_SUPIOPF_SHIFT, entry);    set_field_in_reg_u32(int_type, *entry,                            INT_REMAP_ENTRY_INTTYPE_MASK,                            INT_REMAP_ENTRY_INTTYPE_SHIFT, entry);    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, *entry,                            INT_REMAP_ENTRY_REQEOI_MASK,                            INT_REMAP_ENTRY_REQEOI_SHIFT, entry);    set_field_in_reg_u32((u32)dest_mode, *entry,                            INT_REMAP_ENTRY_DM_MASK,                            INT_REMAP_ENTRY_DM_SHIFT, entry);    set_field_in_reg_u32((u32)dest, *entry,                            INT_REMAP_ENTRY_DEST_MAST,                            INT_REMAP_ENTRY_DEST_SHIFT, entry);    set_field_in_reg_u32((u32)vector, *entry,                            INT_REMAP_ENTRY_VECTOR_MASK,                            INT_REMAP_ENTRY_VECTOR_SHIFT, entry);}void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id){    u32 cmd[4], entry;    cmd[3] = cmd[2] = 0;    set_field_in_reg_u32(device_id, 0,                         IOMMU_INV_INT_TABLE_DEVICE_ID_MASK,                         IOMMU_INV_INT_TABLE_DEVICE_ID_SHIFT, &entry);    cmd[0] = entry;    set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_INT_TABLE, 0,                         IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT,                         &entry);    cmd[1] = entry;    send_iommu_command(iommu, cmd);}static void update_intremap_entry_from_ioapic(    struct IO_APIC_route_entry *ioapic_rte,    unsigned int rte_upper, unsigned int value){    unsigned long flags;    u32* entry;    u8 delivery_mode, dest, vector, dest_mode;    struct IO_APIC_route_entry *rte = ioapic_rte;    spin_lock_irqsave(&int_remap_table_lock, flags);    if ( rte_upper )    {        dest = (value >> 24) & 0xFF;        delivery_mode = rte->delivery_mode;        vector = rte->vector;        dest_mode = rte->dest_mode;        entry = (u32*)get_intremap_entry((u8)rte->vector,                                        (u8)rte->delivery_mode);        update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);    }    spin_unlock_irqrestore(&int_remap_table_lock, flags);    return;}int __init amd_iommu_setup_intremap_table(void){    unsigned long flags;    spin_lock_irqsave(&int_remap_table_lock, flags);    if ( int_remap_table == NULL )        int_remap_table = (void *)alloc_xenheap_pages(1);    if ( !int_remap_table )    {        spin_unlock_irqrestore(&int_remap_table_lock, flags);        return -ENOMEM;    }    memset((u8*)int_remap_table, 0, PAGE_SIZE*2);    spin_unlock_irqrestore(&int_remap_table_lock, flags);    return 0;}void amd_iommu_ioapic_update_ire(    unsigned int apic, unsigned int reg, unsigned int value){    struct IO_APIC_route_entry ioapic_rte = { 0 };    unsigned int rte_upper = (reg & 1) ? 1 : 0;    int saved_mask;    *IO_APIC_BASE(apic) = reg;    *(IO_APIC_BASE(apic)+4) = value;    if ( int_remap_table == NULL )        return;    if ( !rte_upper )        return;    reg--;    /* read both lower and upper 32-bits of rte entry */    *IO_APIC_BASE(apic) = reg;    *(((u32 *)&ioapic_rte) + 0) = *(IO_APIC_BASE(apic)+4);    *IO_APIC_BASE(apic) = reg + 1;    *(((u32 *)&ioapic_rte) + 1) = *(IO_APIC_BASE(apic)+4);    /* mask the interrupt while we change the intremap table */    saved_mask = ioapic_rte.mask;    ioapic_rte.mask = 1;    *IO_APIC_BASE(apic) = reg;    *(IO_APIC_BASE(apic)+4) = *(((int *)&ioapic_rte)+0);    ioapic_rte.mask = saved_mask;    update_intremap_entry_from_ioapic(&ioapic_rte, rte_upper, value);    /* unmask the interrupt after we have updated the intremap table */    *IO_APIC_BASE(apic) = reg;    *(IO_APIC_BASE(apic)+4) = *(((u32 *)&ioapic_rte)+0);}static void update_intremap_entry_from_msi_msg(    struct amd_iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg){    unsigned long flags;    u32* entry;    u16 dev_id;    u8 delivery_mode, dest, vector, dest_mode;    dev_id = (pdev->bus << 8) | pdev->devfn;    spin_lock_irqsave(&int_remap_table_lock, flags);    dest_mode = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;    delivery_mode = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1;    vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK;    dest = (msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff;    entry = (u32*)get_intremap_entry((u8)vector, (u8)delivery_mode);    update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);    spin_unlock_irqrestore(&int_remap_table_lock, flags);    spin_lock_irqsave(&iommu->lock, flags);    invalidate_interrupt_table(iommu, dev_id);    flush_command_buffer(iommu);    spin_unlock_irqrestore(&iommu->lock, flags);    return;}void amd_iommu_msi_msg_update_ire(    struct msi_desc *msi_desc, struct msi_msg *msg){    struct pci_dev *pdev = msi_desc->dev;    struct amd_iommu *iommu = NULL;    iommu = find_iommu_for_device(pdev->bus, pdev->devfn);    if ( !iommu || !int_remap_table )        return;    update_intremap_entry_from_msi_msg(iommu, pdev, msg);}int __init deallocate_intremap_table(void){    unsigned long flags;    spin_lock_irqsave(&int_remap_table_lock, flags);    if ( int_remap_table )    {        free_xenheap_pages(int_remap_table, 1);        int_remap_table = NULL;    }    spin_unlock_irqrestore(&int_remap_table_lock, flags);    return 0;}

⌨️ 快捷键说明

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