Skip to content

Commit fd73000

Browse files
Kyung Min Parkjoergroedel
authored andcommitted
iommu/vt-d: Add Scalable Mode fault information
Intel VT-d specification revision 3 added support for Scalable Mode Translation for DMA remapping. Add the Scalable Mode fault reasons to show detailed fault reasons when the translation fault happens. Link: https://software.intel.com/sites/default/files/managed/c5/15/vt-directed-io-spec.pdf Reviewed-by: Sohil Mehta <[email protected]> Signed-off-by: Kyung Min Park <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent cfb94a3 commit fd73000

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

drivers/iommu/dmar.c

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,64 @@ static const char *dma_remap_fault_reasons[] =
15191519
"PCE for translation request specifies blocking",
15201520
};
15211521

1522+
static const char * const dma_remap_sm_fault_reasons[] = {
1523+
"SM: Invalid Root Table Address",
1524+
"SM: TTM 0 for request with PASID",
1525+
"SM: TTM 0 for page group request",
1526+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x33-0x37 */
1527+
"SM: Error attempting to access Root Entry",
1528+
"SM: Present bit in Root Entry is clear",
1529+
"SM: Non-zero reserved field set in Root Entry",
1530+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x3B-0x3F */
1531+
"SM: Error attempting to access Context Entry",
1532+
"SM: Present bit in Context Entry is clear",
1533+
"SM: Non-zero reserved field set in the Context Entry",
1534+
"SM: Invalid Context Entry",
1535+
"SM: DTE field in Context Entry is clear",
1536+
"SM: PASID Enable field in Context Entry is clear",
1537+
"SM: PASID is larger than the max in Context Entry",
1538+
"SM: PRE field in Context-Entry is clear",
1539+
"SM: RID_PASID field error in Context-Entry",
1540+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x49-0x4F */
1541+
"SM: Error attempting to access the PASID Directory Entry",
1542+
"SM: Present bit in Directory Entry is clear",
1543+
"SM: Non-zero reserved field set in PASID Directory Entry",
1544+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x53-0x57 */
1545+
"SM: Error attempting to access PASID Table Entry",
1546+
"SM: Present bit in PASID Table Entry is clear",
1547+
"SM: Non-zero reserved field set in PASID Table Entry",
1548+
"SM: Invalid Scalable-Mode PASID Table Entry",
1549+
"SM: ERE field is clear in PASID Table Entry",
1550+
"SM: SRE field is clear in PASID Table Entry",
1551+
"Unknown", "Unknown",/* 0x5E-0x5F */
1552+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x60-0x67 */
1553+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x68-0x6F */
1554+
"SM: Error attempting to access first-level paging entry",
1555+
"SM: Present bit in first-level paging entry is clear",
1556+
"SM: Non-zero reserved field set in first-level paging entry",
1557+
"SM: Error attempting to access FL-PML4 entry",
1558+
"SM: First-level entry address beyond MGAW in Nested translation",
1559+
"SM: Read permission error in FL-PML4 entry in Nested translation",
1560+
"SM: Read permission error in first-level paging entry in Nested translation",
1561+
"SM: Write permission error in first-level paging entry in Nested translation",
1562+
"SM: Error attempting to access second-level paging entry",
1563+
"SM: Read/Write permission error in second-level paging entry",
1564+
"SM: Non-zero reserved field set in second-level paging entry",
1565+
"SM: Invalid second-level page table pointer",
1566+
"SM: A/D bit update needed in second-level entry when set up in no snoop",
1567+
"Unknown", "Unknown", "Unknown", /* 0x7D-0x7F */
1568+
"SM: Address in first-level translation is not canonical",
1569+
"SM: U/S set 0 for first-level translation with user privilege",
1570+
"SM: No execute permission for request with PASID and ER=1",
1571+
"SM: Address beyond the DMA hardware max",
1572+
"SM: Second-level entry address beyond the max",
1573+
"SM: No write permission for Write/AtomicOp request",
1574+
"SM: No read permission for Read/AtomicOp request",
1575+
"SM: Invalid address-interrupt address",
1576+
"Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", /* 0x88-0x8F */
1577+
"SM: A/D bit update needed in first-level entry when set up in no snoop",
1578+
};
1579+
15221580
static const char *irq_remap_fault_reasons[] =
15231581
{
15241582
"Detected reserved fields in the decoded interrupt-remapped request",
@@ -1536,6 +1594,10 @@ static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
15361594
ARRAY_SIZE(irq_remap_fault_reasons))) {
15371595
*fault_type = INTR_REMAP;
15381596
return irq_remap_fault_reasons[fault_reason - 0x20];
1597+
} else if (fault_reason >= 0x30 && (fault_reason - 0x30 <
1598+
ARRAY_SIZE(dma_remap_sm_fault_reasons))) {
1599+
*fault_type = DMA_REMAP;
1600+
return dma_remap_sm_fault_reasons[fault_reason - 0x30];
15391601
} else if (fault_reason < ARRAY_SIZE(dma_remap_fault_reasons)) {
15401602
*fault_type = DMA_REMAP;
15411603
return dma_remap_fault_reasons[fault_reason];
@@ -1611,7 +1673,8 @@ void dmar_msi_read(int irq, struct msi_msg *msg)
16111673
}
16121674

