Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 142249
b: refs/heads/master
c: f59c7b6
h: refs/heads/master
i:
  142247: a0cad2a
v: v3
  • Loading branch information
Fenghua Yu authored and David Woodhouse committed Apr 3, 2009
1 parent 99cafc3 commit 0832c27
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8f912ba4d7cdaf7d31cf39fe5a9b7732308a256d
refs/heads/master: f59c7b69bcba31cd355ababe067202b9895d6102
146 changes: 146 additions & 0 deletions trunk/drivers/pci/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/iova.h>
#include <linux/iommu.h>
#include <linux/intel-iommu.h>
#include <linux/sysdev.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
#include "pci.h"
Expand Down Expand Up @@ -2597,6 +2598,150 @@ static void __init init_no_remapping_devices(void)
}
}

#ifdef CONFIG_SUSPEND
static int init_iommu_hw(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;

for_each_active_iommu(iommu, drhd)
if (iommu->qi)
dmar_reenable_qi(iommu);

for_each_active_iommu(iommu, drhd) {
iommu_flush_write_buffer(iommu);

iommu_set_root_entry(iommu);

iommu->flush.flush_context(iommu, 0, 0, 0,
DMA_CCMD_GLOBAL_INVL, 0);
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
iommu_disable_protect_mem_regions(iommu);
iommu_enable_translation(iommu);
}

return 0;
}

static void iommu_flush_all(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;

for_each_active_iommu(iommu, drhd) {
iommu->flush.flush_context(iommu, 0, 0, 0,
DMA_CCMD_GLOBAL_INVL, 0);
iommu->flush.flush_iotlb(iommu, 0, 0, 0,
DMA_TLB_GLOBAL_FLUSH, 0);
}
}

static int iommu_suspend(struct sys_device *dev, pm_message_t state)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
unsigned long flag;

for_each_active_iommu(iommu, drhd) {
iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS,
GFP_ATOMIC);
if (!iommu->iommu_state)
goto nomem;
}

iommu_flush_all();

for_each_active_iommu(iommu, drhd) {
iommu_disable_translation(iommu);

spin_lock_irqsave(&iommu->register_lock, flag);

iommu->iommu_state[SR_DMAR_FECTL_REG] =
readl(iommu->reg + DMAR_FECTL_REG);
iommu->iommu_state[SR_DMAR_FEDATA_REG] =
readl(iommu->reg + DMAR_FEDATA_REG);
iommu->iommu_state[SR_DMAR_FEADDR_REG] =
readl(iommu->reg + DMAR_FEADDR_REG);
iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
readl(iommu->reg + DMAR_FEUADDR_REG);

spin_unlock_irqrestore(&iommu->register_lock, flag);
}
return 0;

nomem:
for_each_active_iommu(iommu, drhd)
kfree(iommu->iommu_state);

return -ENOMEM;
}

static int iommu_resume(struct sys_device *dev)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
unsigned long flag;

if (init_iommu_hw()) {
WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
return -EIO;
}

for_each_active_iommu(iommu, drhd) {

spin_lock_irqsave(&iommu->register_lock, flag);

writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
iommu->reg + DMAR_FECTL_REG);
writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
iommu->reg + DMAR_FEDATA_REG);
writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
iommu->reg + DMAR_FEADDR_REG);
writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
iommu->reg + DMAR_FEUADDR_REG);

spin_unlock_irqrestore(&iommu->register_lock, flag);
}

for_each_active_iommu(iommu, drhd)
kfree(iommu->iommu_state);

return 0;
}

static struct sysdev_class iommu_sysclass = {
.name = "iommu",
.resume = iommu_resume,
.suspend = iommu_suspend,
};

static struct sys_device device_iommu = {
.cls = &iommu_sysclass,
};

static int __init init_iommu_sysfs(void)
{
int error;

error = sysdev_class_register(&iommu_sysclass);
if (error)
return error;

error = sysdev_register(&device_iommu);
if (error)
sysdev_class_unregister(&iommu_sysclass);

return error;
}

#else
static int __init init_iommu_sysfs(void)
{
return 0;
}
#endif /* CONFIG_PM */

int __init intel_iommu_init(void)
{
int ret = 0;
Expand Down Expand Up @@ -2632,6 +2777,7 @@ int __init intel_iommu_init(void)
init_timer(&unmap_timer);
force_iommu = 1;
dma_ops = &intel_dma_ops;
init_iommu_sysfs();

register_iommu(&intel_iommu_ops);

Expand Down
11 changes: 11 additions & 0 deletions trunk/include/linux/intel-iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,14 @@ struct iommu_flush {
unsigned int size_order, u64 type, int non_present_entry_flush);
};

enum {
SR_DMAR_FECTL_REG,
SR_DMAR_FEDATA_REG,
SR_DMAR_FEADDR_REG,
SR_DMAR_FEUADDR_REG,
MAX_SR_DMAR_REGS
};

struct intel_iommu {
void __iomem *reg; /* Pointer to hardware regs, virtual addr */
u64 cap;
Expand All @@ -304,6 +312,8 @@ struct intel_iommu {
struct iommu_flush flush;
#endif
struct q_inval *qi; /* Queued invalidation info */
u32 *iommu_state; /* Store iommu states between suspend and resume.*/

#ifdef CONFIG_INTR_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
Expand All @@ -322,6 +332,7 @@ extern int alloc_iommu(struct dmar_drhd_unit *drhd);
extern void free_iommu(struct intel_iommu *iommu);
extern int dmar_enable_qi(struct intel_iommu *iommu);
extern void dmar_disable_qi(struct intel_iommu *iommu);
extern int dmar_reenable_qi(struct intel_iommu *iommu);
extern void qi_global_iec(struct intel_iommu *iommu);

extern int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid,
Expand Down

0 comments on commit 0832c27

Please sign in to comment.