diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2016-03-17 14:12:25 -0600 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-04-05 16:21:49 +0200 |
commit | c43fce4eebae257ca413733690e2076757282093 (patch) | |
tree | 31120baca6aa7bb297520e1806dbddd827eccb26 /drivers/iommu | |
parent | 9735a22799b9214d17d3c231fe377fc852f042e9 (diff) | |
download | linux-stable-c43fce4eebae257ca413733690e2076757282093.tar.gz linux-stable-c43fce4eebae257ca413733690e2076757282093.tar.bz2 linux-stable-c43fce4eebae257ca413733690e2076757282093.zip |
iommu/vt-d: Ratelimit fault handler
Fault rates can easily overwhelm the console and make the system
unresponsive. Ratelimit to allow an opportunity for maintenance.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Fixes: 0ac2491f57af ('x86, dmar: move page fault handling code to dmar.c')
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/dmar.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 8ffd7568fc91..8f8bfffbf1e6 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1602,10 +1602,17 @@ irqreturn_t dmar_fault(int irq, void *dev_id) int reg, fault_index; u32 fault_status; unsigned long flag; + bool ratelimited; + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + + /* Disable printing, simply clear the fault when ratelimited */ + ratelimited = !__ratelimit(&rs); raw_spin_lock_irqsave(&iommu->register_lock, flag); fault_status = readl(iommu->reg + DMAR_FSTS_REG); - if (fault_status) + if (fault_status && !ratelimited) pr_err("DRHD: handling fault status reg %x\n", fault_status); /* TBD: ignore advanced fault log currently */ @@ -1627,24 +1634,28 @@ irqreturn_t dmar_fault(int irq, void *dev_id) if (!(data & DMA_FRCD_F)) break; - fault_reason = dma_frcd_fault_reason(data); - type = dma_frcd_type(data); + if (!ratelimited) { + fault_reason = dma_frcd_fault_reason(data); + type = dma_frcd_type(data); - data = readl(iommu->reg + reg + - fault_index * PRIMARY_FAULT_REG_LEN + 8); - source_id = dma_frcd_source_id(data); + data = readl(iommu->reg + reg + + fault_index * PRIMARY_FAULT_REG_LEN + 8); + source_id = dma_frcd_source_id(data); + + guest_addr = dmar_readq(iommu->reg + reg + + fault_index * PRIMARY_FAULT_REG_LEN); + guest_addr = dma_frcd_page_addr(guest_addr); + } - guest_addr = dmar_readq(iommu->reg + reg + - fault_index * PRIMARY_FAULT_REG_LEN); - guest_addr = dma_frcd_page_addr(guest_addr); /* clear the fault */ writel(DMA_FRCD_F, iommu->reg + reg + fault_index * PRIMARY_FAULT_REG_LEN + 12); raw_spin_unlock_irqrestore(&iommu->register_lock, flag); - dmar_fault_do_one(iommu, type, fault_reason, - source_id, guest_addr); + if (!ratelimited) + dmar_fault_do_one(iommu, type, fault_reason, + source_id, guest_addr); fault_index++; if (fault_index >= cap_num_fault_regs(iommu->cap)) |