Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 373568
b: refs/heads/master
c: 3f398bc
h: refs/heads/master
v: v3
  • Loading branch information
Suravee Suthikulpanit authored and Joerg Roedel committed Apr 23, 2013
1 parent e9d709d commit ed31cc7
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 51 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d3263bc29706e42f74d8800807c2dedf320d77f1
refs/heads/master: 3f398bc7762adcd860bd2acce18465a106f47325
82 changes: 33 additions & 49 deletions trunk/drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,22 +700,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)

static void iommu_poll_events(struct amd_iommu *iommu)
{
u32 head, tail, status;
unsigned long flags;

spin_lock_irqsave(&iommu->lock, flags);

/* enable event interrupts again */
do {
/*
* Workaround for Erratum ERBT1312
* Clearing the EVT_INT bit may race in the hardware, so read
* it again and make sure it was really cleared
*/
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
writel(MMIO_STATUS_EVT_INT_MASK,
iommu->mmio_base + MMIO_STATUS_OFFSET);
} while (status & MMIO_STATUS_EVT_INT_MASK);
u32 head, tail;

head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
Expand All @@ -726,8 +711,6 @@ static void iommu_poll_events(struct amd_iommu *iommu)
}

writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);

spin_unlock_irqrestore(&iommu->lock, flags);
}

static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)
Expand All @@ -752,26 +735,11 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)

static void iommu_poll_ppr_log(struct amd_iommu *iommu)
{
unsigned long flags;
u32 head, tail, status;
u32 head, tail;

if (iommu->ppr_log == NULL)
return;

spin_lock_irqsave(&iommu->lock, flags);

/* enable ppr interrupts again */
do {
/*
* Workaround for Erratum ERBT1312
* Clearing the PPR_INT bit may race in the hardware, so read
* it again and make sure it was really cleared
*/
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
writel(MMIO_STATUS_PPR_INT_MASK,
iommu->mmio_base + MMIO_STATUS_OFFSET);
} while (status & MMIO_STATUS_PPR_INT_MASK);

head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);

Expand Down Expand Up @@ -807,34 +775,50 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);

/*
* Release iommu->lock because ppr-handling might need to
* re-acquire it
*/
spin_unlock_irqrestore(&iommu->lock, flags);

/* Handle PPR entry */
iommu_handle_ppr_entry(iommu, entry);

spin_lock_irqsave(&iommu->lock, flags);

/* Refresh ring-buffer information */
head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
}

spin_unlock_irqrestore(&iommu->lock, flags);
}

irqreturn_t amd_iommu_int_thread(int irq, void *data)
{
struct amd_iommu *iommu;
struct amd_iommu *iommu = (struct amd_iommu *) data;
u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);

for_each_iommu(iommu) {
iommu_poll_events(iommu);
iommu_poll_ppr_log(iommu);
}
while (status & (MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK)) {
/* Enable EVT and PPR interrupts again */
writel((MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK),
iommu->mmio_base + MMIO_STATUS_OFFSET);

if (status & MMIO_STATUS_EVT_INT_MASK) {
pr_devel("AMD-Vi: Processing IOMMU Event Log\n");
iommu_poll_events(iommu);
}

if (status & MMIO_STATUS_PPR_INT_MASK) {
pr_devel("AMD-Vi: Processing IOMMU PPR Log\n");
iommu_poll_ppr_log(iommu);
}

/*
* Hardware bug: ERBT1312
* When re-enabling interrupt (by writing 1
* to clear the bit), the hardware might also try to set
* the interrupt bit in the event status register.
* In this scenario, the bit will be set, and disable
* subsequent interrupts.
*
* Workaround: The IOMMU driver should read back the
* status register and check if the interrupt bits are cleared.
* If not, driver will need to go through the interrupt handler
* again and re-clear the bits
*/
status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
}
return IRQ_HANDLED;
}

Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/iommu/amd_iommu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1324,7 +1324,7 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
amd_iommu_int_handler,
amd_iommu_int_thread,
0, "AMD-Vi",
iommu->dev);
iommu);

if (r) {
pci_disable_msi(iommu->dev);
Expand Down

0 comments on commit ed31cc7

Please sign in to comment.