16131675
static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
1614-
u8 fault_reason, u16 source_id, unsigned long long addr)
1676+
u8 fault_reason, int pasid, u16 source_id,
1677+
unsigned long long addr)
16151678
{
16161679
const char *reason;
16171680
int fault_type;
@@ -1624,10 +1687,11 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
16241687
PCI_FUNC(source_id & 0xFF), addr >> 48,
16251688
fault_reason, reason);
16261689
else
1627-
pr_err("[%s] Request device [%02x:%02x.%d] fault addr %llx [fault reason %02d] %s\n",
1690+
pr_err("[%s] Request device [%02x:%02x.%d] PASID %x fault addr %llx [fault reason %02d] %s\n",
16281691
type ? "DMA Read" : "DMA Write",
16291692
source_id >> 8, PCI_SLOT(source_id & 0xFF),
1630-
PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
1693+
PCI_FUNC(source_id & 0xFF), pasid, addr,
1694+
fault_reason, reason);
16311695
return 0;
16321696
}
16331697

@@ -1659,8 +1723,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
16591723
u8 fault_reason;
16601724
u16 source_id;
16611725
u64 guest_addr;
1662-
int type;
1726+
int type, pasid;
16631727
u32 data;
1728+
bool pasid_present;
16641729

16651730
/* highest 32 bits */
16661731
data = readl(iommu->reg + reg +
@@ -1672,10 +1737,12 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
16721737
fault_reason = dma_frcd_fault_reason(data);
16731738
type = dma_frcd_type(data);
16741739

1740+
pasid = dma_frcd_pasid_value(data);
16751741
data = readl(iommu->reg + reg +
16761742
fault_index * PRIMARY_FAULT_REG_LEN + 8);
16771743
source_id = dma_frcd_source_id(data);
16781744

1745+
pasid_present = dma_frcd_pasid_present(data);
16791746
guest_addr = dmar_readq(iommu->reg + reg +
16801747
fault_index * PRIMARY_FAULT_REG_LEN);
16811748
guest_addr = dma_frcd_page_addr(guest_addr);
@@ -1688,7 +1755,9 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
16881755
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
16891756

16901757
if (!ratelimited)
1758+
/* Using pasid -1 if pasid is not present */
16911759
dmar_fault_do_one(iommu, type, fault_reason,
1760+
pasid_present ? pasid : -1,
16921761
source_id, guest_addr);
16931762

16941763
fault_index++;

include/linux/intel-iommu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@
272272
#define dma_frcd_type(d) ((d >> 30) & 1)
273273
#define dma_frcd_fault_reason(c) (c & 0xff)
274274
#define dma_frcd_source_id(c) (c & 0xffff)
275+
#define dma_frcd_pasid_value(c) (((c) >> 8) & 0xfffff)
276+
#define dma_frcd_pasid_present(c) (((c) >> 31) & 1)
275277
/* low 64 bit */
276278
#define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
277279

0 commit comments

Comments
 (0)