📄 intremap.c
字号:
struct iommu *iommu, struct msi_msg *msg){ struct iremap_entry *iremap_entry = NULL, *iremap_entries; struct msi_msg_remap_entry *remap_rte; int index; unsigned long flags; struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); if ( ir_ctrl == NULL ) { dprintk(XENLOG_ERR VTDPREFIX, "remap_entry_to_msi_msg: ir_ctl == NULL"); return; } remap_rte = (struct msi_msg_remap_entry *) msg; index = (remap_rte->address_lo.index_15 << 15) | remap_rte->address_lo.index_0_14; if ( index > ir_ctrl->iremap_index ) panic("%s: index (%d) is larger than remap table entry size (%d)\n", __func__, index, ir_ctrl->iremap_index); spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); iremap_entries = (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); iremap_entry = &iremap_entries[index]; msg->address_hi = MSI_ADDR_BASE_HI; msg->address_lo = MSI_ADDR_BASE_LO | ((iremap_entry->lo.dm == 0) ? MSI_ADDR_DESTMODE_PHYS: MSI_ADDR_DESTMODE_LOGIC) | ((iremap_entry->lo.dlm != dest_LowestPrio) ? MSI_ADDR_REDIRECTION_CPU: MSI_ADDR_REDIRECTION_LOWPRI) | iremap_entry->lo.dst >> 8; msg->data = MSI_DATA_TRIGGER_EDGE | MSI_DATA_LEVEL_ASSERT | ((iremap_entry->lo.dlm != dest_LowestPrio) ? MSI_DATA_DELIVERY_FIXED: MSI_DATA_DELIVERY_LOWPRI) | iremap_entry->lo.vector; unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags);}static void msi_msg_to_remap_entry( struct iommu *iommu, struct pci_dev *pdev, struct msi_msg *msg){ struct iremap_entry *iremap_entry = NULL, *iremap_entries; struct iremap_entry new_ire; struct msi_msg_remap_entry *remap_rte; unsigned int index; unsigned long flags; struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); int i = 0; remap_rte = (struct msi_msg_remap_entry *) msg; spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); iremap_entries = (struct iremap_entry *)map_vtd_domain_page(ir_ctrl->iremap_maddr); /* If the entry for a PCI device has been there, use the old entry, * Or, assign a new entry for it. */ for ( i = 0; i <= ir_ctrl->iremap_index; i++ ) { iremap_entry = &iremap_entries[i]; if ( iremap_entry->hi.sid == ((pdev->bus << 8) | pdev->devfn) ) break; } if ( i > ir_ctrl->iremap_index ) { ir_ctrl->iremap_index++; index = ir_ctrl->iremap_index; } else index = i; if ( index > IREMAP_ENTRY_NR - 1 ) panic("msi_msg_to_remap_entry: intremap index is more than 256!\n"); iremap_entry = &iremap_entries[index]; memcpy(&new_ire, iremap_entry, sizeof(struct iremap_entry)); /* Set interrupt remapping table entry */ new_ire.lo.fpd = 0; new_ire.lo.dm = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1; new_ire.lo.rh = 0; new_ire.lo.tm = (msg->data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; new_ire.lo.dlm = (msg->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x1; new_ire.lo.avail = 0; new_ire.lo.res_1 = 0; new_ire.lo.vector = (msg->data >> MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK; new_ire.lo.res_2 = 0; new_ire.lo.dst = ((msg->address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff) << 8; new_ire.hi.sid = (pdev->bus << 8) | pdev->devfn; new_ire.hi.sq = 0; new_ire.hi.svt = 1; new_ire.hi.res_1 = 0; new_ire.lo.p = 1; /* finally, set present bit */ /* now construct new MSI/MSI-X rte entry */ remap_rte->address_lo.dontcare = 0; remap_rte->address_lo.index_15 = (index >> 15) & 0x1; remap_rte->address_lo.index_0_14 = index & 0x7fff; remap_rte->address_lo.SHV = 1; remap_rte->address_lo.format = 1; remap_rte->address_hi = 0; remap_rte->data = 0; memcpy(iremap_entry, &new_ire, sizeof(struct iremap_entry)); iommu_flush_cache_entry(iremap_entry); iommu_flush_iec_index(iommu, 0, index); invalidate_sync(iommu); unmap_vtd_domain_page(iremap_entries); spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); return;}void msi_msg_read_remap_rte( struct msi_desc *msi_desc, struct msi_msg *msg){ struct pci_dev *pdev = msi_desc->dev; struct acpi_drhd_unit *drhd = NULL; struct iommu *iommu = NULL; struct ir_ctrl *ir_ctrl; drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn); iommu = drhd->iommu; ir_ctrl = iommu_ir_ctrl(iommu); if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) return; remap_entry_to_msi_msg(iommu, msg);}void msi_msg_write_remap_rte( struct msi_desc *msi_desc, struct msi_msg *msg){ struct pci_dev *pdev = msi_desc->dev; struct acpi_drhd_unit *drhd = NULL; struct iommu *iommu = NULL; struct ir_ctrl *ir_ctrl; drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn); iommu = drhd->iommu; ir_ctrl = iommu_ir_ctrl(iommu); if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ) return; msi_msg_to_remap_entry(iommu, pdev, msg);}int intremap_setup(struct iommu *iommu){ struct ir_ctrl *ir_ctrl; s_time_t start_time; if ( !ecap_intr_remap(iommu->ecap) ) return -ENODEV; ir_ctrl = iommu_ir_ctrl(iommu); if ( ir_ctrl->iremap_maddr == 0 ) { ir_ctrl->iremap_maddr = alloc_pgtable_maddr(); if ( ir_ctrl->iremap_maddr == 0 ) { dprintk(XENLOG_WARNING VTDPREFIX, "Cannot allocate memory for ir_ctrl->iremap_maddr\n"); return -ENODEV; } ir_ctrl->iremap_index = -1; }#if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT) /* set extended interrupt mode bit */ ir_ctrl->iremap_maddr |= ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIMI_SHIFT) : 0;#endif /* size field = 256 entries per 4K page = 8 - 1 */ ir_ctrl->iremap_maddr |= 7; dmar_writeq(iommu->reg, DMAR_IRTA_REG, ir_ctrl->iremap_maddr); /* set SIRTP */ iommu->gcmd |= DMA_GCMD_SIRTP; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); /* Make sure hardware complete it */ start_time = NOW(); while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) ) { if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) { dprintk(XENLOG_ERR VTDPREFIX, "Cannot set SIRTP field for interrupt remapping\n"); return -ENODEV; } cpu_relax(); } /* enable comaptiblity format interrupt pass through */ iommu->gcmd |= DMA_GCMD_CFI; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); start_time = NOW(); while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) ) { if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) { dprintk(XENLOG_ERR VTDPREFIX, "Cannot set CFI field for interrupt remapping\n"); return -ENODEV; } cpu_relax(); } /* enable interrupt remapping hardware */ iommu->gcmd |= DMA_GCMD_IRE; dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); start_time = NOW(); while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) ) { if ( NOW() > (start_time + DMAR_OPERATION_TIMEOUT) ) { dprintk(XENLOG_ERR VTDPREFIX, "Cannot set IRE field for interrupt remapping\n"); return -ENODEV; } cpu_relax(); } /* After set SIRTP, we should do globally invalidate the IEC */ iommu_flush_iec_global(iommu); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -