Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 112642
b: refs/heads/master
c: 2ae2101
h: refs/heads/master
v: v3
  • Loading branch information
Suresh Siddha authored and Ingo Molnar committed Jul 12, 2008
1 parent ff1dee5 commit 6d6b753
Show file tree
Hide file tree
Showing 8 changed files with 273 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: fe962e90cb17a8426e144dee970e77ed789d98ee
refs/heads/master: 2ae21010694e56461a63bfc80e960090ce0a5ed9
2 changes: 2 additions & 0 deletions trunk/drivers/pci/dma_remapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ struct device_domain_info {
extern int init_dmars(void);
extern void free_dmar_iommu(struct intel_iommu *iommu);

extern int dmar_disabled;

#ifndef CONFIG_DMAR_GFX_WA
static inline void iommu_prepare_gfx_mapping(void)
{
Expand Down
16 changes: 16 additions & 0 deletions trunk/drivers/pci/dmar.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,22 @@ int __init early_dmar_detect(void)
return (ACPI_SUCCESS(status) ? 1 : 0);
}

void __init detect_intel_iommu(void)
{
int ret;

ret = early_dmar_detect();

#ifdef CONFIG_DMAR
{
if (ret && !no_iommu && !iommu_detected && !swiotlb &&
!dmar_disabled)
iommu_detected = 1;
}
#endif
}


int alloc_iommu(struct dmar_drhd_unit *drhd)
{
struct intel_iommu *iommu;
Expand Down
21 changes: 8 additions & 13 deletions trunk/drivers/pci/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ static long list_size;

static void domain_remove_dev_info(struct dmar_domain *domain);

static int dmar_disabled;
int dmar_disabled;
static int __initdata dmar_map_gfx = 1;
static int dmar_forcedac;
static int intel_iommu_strict;
Expand Down Expand Up @@ -2238,15 +2238,6 @@ static void __init iommu_exit_mempool(void)

}

void __init detect_intel_iommu(void)
{
if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
return;
if (early_dmar_detect()) {
iommu_detected = 1;
}
}

static void __init init_no_remapping_devices(void)
{
struct dmar_drhd_unit *drhd;
Expand Down Expand Up @@ -2293,15 +2284,19 @@ int __init intel_iommu_init(void)
{
int ret = 0;

if (no_iommu || swiotlb || dmar_disabled)
return -ENODEV;

if (dmar_table_init())
return -ENODEV;

if (dmar_dev_scope_init())
return -ENODEV;

/*
* Check the need for DMA-remapping initialization now.
* Above initialization will also be used by Interrupt-remapping.
*/
if (no_iommu || swiotlb || dmar_disabled)
return -ENODEV;

iommu_init_mempool();
dmar_init_reserved_ranges();

Expand Down
24 changes: 22 additions & 2 deletions trunk/drivers/pci/intel-iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */
#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
#define DMAR_ICS_REG 0x98 /* Invalidation complete status register */
#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */

#define OFFSET_STRIDE (9)
/*
Expand Down Expand Up @@ -157,16 +158,20 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_GCMD_SRTP (((u32)1) << 30)
#define DMA_GCMD_SFL (((u32)1) << 29)
#define DMA_GCMD_EAFL (((u32)1) << 28)
#define DMA_GCMD_QIE (((u32)1) << 26)
#define DMA_GCMD_WBF (((u32)1) << 27)
#define DMA_GCMD_QIE (((u32)1) << 26)
#define DMA_GCMD_SIRTP (((u32)1) << 24)
#define DMA_GCMD_IRE (((u32) 1) << 25)

/* GSTS_REG */
#define DMA_GSTS_TES (((u32)1) << 31)
#define DMA_GSTS_RTPS (((u32)1) << 30)
#define DMA_GSTS_FLS (((u32)1) << 29)
#define DMA_GSTS_AFLS (((u32)1) << 28)
#define DMA_GSTS_QIES (((u32)1) << 26)
#define DMA_GSTS_WBFS (((u32)1) << 27)
#define DMA_GSTS_QIES (((u32)1) << 26)
#define DMA_GSTS_IRTPS (((u32)1) << 24)
#define DMA_GSTS_IRES (((u32)1) << 25)

/* CCMD_REG */
#define DMA_CCMD_ICC (((u64)1) << 63)
Expand Down Expand Up @@ -245,6 +250,16 @@ struct q_inval {
int free_cnt;
};

#ifdef CONFIG_INTR_REMAP
/* 1MB - maximum possible interrupt remapping table size */
#define INTR_REMAP_PAGE_ORDER 8
#define INTR_REMAP_TABLE_REG_SIZE 0xf

struct ir_table {
struct irte *base;
};
#endif

struct intel_iommu {
void __iomem *reg; /* Pointer to hardware regs, virtual addr */
u64 cap;
Expand All @@ -266,6 +281,9 @@ struct intel_iommu {
struct sys_device sysdev;
#endif
struct q_inval *qi; /* Queued invalidation info */
#ifdef CONFIG_INTR_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
};

static inline void __iommu_flush_cache(
Expand All @@ -279,5 +297,7 @@ extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);

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 qi_global_iec(struct intel_iommu *iommu);

#endif
137 changes: 137 additions & 0 deletions trunk/drivers/pci/intr_remapping.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,147 @@
#include <linux/dmar.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/pci.h>
#include <asm/io_apic.h>
#include "intel-iommu.h"
#include "intr_remapping.h"

static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static int ir_ioapic_num;
int intr_remapping_enabled;

static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
{
u64 addr;
u32 cmd, sts;
unsigned long flags;

addr = virt_to_phys((void *)iommu->ir_table->base);

spin_lock_irqsave(&iommu->register_lock, flags);

dmar_writeq(iommu->reg + DMAR_IRTA_REG,
(addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE);

/* Set interrupt-remapping table pointer */
cmd = iommu->gcmd | DMA_GCMD_SIRTP;
writel(cmd, iommu->reg + DMAR_GCMD_REG);

IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_IRTPS), sts);
spin_unlock_irqrestore(&iommu->register_lock, flags);

/*
* global invalidation of interrupt entry cache before enabling
* interrupt-remapping.
*/
qi_global_iec(iommu);

spin_lock_irqsave(&iommu->register_lock, flags);

/* Enable interrupt-remapping */
cmd = iommu->gcmd | DMA_GCMD_IRE;
iommu->gcmd |= DMA_GCMD_IRE;
writel(cmd, iommu->reg + DMAR_GCMD_REG);

IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_IRES), sts);

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


static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
{
struct ir_table *ir_table;
struct page *pages;

ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
GFP_KERNEL);

if (!iommu->ir_table)
return -ENOMEM;

pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);

if (!pages) {
printk(KERN_ERR "failed to allocate pages of order %d\n",
INTR_REMAP_PAGE_ORDER);
kfree(iommu->ir_table);
return -ENOMEM;
}

ir_table->base = page_address(pages);

iommu_set_intr_remapping(iommu, mode);
return 0;
}

int __init enable_intr_remapping(int eim)
{
struct dmar_drhd_unit *drhd;
int setup = 0;

/*
* check for the Interrupt-remapping support
*/
for_each_drhd_unit(drhd) {
struct intel_iommu *iommu = drhd->iommu;

if (!ecap_ir_support(iommu->ecap))
continue;

if (eim && !ecap_eim_support(iommu->ecap)) {
printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
" ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
return -1;
}
}

/*
* Enable queued invalidation for all the DRHD's.
*/
for_each_drhd_unit(drhd) {
int ret;
struct intel_iommu *iommu = drhd->iommu;
ret = dmar_enable_qi(iommu);

if (ret) {
printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
" invalidation, ecap %Lx, ret %d\n",
drhd->reg_base_addr, iommu->ecap, ret);
return -1;
}
}

/*
* Setup Interrupt-remapping for all the DRHD's now.
*/
for_each_drhd_unit(drhd) {
struct intel_iommu *iommu = drhd->iommu;

if (!ecap_ir_support(iommu->ecap))
continue;

if (setup_intr_remapping(iommu, eim))
goto error;

setup = 1;
}

if (!setup)
goto error;

intr_remapping_enabled = 1;

return 0;

error:
/*
* handle error condition gracefully here!
*/
return -1;
}

static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
struct intel_iommu *iommu)
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/pci/intr_remapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
};

#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
Loading

0 comments on commit 6d6b753

Please sign in to comment.