[PATCH 09/28] iommu/amd: Move unmap_flush message to amd_iommu_init_dma_ops()

2012-07-05 Thread Joerg Roedel
The message belongs there anyway, so move it to that
function.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c  |5 +
 drivers/iommu/amd_iommu_init.c |8 
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index cfa01c4..569800f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2962,6 +2962,11 @@ int __init amd_iommu_init_dma_ops(void)
 
amd_iommu_stats_init();
 
+   if (amd_iommu_unmap_flush)
+   pr_info(AMD-Vi: IO/TLB flush on unmap enabled\n);
+   else
+   pr_info(AMD-Vi: Lazy IO/TLB flushing enabled\n);
+
return 0;
 
 free_domains:
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 2324f9b..ab3bc19 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1706,14 +1706,6 @@ static int __init amd_iommu_init(void)
 
amd_iommu_init_api();
 
-   if (iommu_pass_through)
-   goto out;
-
-   if (amd_iommu_unmap_flush)
-   printk(KERN_INFO AMD-Vi: IO/TLB flush on unmap enabled\n);
-   else
-   printk(KERN_INFO AMD-Vi: Lazy IO/TLB flushing enabled\n);
-
 out:
return ret;
 
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 12/28] iommu/amd: Keep track of HPET and IOAPIC device ids

2012-07-05 Thread Joerg Roedel
The IVRS ACPI table provides information about the IOAPICs
and the HPETs available in the system and which PCI device
ID they use in transactions. Save that information for later
usage in interrupt remapping.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c   |3 ++
 drivers/iommu/amd_iommu_init.c  |   65 +--
 drivers/iommu/amd_iommu_types.h |   34 
 3 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 569800f..cca9c70 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -72,6 +72,9 @@ static DEFINE_SPINLOCK(iommu_pd_list_lock);
 static LIST_HEAD(dev_data_list);
 static DEFINE_SPINLOCK(dev_data_list_lock);
 
+LIST_HEAD(ioapic_map);
+LIST_HEAD(hpet_map);
+
 /*
  * Domain for untranslated devices - only allocated
  * if iommu=pt passed on kernel cmd line.
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 8d1780c..b4cc3a7 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -55,6 +55,7 @@
 #define IVHD_DEV_ALIAS_RANGE0x43
 #define IVHD_DEV_EXT_SELECT 0x46
 #define IVHD_DEV_EXT_SELECT_RANGE   0x47
+#define IVHD_DEV_SPECIAL   0x48
 
 #define IVHD_FLAG_HT_TUN_EN_MASK0x01
 #define IVHD_FLAG_PASSPW_EN_MASK0x02
@@ -696,6 +697,31 @@ static void __init set_dev_entry_from_acpi(struct 
amd_iommu *iommu,
set_iommu_for_device(iommu, devid);
 }
 
+static int add_special_device(u8 type, u8 id, u16 devid)
+{
+   struct devid_map *entry;
+   struct list_head *list;
+
+   if (type != 1  type != 2)
+   return -EINVAL;
+
+   entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+   if (!entry)
+   return -ENOMEM;
+
+   entry-id= id;
+   entry-devid = devid;
+
+   if (type == 1)
+   list = ioapic_map;
+   else
+   list = hpet_map;
+
+   list_add_tail(entry-list, list);
+
+   return 0;
+}
+
 /*
  * Reads the device exclusion range from ACPI and initialize IOMMU with
  * it
@@ -723,7 +749,7 @@ static void __init set_device_exclusion_range(u16 devid, 
struct ivmd_header *m)
  * Takes a pointer to an AMD IOMMU entry in the ACPI table and
  * initializes the hardware and our data structures with it.
  */
-static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
+static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
struct ivhd_header *h)
 {
u8 *p = (u8 *)h;
@@ -873,12 +899,43 @@ static void __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
flags, ext_flags);
}
break;
+   case IVHD_DEV_SPECIAL: {
+   u8 handle, type;
+   const char *var;
+   u16 devid;
+   int ret;
+
+   handle = e-ext  0xff;
+   devid  = (e-ext   8)  0x;
+   type   = (e-ext  24)  0xff;
+
+   if (type == 1)
+   var = IOAPIC;
+   else if (type == 2)
+   var = HPET;
+   else
+   var = UNKNOWN;
+
+   DUMP_printk(  DEV_SPECIAL(%s[%d])\t\tdevid: 
%02x:%02x.%x\n,
+   var, (int)handle,
+   PCI_BUS(devid),
+   PCI_SLOT(devid),
+   PCI_FUNC(devid));
+
+   set_dev_entry_from_acpi(iommu, devid, e-flags, 0);
+   ret = add_special_device(type, handle, devid);
+   if (ret)
+   return ret;
+   break;
+   }
default:
break;
}
 
p += ivhd_entry_length(p);
}
+
+   return 0;
 }
 
 /* Initializes the device-iommu mapping for the driver */
@@ -918,6 +975,8 @@ static void __init free_iommu_all(void)
  */
 static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header 
*h)
 {
+   int ret;
+
spin_lock_init(iommu-lock);
 
/* Add IOMMU to internal data structures */
@@ -953,7 +1012,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h)
 
iommu-int_enabled = false;
 
-   init_iommu_from_acpi(iommu, h);
+   ret = init_iommu_from_acpi(iommu, h);
+   if (ret)
+   return ret;
init_iommu_devices(iommu);
 
return 0;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 6f32d7b..925885d 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ 

[PATCH 01/28] x86/irq: Add data structure to keep AMD specific irq remapping information

2012-07-05 Thread Joerg Roedel
Add a data structure to store information the IOMMU driver
can use to get from a 'struct irq_cfg' to the remapping
entry.

Cc: x...@kernel.org
Cc: Yinghai Lu ying...@kernel.org
Cc: Suresh Siddha suresh.b.sid...@intel.com
Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 arch/x86/include/asm/hw_irq.h   |   14 +-
 arch/x86/kernel/apic/io_apic.c  |2 +-
 drivers/iommu/intel_irq_remapping.c |2 +-
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index eb92a6e..b6171e6 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct 
io_apic_irq_attr *irq_attr,
irq_attr-polarity  = polarity;
 }
 
+/* Intel specific interrupt remapping information */
 struct irq_2_iommu {
struct intel_iommu *iommu;
u16 irte_index;
@@ -108,6 +109,17 @@ struct irq_2_iommu {
u8  irte_mask;
 };
 
+/* AMD specific interrupt remapping information */
+struct irq_2_irte {
+   u16 devid; /* Device ID for IRTE table */
+   u16 index; /* Index into IRTE table*/
+};
+
+union irq_remap_info {
+   struct irq_2_iommu irq_2_iommu;
+   struct irq_2_irte  irq_2_irte;
+};
+
 /*
  * This is performance-critical, we want to do it O(1)
  *
@@ -120,7 +132,7 @@ struct irq_cfg {
u8  vector;
u8  move_in_progress : 1;
 #ifdef CONFIG_IRQ_REMAP
-   struct irq_2_iommu  irq_2_iommu;
+   union irq_remap_infoirq_remap_info;
 #endif
 };
 
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 5f0ff59..08f666c 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -72,7 +72,7 @@
 static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
 static inline bool irq_remapped(struct irq_cfg *cfg)
 {
-   return cfg-irq_2_iommu.iommu != NULL;
+   return cfg-irq_remap_info.irq_2_iommu.iommu != NULL;
 }
 #else
 static inline bool irq_remapped(struct irq_cfg *cfg)
diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 6d34706..e4e4334 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -43,7 +43,7 @@ static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
struct irq_cfg *cfg = irq_get_chip_data(irq);
-   return cfg ? cfg-irq_2_iommu : NULL;
+   return cfg ? cfg-irq_remap_info.irq_2_iommu : NULL;
 }
 
 int get_irte(int irq, struct irte *entry)
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 13/28] iommu/amd: Add slab-cache for irq remapping tables

2012-07-05 Thread Joerg Roedel
The irq remapping tables for the AMD IOMMU need to be
aligned on a 128 byte boundary. Create a seperate slab-cache
to guarantee this alignment.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c   |2 ++
 drivers/iommu/amd_iommu_init.c  |   23 +++
 drivers/iommu/amd_iommu_types.h |9 +
 drivers/iommu/irq_remapping.h   |4 
 4 files changed, 38 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index cca9c70..6282dab 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -93,6 +93,8 @@ struct iommu_cmd {
u32 data[4];
 };
 
+struct kmem_cache *amd_iommu_irq_cache;
+
 static void update_domain(struct protection_domain *domain);
 static int __init alloc_passthrough_domain(void);
 
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index b4cc3a7..34b46b7 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -36,6 +36,7 @@
 
 #include amd_iommu_proto.h
 #include amd_iommu_types.h
+#include irq_remapping.h
 
 /*
  * definitions for the ACPI scanning code
@@ -124,6 +125,7 @@ struct ivmd_header {
 } __attribute__((packed));
 
 bool amd_iommu_dump;
+bool amd_iommu_irq_remap __read_mostly;
 
 static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
@@ -1533,6 +1535,11 @@ static struct syscore_ops amd_iommu_syscore_ops = {
 
 static void __init free_on_init_error(void)
 {
+   if (amd_iommu_irq_cache) {
+   kmem_cache_destroy(amd_iommu_irq_cache);
+   amd_iommu_irq_cache = NULL;
+   }
+
amd_iommu_uninit_devices();
 
free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
@@ -1672,6 +1679,19 @@ static int __init early_amd_iommu_init(void)
if (ret)
goto out;
 
+   if (amd_iommu_irq_remap) {
+   /*
+* Interrupt remapping enabled, create kmem_cache for the
+* remapping tables.
+*/
+   amd_iommu_irq_cache = kmem_cache_create(irq_remap_cache,
+   MAX_IRQS_PER_TABLE * sizeof(u32),
+   IRQ_TABLE_ALIGNMENT,
+   0, NULL);
+   if (!amd_iommu_irq_cache)
+   goto out;
+   }
+
ret = init_memory_definitions(ivrs_base);
if (ret)
goto out;
@@ -1716,6 +1736,9 @@ static bool detect_ivrs(void)
 
early_acpi_os_unmap_memory((char *)ivrs_base, ivrs_size);
 
+   if (!disable_irq_remap)
+   amd_iommu_irq_remap = true;
+
return true;
 }
 
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 925885d..c9e0049 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -334,6 +334,15 @@ extern bool amd_iommu_np_cache;
 /* Only true if all IOMMUs support device IOTLBs */
 extern bool amd_iommu_iotlb_sup;
 
+#define MAX_IRQS_PER_TABLE 256
+#define IRQ_TABLE_ALIGNMENT128
+
+/* Interrupt remapping feature used? */
+extern bool amd_iommu_irq_remap;
+
+/* kmem_cache to get tables with 128 byte alignement */
+extern struct kmem_cache *amd_iommu_irq_cache;
+
 /*
  * Make iterating over all IOMMUs easier
  */
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index be9d729..b3f70c9 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -85,6 +85,10 @@ struct irq_remap_ops {
 
 extern struct irq_remap_ops intel_irq_remap_ops;
 
+#else  /* CONFIG_IRQ_REMAP */
+
+#define disable_irq_remap  1
+
 #endif /* CONFIG_IRQ_REMAP */
 
 #endif /* __IRQ_REMAPPING_H */
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 02/28] x86/irq: Introduce irq_cfg-remapped

2012-07-05 Thread Joerg Roedel
This flag will show whether the interrupt is remapped in a
way that works for VT-d and AMD-Vi.

Cc: x...@kernel.org
Cc: Yinghai Lu ying...@kernel.org
Cc: Suresh Siddha suresh.b.sid...@intel.com
Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 arch/x86/include/asm/hw_irq.h   |1 +
 arch/x86/kernel/apic/io_apic.c  |2 +-
 drivers/iommu/intel_irq_remapping.c |4 
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index b6171e6..71bb327 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -132,6 +132,7 @@ struct irq_cfg {
u8  vector;
u8  move_in_progress : 1;
 #ifdef CONFIG_IRQ_REMAP
+   boolremapped;
union irq_remap_infoirq_remap_info;
 #endif
 };
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 08f666c..d5bccc0 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -72,7 +72,7 @@
 static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
 static inline bool irq_remapped(struct irq_cfg *cfg)
 {
-   return cfg-irq_remap_info.irq_2_iommu.iommu != NULL;
+   return cfg-remapped;
 }
 #else
 static inline bool irq_remapped(struct irq_cfg *cfg)
diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index e4e4334..29411ed 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 
count)
 {
struct ir_table *table = iommu-ir_table;
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+   struct irq_cfg *cfg = irq_get_chip_data(irq);
u16 index, start_index;
unsigned int mask = 0;
unsigned long flags;
@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, 
u16 count)
for (i = index; i  index + count; i++)
table-base[i].present = 1;
 
+   cfg-remapped = true;
irq_iommu-iommu = iommu;
irq_iommu-irte_index =  index;
irq_iommu-sub_handle = 0;
@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 
subhandle)
 {
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+   struct irq_cfg *cfg = irq_get_chip_data(irq);
unsigned long flags;
 
if (!irq_iommu)
@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, 
u16 index, u16 subha
 
raw_spin_lock_irqsave(irq_2_ir_lock, flags);
 
+   cfg-remapped = true;
irq_iommu-iommu = iommu;
irq_iommu-irte_index = index;
irq_iommu-sub_handle = subhandle;
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 05/28] iommu/amd: Split out PCI related parts of IOMMU initialization

2012-07-05 Thread Joerg Roedel
For interrupt remapping the relevant IOMMU initialization
needs to run earlier at boot when the PCI subsystem is not
yet initialized. To support that this patch splits the parts
of IOMMU initialization which need PCI accesses out of the
initial setup path so that this can be done later.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c  |  224 +--
 drivers/iommu/amd_iommu_types.h |5 +-
 2 files changed, 121 insertions(+), 108 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index fb118bb..1354497 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -721,90 +721,6 @@ static void __init set_device_exclusion_range(u16 devid, 
struct ivmd_header *m)
 }
 
 /*
- * This function reads some important data from the IOMMU PCI space and
- * initializes the driver data structure with it. It reads the hardware
- * capabilities and the first/last device entries
- */
-static void __init init_iommu_from_pci(struct amd_iommu *iommu)
-{
-   int cap_ptr = iommu-cap_ptr;
-   u32 range, misc, low, high;
-   int i, j;
-
-   pci_read_config_dword(iommu-dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
- iommu-cap);
-   pci_read_config_dword(iommu-dev, cap_ptr + MMIO_RANGE_OFFSET,
- range);
-   pci_read_config_dword(iommu-dev, cap_ptr + MMIO_MISC_OFFSET,
- misc);
-
-   iommu-first_device = calc_devid(MMIO_GET_BUS(range),
-MMIO_GET_FD(range));
-   iommu-last_device = calc_devid(MMIO_GET_BUS(range),
-   MMIO_GET_LD(range));
-   iommu-evt_msi_num = MMIO_MSI_NUM(misc);
-
-   if (!(iommu-cap  (1  IOMMU_CAP_IOTLB)))
-   amd_iommu_iotlb_sup = false;
-
-   /* read extended feature bits */
-   low  = readl(iommu-mmio_base + MMIO_EXT_FEATURES);
-   high = readl(iommu-mmio_base + MMIO_EXT_FEATURES + 4);
-
-   iommu-features = ((u64)high  32) | low;
-
-   if (iommu_feature(iommu, FEATURE_GT)) {
-   int glxval;
-   u32 pasids;
-   u64 shift;
-
-   shift   = iommu-features  FEATURE_PASID_MASK;
-   shift = FEATURE_PASID_SHIFT;
-   pasids  = (1  shift);
-
-   amd_iommu_max_pasids = min(amd_iommu_max_pasids, pasids);
-
-   glxval   = iommu-features  FEATURE_GLXVAL_MASK;
-   glxval = FEATURE_GLXVAL_SHIFT;
-
-   if (amd_iommu_max_glx_val == -1)
-   amd_iommu_max_glx_val = glxval;
-   else
-   amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, 
glxval);
-   }
-
-   if (iommu_feature(iommu, FEATURE_GT) 
-   iommu_feature(iommu, FEATURE_PPR)) {
-   iommu-is_iommu_v2   = true;
-   amd_iommu_v2_present = true;
-   }
-
-   if (!is_rd890_iommu(iommu-dev))
-   return;
-
-   /*
-* Some rd890 systems may not be fully reconfigured by the BIOS, so
-* it's necessary for us to store this information so it can be
-* reprogrammed on resume
-*/
-
-   pci_read_config_dword(iommu-dev, iommu-cap_ptr + 4,
- iommu-stored_addr_lo);
-   pci_read_config_dword(iommu-dev, iommu-cap_ptr + 8,
- iommu-stored_addr_hi);
-
-   /* Low bit locks writes to configuration space */
-   iommu-stored_addr_lo = ~1;
-
-   for (i = 0; i  6; i++)
-   for (j = 0; j  0x12; j++)
-   iommu-stored_l1[i][j] = iommu_read_l1(iommu, i, j);
-
-   for (i = 0; i  0x83; i++)
-   iommu-stored_l2[i] = iommu_read_l2(iommu, i);
-}
-
-/*
  * Takes a pointer to an AMD IOMMU entry in the ACPI table and
  * initializes the hardware and our data structures with it.
  */
@@ -1020,13 +936,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h)
/*
 * Copy data from ACPI table entry to the iommu struct
 */
-   iommu-dev = pci_get_bus_and_slot(PCI_BUS(h-devid), h-devid  0xff);
-   if (!iommu-dev)
-   return 1;
-
-   iommu-root_pdev = pci_get_bus_and_slot(iommu-dev-bus-number,
-   PCI_DEVFN(0, 0));
-
+   iommu-devid   = h-devid;
iommu-cap_ptr = h-cap_ptr;
iommu-pci_seg = h-pci_seg;
iommu-mmio_phys = h-mmio_phys;
@@ -1044,20 +954,10 @@ static int __init init_iommu_one(struct amd_iommu 
*iommu, struct ivhd_header *h)
 
iommu-int_enabled = false;
 
-   init_iommu_from_pci(iommu);
init_iommu_from_acpi(iommu, h);
init_iommu_devices(iommu);
 
-   if (iommu_feature(iommu, FEATURE_PPR)) {
-   iommu-ppr_log = alloc_ppr_log(iommu);
-   if (!iommu-ppr_log)
-   

[PATCH 11/28] iommu/amd: Convert iommu initialization to state machine

2012-07-05 Thread Joerg Roedel
This step makes it very easy to keep track about the current
intialization state of the iommu driver. With this change we
can initialize the IOMMU hardware to a point where it can
remap interrupts and later resume the initializion to enable
dma remapping.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c |  174 +---
 1 file changed, 109 insertions(+), 65 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 0afd89c..8d1780c 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -193,7 +193,23 @@ static u32 rlookup_table_size; /* size if the rlookup 
table */
  */
 extern void iommu_flush_all_caches(struct amd_iommu *iommu);
 
+enum iommu_init_state {
+   IOMMU_START_STATE,
+   IOMMU_IVRS_DETECTED,
+   IOMMU_ACPI_FINISHED,
+   IOMMU_ENABLED,
+   IOMMU_PCI_INIT,
+   IOMMU_INTERRUPTS_EN,
+   IOMMU_DMA_OPS,
+   IOMMU_INITIALIZED,
+   IOMMU_NOT_FOUND,
+   IOMMU_INIT_ERROR,
+};
+
+enum iommu_init_state init_state = IOMMU_START_STATE;
+
 static int amd_iommu_enable_interrupts(void);
+static int __init iommu_go_to_state(enum iommu_init_state state);
 
 static inline void update_last_devid(u16 devid)
 {
@@ -1107,7 +1123,7 @@ static void print_iommu_info(void)
}
 }
 
-static int amd_iommu_init_pci(void)
+static int __init amd_iommu_init_pci(void)
 {
struct amd_iommu *iommu;
int ret = 0;
@@ -1396,9 +1412,6 @@ static void early_enable_iommus(void)
iommu_enable(iommu);
iommu_flush_all_caches(iommu);
}
-
-   x86_platform.iommu_shutdown = disable_iommus;
-
 }
 
 static void enable_iommus_v2(void)
@@ -1522,11 +1535,6 @@ static int __init early_amd_iommu_init(void)
if (!amd_iommu_detected)
return -ENODEV;
 
-   if (amd_iommu_dev_table != NULL) {
-   /* Hardware already initialized */
-   return 0;
-   }
-
status = acpi_get_table_with_size(IVRS, 0, ivrs_base, ivrs_size);
if (status == AE_NOT_FOUND)
return -ENODEV;
@@ -1541,7 +1549,8 @@ static int __init early_amd_iommu_init(void)
 * we need to handle. Upon this information the shared data
 * structures for the IOMMUs in the system will be allocated
 */
-   if (find_last_devid_acpi(ivrs_base))
+   ret = find_last_devid_acpi(ivrs_base);
+   if (ret)
goto out;
 
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
@@ -1562,20 +1571,20 @@ static int __init early_amd_iommu_init(void)
amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL,
get_order(alias_table_size));
if (amd_iommu_alias_table == NULL)
-   goto free;
+   goto out;
 
/* IOMMU rlookup table - find the IOMMU for a specific device */
amd_iommu_rlookup_table = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(rlookup_table_size));
if (amd_iommu_rlookup_table == NULL)
-   goto free;
+   goto out;
 
amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(MAX_DOMAIN_ID/8));
if (amd_iommu_pd_alloc_bitmap == NULL)
-   goto free;
+   goto out;
 
/* init the device table */
init_device_table();
@@ -1600,11 +1609,11 @@ static int __init early_amd_iommu_init(void)
 */
ret = init_iommu_all(ivrs_base);
if (ret)
-   goto free;
+   goto out;
 
ret = init_memory_definitions(ivrs_base);
if (ret)
-   goto free;
+   goto out;
 
 out:
/* Don't leak any ACPI memory */
@@ -1612,30 +1621,6 @@ out:
ivrs_base = NULL;
 
return ret;
-
-free:
-   free_on_init_error();
-
-   goto out;
-}
-
-int amd_iommu_init_hardware(void)
-{
-   int ret = 0;
-
-   ret = early_amd_iommu_init();
-   if (ret)
-   return ret;
-
-   ret = amd_iommu_init_pci();
-   if (ret)
-   return ret;
-
-   enable_iommus();
-
-   register_syscore_ops(amd_iommu_syscore_ops);
-
-   return ret;
 }
 
 static int amd_iommu_enable_interrupts(void)
@@ -1692,42 +1677,99 @@ static int amd_iommu_init_dma(void)
return 0;
 }
 
-/*
- * This is the core init function for AMD IOMMU hardware in the system.
- * This function is called from the generic x86 DMA layer initialization
- * code.
+/
  *
- * The function calls amd_iommu_init_hardware() to setup and enable the
- * IOMMU hardware if this has not happened yet. After that the driver
- * registers for the DMA-API and for the IOMMU-API as 

[PATCH 27/28] iommu/amd: Print message to system log when irq remapping is enabled

2012-07-05 Thread Joerg Roedel
Print an indicator to dmesg to easily find out if interrupt
remapping is enabled of a given system.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 1bfeef5..f2d0fdb 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1198,6 +1198,8 @@ static void print_iommu_info(void)
}
pr_cont(\n);
}
+   if (irq_remapping_enabled)
+   pr_info(AMD-Vi: Interrupt remapping enabled\n);
 }
 
 static int __init amd_iommu_init_pci(void)
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 04/28] iommu/amd: Use acpi_get_table instead of acpi_table_parse

2012-07-05 Thread Joerg Roedel
This makes it easier to propagate errors while parsing the
IVRS table and makes the amd_iommu_init_err hack obsolete.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c |  118 ++--
 1 file changed, 66 insertions(+), 52 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 542024b..fb118bb 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -26,6 +26,8 @@
 #include linux/msi.h
 #include linux/amd-iommu.h
 #include linux/export.h
+#include linux/acpi.h
+#include acpi/acpi.h
 #include asm/pci-direct.h
 #include asm/iommu.h
 #include asm/gart.h
@@ -122,7 +124,7 @@ struct ivmd_header {
 
 bool amd_iommu_dump;
 
-static int __initdata amd_iommu_detected;
+static bool amd_iommu_detected;
 static bool __initdata amd_iommu_disabled;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
@@ -149,11 +151,6 @@ bool amd_iommu_v2_present __read_mostly;
 bool amd_iommu_force_isolation __read_mostly;
 
 /*
- * The ACPI table parsing functions set this variable on an error
- */
-static int __initdata amd_iommu_init_err;
-
-/*
  * List of protection domains - used during resume
  */
 LIST_HEAD(amd_iommu_pd_list);
@@ -463,11 +460,9 @@ static int __init find_last_devid_acpi(struct 
acpi_table_header *table)
 */
for (i = 0; i  table-length; ++i)
checksum += p[i];
-   if (checksum != 0) {
+   if (checksum != 0)
/* ACPI table corrupt */
-   amd_iommu_init_err = -ENODEV;
-   return 0;
-   }
+   return -ENODEV;
 
p += IVRS_HEADER_LENGTH;
 
@@ -1093,16 +1088,12 @@ static int __init init_iommu_all(struct 
acpi_table_header *table)
h-mmio_phys);
 
iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
-   if (iommu == NULL) {
-   amd_iommu_init_err = -ENOMEM;
-   return 0;
-   }
+   if (iommu == NULL)
+   return -ENOMEM;
 
ret = init_iommu_one(iommu, h);
-   if (ret) {
-   amd_iommu_init_err = ret;
-   return 0;
-   }
+   if (ret)
+   return ret;
break;
default:
break;
@@ -1483,9 +1474,15 @@ static void __init free_on_init_error(void)
  */
 int __init amd_iommu_init_hardware(void)
 {
+   struct acpi_table_header *ivrs_base;
+   acpi_size ivrs_size;
+   acpi_status status;
int i, ret = 0;
 
-   if (!amd_iommu_detected)
+   if (no_iommu || (iommu_detected  !gart_iommu_aperture))
+   return -ENODEV;
+
+   if (amd_iommu_disabled || !amd_iommu_detected)
return -ENODEV;
 
if (amd_iommu_dev_table != NULL) {
@@ -1493,16 +1490,21 @@ int __init amd_iommu_init_hardware(void)
return 0;
}
 
+   status = acpi_get_table_with_size(IVRS, 0, ivrs_base, ivrs_size);
+   if (status == AE_NOT_FOUND)
+   return -ENODEV;
+   else if (ACPI_FAILURE(status)) {
+   const char *err = acpi_format_exception(status);
+   pr_err(AMD-Vi: IVRS table error: %s\n, err);
+   return -EINVAL;
+   }
+
/*
 * First parse ACPI tables to find the largest Bus/Dev/Func
 * we need to handle. Upon this information the shared data
 * structures for the IOMMUs in the system will be allocated
 */
-   if (acpi_table_parse(IVRS, find_last_devid_acpi) != 0)
-   return -ENODEV;
-
-   ret = amd_iommu_init_err;
-   if (ret)
+   if (find_last_devid_acpi(ivrs_base))
goto out;
 
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
@@ -1559,22 +1561,13 @@ int __init amd_iommu_init_hardware(void)
 * now the data structures are allocated and basically initialized
 * start the real acpi table scan
 */
-   ret = -ENODEV;
-   if (acpi_table_parse(IVRS, init_iommu_all) != 0)
-   goto free;
-
-   if (amd_iommu_init_err) {
-   ret = amd_iommu_init_err;
-   goto free;
-   }
-
-   if (acpi_table_parse(IVRS, init_memory_definitions) != 0)
+   ret = init_iommu_all(ivrs_base);
+   if (ret)
goto free;
 
-   if (amd_iommu_init_err) {
-   ret = amd_iommu_init_err;
+   ret = init_memory_definitions(ivrs_base);
+   if (ret)
goto free;
-   }
 
ret = amd_iommu_init_devices();
if (ret)
@@ -1587,12 +1580,16 @@ int __init amd_iommu_init_hardware(void)
register_syscore_ops(amd_iommu_syscore_ops);
 
 out:

[PATCH 17/28] iommu/amd: Split device table initialization into irq and dma part

2012-07-05 Thread Joerg Roedel
When the IOMMU is enabled very early (as with irq-remapping)
some devices are still in BIOS hand. When dma is blocked
early this can cause lots of IO_PAGE_FAULTs. So delay the
DMA initialization and do it right before the dma_ops are
initialized.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c |   22 ++
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index e663f1d..453f80a 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1383,19 +1383,27 @@ static int __init init_memory_definitions(struct 
acpi_table_header *table)
  * Init the device table to not allow DMA access for devices and
  * suppress all page faults
  */
-static void init_device_table(void)
+static void init_device_table_dma(void)
 {
u32 devid;
 
for (devid = 0; devid = amd_iommu_last_bdf; ++devid) {
set_dev_entry_bit(devid, DEV_ENTRY_VALID);
set_dev_entry_bit(devid, DEV_ENTRY_TRANSLATION);
-
-   if (amd_iommu_irq_remap)
-   set_dev_entry_bit(devid, DEV_ENTRY_IRQ_TBL_EN);
}
 }
 
+static void init_device_table(void)
+{
+   u32 devid;
+
+   if (!amd_iommu_irq_remap)
+   return;
+
+   for (devid = 0; devid = amd_iommu_last_bdf; ++devid)
+   set_dev_entry_bit(devid, DEV_ENTRY_IRQ_TBL_EN);
+}
+
 static void iommu_init_flags(struct amd_iommu *iommu)
 {
iommu-acpi_flags  IVHD_FLAG_HT_TUN_EN_MASK ?
@@ -1783,8 +1791,14 @@ static bool detect_ivrs(void)
 
 static int amd_iommu_init_dma(void)
 {
+   struct amd_iommu *iommu;
int ret;
 
+   init_device_table_dma();
+
+   for_each_iommu(iommu)
+   iommu_flush_all_caches(iommu);
+
if (iommu_pass_through)
ret = amd_iommu_init_passthrough();
else
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 19/28] iommu/amd: Add IRTE invalidation routine

2012-07-05 Thread Joerg Roedel
Add routine to invalidate the IOMMU cache for interupt
translations. Also include the IRTE caches when flushing all
IOMMU caches.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c   |   27 +++
 drivers/iommu/amd_iommu_types.h |1 +
 2 files changed, 28 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 6282dab..7006605 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -834,6 +834,13 @@ static void build_inv_all(struct iommu_cmd *cmd)
CMD_SET_TYPE(cmd, CMD_INV_ALL);
 }
 
+static void build_inv_irt(struct iommu_cmd *cmd, u16 devid)
+{
+   memset(cmd, 0, sizeof(*cmd));
+   cmd-data[0] = devid;
+   CMD_SET_TYPE(cmd, CMD_INV_IRT);
+}
+
 /*
  * Writes the command to the IOMMUs command buffer and informs the
  * hardware about the new command.
@@ -955,12 +962,32 @@ static void iommu_flush_all(struct amd_iommu *iommu)
iommu_completion_wait(iommu);
 }
 
+static void iommu_flush_irt(struct amd_iommu *iommu, u16 devid)
+{
+   struct iommu_cmd cmd;
+
+   build_inv_irt(cmd, devid);
+
+   iommu_queue_command(iommu, cmd);
+}
+
+static void iommu_flush_irt_all(struct amd_iommu *iommu)
+{
+   u32 devid;
+
+   for (devid = 0; devid = 0x; ++devid)
+   iommu_flush_irt(iommu, devid);
+
+   iommu_completion_wait(iommu);
+}
+
 void iommu_flush_all_caches(struct amd_iommu *iommu)
 {
if (iommu_feature(iommu, FEATURE_IA)) {
iommu_flush_all(iommu);
} else {
iommu_flush_dte_all(iommu);
+   iommu_flush_irt_all(iommu);
iommu_flush_tlb_all(iommu);
}
 }
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 1155389..0791451 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -152,6 +152,7 @@
 #define CMD_INV_DEV_ENTRY   0x02
 #define CMD_INV_IOMMU_PAGES0x03
 #define CMD_INV_IOTLB_PAGES0x04
+#define CMD_INV_IRT0x05
 #define CMD_COMPLETE_PPR   0x07
 #define CMD_INV_ALL0x08
 
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 15/28] iommu/amd: Check if IOAPIC information is correct

2012-07-05 Thread Joerg Roedel
When the IOAPIC information provided in the IVRS table is
not correct or not complete the system may not boot at all
when interrupt remapping is enabled. So check if this
information is correct and print out a firmware bug message
when it is not.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu_init.c |   26 +++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 9dc0ebc..ed4e690 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1578,6 +1578,23 @@ static void __init free_on_init_error(void)
 #endif
 }
 
+static bool __init check_ioapic_information(void)
+{
+   int idx;
+
+   for (idx = 0; idx  nr_ioapics; ++idx) {
+   int id = mpc_ioapic_id(idx);
+
+   if (get_ioapic_devid(id)  0) {
+   pr_err(FW_BUG AMD-Vi: IO-APIC[%d] not in IVRS 
table\n, id);
+   pr_err(AMD-Vi: Disabling interrupt remapping due to 
BIOS Bug\n);
+   return false;
+   }
+   }
+
+   return true;
+}
+
 /*
  * This is the hardware init function for AMD IOMMU in the system.
  * This function is called either from amd_iommu_init or from the interrupt
@@ -1664,9 +1681,6 @@ static int __init early_amd_iommu_init(void)
if (amd_iommu_pd_alloc_bitmap == NULL)
goto out;
 
-   /* init the device table */
-   init_device_table();
-
/*
 * let all alias entries point to itself
 */
@@ -1689,6 +1703,9 @@ static int __init early_amd_iommu_init(void)
if (ret)
goto out;
 
+   if (amd_iommu_irq_remap)
+   amd_iommu_irq_remap = check_ioapic_information();
+
if (amd_iommu_irq_remap) {
/*
 * Interrupt remapping enabled, create kmem_cache for the
@@ -1712,6 +1729,9 @@ static int __init early_amd_iommu_init(void)
if (ret)
goto out;
 
+   /* init the device table */
+   init_device_table();
+
 out:
/* Don't leak any ACPI memory */
early_acpi_os_unmap_memory((char *)ivrs_base, ivrs_size);
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 26/28] iommu/irq: Use amd_iommu_irq_ops if supported

2012-07-05 Thread Joerg Roedel
Finally enable interrupt remapping for AMD systems.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/irq_remapping.c |5 +
 drivers/iommu/irq_remapping.h |1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 7a880c3..e2c06c1 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -47,6 +47,11 @@ early_param(intremap, setup_irqremap);
 void __init setup_irq_remapping_ops(void)
 {
remap_ops = intel_irq_remap_ops;
+
+#ifdef CONFIG_AMD_IOMMU
+   if (amd_iommu_irq_ops.prepare() == 0)
+   remap_ops = amd_iommu_irq_ops;
+#endif
 }
 
 int irq_remapping_supported(void)
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index b3f70c9..915a247 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -84,6 +84,7 @@ struct irq_remap_ops {
 };
 
 extern struct irq_remap_ops intel_irq_remap_ops;
+extern struct irq_remap_ops amd_iommu_irq_ops;
 
 #else  /* CONFIG_IRQ_REMAP */
 
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 22/28] iommu/amd: Implement MSI routines for interrupt remapping

2012-07-05 Thread Joerg Roedel
Add routines to setup interrupt remapping for MSI
interrupts.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c |   74 +
 1 file changed, 74 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index dc2e699..ee10f30 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4054,4 +4054,78 @@ static int free_irq(int irq)
return 0;
 }
 
+static void compose_msi_msg(struct pci_dev *pdev,
+   unsigned int irq, unsigned int dest,
+   struct msi_msg *msg, u8 hpet_id)
+{
+   struct irq_2_irte *irte_info;
+   struct irq_cfg *cfg;
+   union irte irte;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return;
+
+   irte_info = cfg-irq_remap_info.irq_2_irte;
+
+   irte.val= 0;
+   irte.fields.vector  = cfg-vector;
+   irte.fields.int_type= apic-irq_delivery_mode;
+   irte.fields.destination = dest;
+   irte.fields.dm  = apic-irq_dest_mode;
+   irte.fields.valid   = 1;
+
+   modify_irte(irte_info-devid, irte_info-index, irte);
+
+   msg-address_hi = MSI_ADDR_BASE_HI;
+   msg-address_lo = MSI_ADDR_BASE_LO;
+   msg-data   = irte_info-index;
+}
+
+static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
+{
+   struct irq_cfg *cfg;
+   int index;
+   u16 devid;
+
+   if (!pdev)
+   return -EINVAL;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return -EINVAL;
+
+   devid = get_device_id(pdev-dev);
+   index = alloc_irq_index(cfg, devid, nvec);
+
+   return index  0 ? MAX_IRQS_PER_TABLE : index;
+}
+
+static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
+int index, int offset)
+{
+   struct irq_2_irte *irte_info;
+   struct irq_cfg *cfg;
+   u16 devid;
+
+   if (!pdev)
+   return -EINVAL;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return -EINVAL;
+
+   if (index = MAX_IRQS_PER_TABLE)
+   return 0;
+
+   devid   = get_device_id(pdev-dev);
+   irte_info   = cfg-irq_remap_info.irq_2_irte;
+
+   irte_info-devid = devid;
+   irte_info-index = index + offset;
+   cfg-remapped= true;
+
+   return 0;
+}
+
 #endif
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 21/28] iommu/amd: Add IOAPIC remapping routines

2012-07-05 Thread Joerg Roedel
Add the routine to setup interrupt remapping for ioapic
interrupts. Also add a routine to change the affinity of an
irq and to free an irq allocation for interrupt remapping.
The last two functions will also be used for MSI interrupts.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c |  119 +
 1 file changed, 119 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 6ec44ab..dc2e699 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3935,4 +3935,123 @@ static void free_irte(u16 devid, int index)
iommu_completion_wait(iommu);
 }
 
+static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
+ unsigned int destination, int vector,
+ struct io_apic_irq_attr *attr)
+{
+   struct irq_remap_table *table;
+   struct irq_2_irte *irte_info;
+   struct irq_cfg *cfg;
+   union irte irte;
+   int ioapic_id;
+   int index;
+   int devid;
+   int ret;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return -EINVAL;
+
+   irte_info = cfg-irq_remap_info.irq_2_irte;
+   ioapic_id = mpc_ioapic_id(attr-ioapic);
+   devid = get_ioapic_devid(ioapic_id);
+
+   if (devid  0)
+   return devid;
+
+   table = get_irq_table(devid, true);
+   if (table == NULL)
+   return -ENOMEM;
+
+   index = attr-ioapic_pin;
+
+   /* Setup IRQ remapping info */
+   irte_info-devid = devid;
+   irte_info-index = index;
+   cfg-remapped= true;
+
+   /* Setup IRTE for IOMMU */
+   irte.val= 0;
+   irte.fields.vector  = vector;
+   irte.fields.int_type= apic-irq_delivery_mode;
+   irte.fields.destination = destination;
+   irte.fields.dm  = apic-irq_dest_mode;
+   irte.fields.valid   = 1;
+
+   ret = modify_irte(devid, index, irte);
+   if (ret)
+   return ret;
+
+   /* Setup IOAPIC entry */
+   memset(entry, 0, sizeof(*entry));
+
+   entry-vector= index;
+   entry-mask  = 0;
+   entry-trigger   = attr-trigger;
+   entry-polarity  = attr-polarity;
+
+   /*
+* Mask level triggered irqs.
+* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
+*/
+   if (attr-trigger)
+   entry-mask = 1;
+
+   return 0;
+}
+
+#ifdef CONFIG_SMP
+static int set_affinity(struct irq_data *data, const struct cpumask *mask,
+   bool force)
+{
+   struct irq_2_irte *irte_info;
+   unsigned int dest, irq;
+   struct irq_cfg *cfg;
+   union irte irte;
+
+   cfg   = data-chip_data;
+   irq   = data-irq;
+   irte_info = cfg-irq_remap_info.irq_2_irte;
+
+   if (!cpumask_intersects(mask, cpu_online_mask))
+   return -EINVAL;
+
+   if (get_irte(irte_info-devid, irte_info-index, irte))
+   return -EBUSY;
+
+   if (assign_irq_vector(irq, cfg, mask))
+   return -EBUSY;
+
+   dest = apic-cpu_mask_to_apicid_and(cfg-domain, mask);
+
+   irte.fields.vector  = cfg-vector;
+   irte.fields.destination = dest;
+
+   modify_irte(irte_info-devid, irte_info-index, irte);
+
+   if (cfg-move_in_progress)
+   send_cleanup_vector(cfg);
+
+   cpumask_copy(data-affinity, mask);
+
+   return 0;
+}
+#endif /* CONFIG_SMP */
+
+static int free_irq(int irq)
+{
+   struct irq_2_irte *irte_info;
+   struct irq_cfg *cfg;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return -EINVAL;
+
+   irte_info = cfg-irq_remap_info.irq_2_irte;
+
+   free_irte(irte_info-devid, irte_info-index);
+
+   return 0;
+}
+
 #endif
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 20/28] iommu/amd: Add routines to manage irq remapping tables

2012-07-05 Thread Joerg Roedel
Add routines to:

* Alloc remapping tables and single entries from these
  tables
* Change entries in the tables
* Free entries in the table

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c |  230 +
 1 file changed, 230 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 7006605..6ec44ab 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -31,6 +31,12 @@
 #include linux/amd-iommu.h
 #include linux/notifier.h
 #include linux/export.h
+#include linux/irq.h
+#include linux/msi.h
+#include asm/irq_remapping.h
+#include asm/io_apic.h
+#include asm/apic.h
+#include asm/hw_irq.h
 #include asm/msidef.h
 #include asm/proto.h
 #include asm/iommu.h
@@ -3706,3 +3712,227 @@ int amd_iommu_device_info(struct pci_dev *pdev,
return 0;
 }
 EXPORT_SYMBOL(amd_iommu_device_info);
+
+#ifdef CONFIG_IRQ_REMAP
+
+/*
+ *
+ * Interrupt Remapping Implementation
+ *
+ */
+
+union irte {
+   u32 val;
+   struct {
+   u32 valid   : 1,
+   no_fault: 1,
+   int_type: 3,
+   rq_eoi  : 1,
+   dm  : 1,
+   rsvd_1  : 1,
+   destination : 8,
+   vector  : 8,
+   rsvd_2  : 8;
+   } fields;
+};
+
+#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL  45)-1)  6)
+#define DTE_IRQ_REMAP_INTCTL(2ULL  60)
+#define DTE_IRQ_TABLE_LEN   (8ULL  1)
+#define DTE_IRQ_REMAP_ENABLE1ULL
+
+static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
+{
+   u64 dte;
+
+   dte = amd_iommu_dev_table[devid].data[2];
+   dte = ~DTE_IRQ_PHYS_ADDR_MASK;
+   dte |= virt_to_phys(table-table);
+   dte |= DTE_IRQ_REMAP_INTCTL;
+   dte |= DTE_IRQ_TABLE_LEN;
+   dte |= DTE_IRQ_REMAP_ENABLE;
+
+   amd_iommu_dev_table[devid].data[2] = dte;
+}
+
+#define IRTE_ALLOCATED (~1U)
+
+static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic)
+{
+   struct irq_remap_table *table = NULL;
+   struct amd_iommu *iommu;
+   unsigned long flags;
+   u16 alias;
+
+   write_lock_irqsave(amd_iommu_devtable_lock, flags);
+
+   iommu = amd_iommu_rlookup_table[devid];
+   if (!iommu)
+   goto out_unlock;
+
+   table = irq_lookup_table[devid];
+   if (table)
+   goto out;
+
+   alias = amd_iommu_alias_table[devid];
+   table = irq_lookup_table[alias];
+   if (table) {
+   irq_lookup_table[devid] = table;
+   set_dte_irq_entry(devid, table);
+   iommu_flush_dte(iommu, devid);
+   goto out;
+   }
+
+   /* Nothing there yet, allocate new irq remapping table */
+   table = kzalloc(sizeof(*table), GFP_ATOMIC);
+   if (!table)
+   goto out;
+
+   if (ioapic)
+   /* Keep the first 32 indexes free for IOAPIC interrupts */
+   table-min_index = 32;
+
+   table-table = kmem_cache_alloc(amd_iommu_irq_cache, GFP_ATOMIC);
+   if (!table-table) {
+   kfree(table);
+   goto out;
+   }
+
+   memset(table-table, 0, MAX_IRQS_PER_TABLE * sizeof(u32));
+
+   if (ioapic) {
+   int i;
+
+   for (i = 0; i  32; ++i)
+   table-table[i] = IRTE_ALLOCATED;
+   }
+
+   irq_lookup_table[devid] = table;
+   set_dte_irq_entry(devid, table);
+   iommu_flush_dte(iommu, devid);
+   if (devid != alias) {
+   irq_lookup_table[alias] = table;
+   set_dte_irq_entry(devid, table);
+   iommu_flush_dte(iommu, alias);
+   }
+
+out:
+   iommu_completion_wait(iommu);
+
+out_unlock:
+   write_unlock_irqrestore(amd_iommu_devtable_lock, flags);
+
+   return table;
+}
+
+static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
+{
+   struct irq_remap_table *table;
+   unsigned long flags;
+   int index, c;
+
+   table = get_irq_table(devid, false);
+   if (!table)
+   return -ENODEV;
+
+   spin_lock_irqsave(table-lock, flags);
+
+   /* Scan table for free entries */
+   for (c = 0, index = table-min_index;
+index  MAX_IRQS_PER_TABLE;
+++index) {
+   if (table-table[index] == 0)
+   c += 1;
+   else
+   c = 0;
+
+   if (c == count) {
+   struct irq_2_irte *irte_info;
+
+   for (; c != 0; --c)
+   table-table[index - c + 1] = IRTE_ALLOCATED;
+
+   index -= count - 1;
+
+   irte_info= 

[PATCH 23/28] iommu/amd: Add call-back routine for HPET MSI

2012-07-05 Thread Joerg Roedel
Add a routine to setup a HPET MSI interrupt for remapping.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c |   26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index ee10f30..fed1395 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4128,4 +4128,30 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned 
int irq,
return 0;
 }
 
+static int setup_hpet_msi(unsigned int irq, unsigned int id)
+{
+   struct irq_2_irte *irte_info;
+   struct irq_cfg *cfg;
+   int index, devid;
+
+   cfg = irq_get_chip_data(irq);
+   if (!cfg)
+   return -EINVAL;
+
+   irte_info = cfg-irq_remap_info.irq_2_irte;
+   devid = get_hpet_devid(id);
+   if (devid  0)
+   return devid;
+
+   index = alloc_irq_index(cfg, devid, 1);
+   if (index  0)
+   return index;
+
+   irte_info-devid = devid;
+   irte_info-index = index;
+   cfg-remapped= true;
+
+   return 0;
+}
+
 #endif
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 28/28] iommu/amd: Report irq remapping through IOMMU-API

2012-07-05 Thread Joerg Roedel
Report the availability of irq remapping through the
IOMMU-API to allow KVM device passthrough again without
additional module parameter overrides.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 41fe178..e9d08f8 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3265,6 +3265,8 @@ static int amd_iommu_domain_has_cap(struct iommu_domain 
*domain,
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return 1;
+   case IOMMU_CAP_INTR_REMAP:
+   return irq_remapping_enabled;
}
 
return 0;
-- 
1.7.9.5


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[iommu:irq-remapping 7/28] WARNING: drivers/iommu/built-in.o(.text+0x617a): Section mismatch in reference from the function amd_iommu_init_pci() to the function .init.text:amd_iommu_init_devices()

2012-07-05 Thread wfg
Hi Joerg,

There are new compile warnings show up in

tree:   git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git 
irq-remapping
head:   afd6b14061a786c34b41722d35035d0eeecae55c
commit: ac2ff05e6451271c6744e9c9d9742de40575dbce [7/28] iommu/amd: Introduce 
early_amd_iommu_init routine

All warnings:


WARNING: drivers/iommu/built-in.o(.text+0x617a): Section mismatch in reference 
from the function amd_iommu_init_pci() to the function 
.init.text:amd_iommu_init_devices()
The function amd_iommu_init_pci() references
the function __init amd_iommu_init_devices().
This is often because amd_iommu_init_pci lacks a __init 
annotation or the annotation of amd_iommu_init_devices is wrong.


WARNING: drivers/iommu/built-in.o(.text+0x6a18): Section mismatch in reference 
from the function amd_iommu_init_hardware() to the function 
.init.text:early_amd_iommu_init()
The function amd_iommu_init_hardware() references
the function __init early_amd_iommu_init().
This is often because amd_iommu_init_hardware lacks a __init 
annotation or the annotation of early_amd_iommu_init is wrong.


WARNING: drivers/built-in.o(.text+0x13ec1a): Section mismatch in reference from 
the function amd_iommu_init_pci() to the function 
.init.text:amd_iommu_init_devices()
The function amd_iommu_init_pci() references
the function __init amd_iommu_init_devices().
This is often because amd_iommu_init_pci lacks a __init 
annotation or the annotation of amd_iommu_init_devices is wrong.


WARNING: drivers/built-in.o(.text+0x13f4b8): Section mismatch in reference from 
the function amd_iommu_init_hardware() to the function 
.init.text:early_amd_iommu_init()
The function amd_iommu_init_hardware() references
the function __init early_amd_iommu_init().
This is often because amd_iommu_init_hardware lacks a __init 
annotation or the annotation of early_amd_iommu_init is wrong.


WARNING: vmlinux.o(.text+0x4de732): Section mismatch in reference from the 
function amd_iommu_init_pci() to the function 
.init.text:amd_iommu_init_devices()
The function amd_iommu_init_pci() references
the function __init amd_iommu_init_devices().
This is often because amd_iommu_init_pci lacks a __init 
annotation or the annotation of amd_iommu_init_devices is wrong.


WARNING: vmlinux.o(.text+0x4defd0): Section mismatch in reference from the 
function amd_iommu_init_hardware() to the function 
.init.text:early_amd_iommu_init()
The function amd_iommu_init_hardware() references
the function __init early_amd_iommu_init().
This is often because amd_iommu_init_hardware lacks a __init 
annotation or the annotation of early_amd_iommu_init is wrong.

---
0-DAY kernel build testing backend Open Source Technology Centre
Fengguang Wu w...@linux.intel.com Intel Corporation
From ac2ff05e6451271c6744e9c9d9742de40575dbce Mon Sep 17 00:00:00 2001
From: Joerg Roedel joerg.roe...@amd.com
Date: Tue, 12 Jun 2012 12:09:35 +0200
Subject: [PATCH] iommu/amd: Introduce early_amd_iommu_init routine

Split out the code to parse the ACPI table and setup
relevant data structures into a new function.

Signed-off-by: Joerg Roedel joerg.roe...@amd.com
---
 drivers/iommu/amd_iommu.c  |1 -
 drivers/iommu/amd_iommu_init.c |   38 +++---
 2 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a2e418c..cfa01c4 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -376,19 +376,18 @@ DECLARE_STATS_COUNTER(cross_page);
 DECLARE_STATS_COUNTER(domain_flush_single);
 DECLARE_STATS_COUNTER(domain_flush_all);
 DECLARE_STATS_COUNTER(alloced_io_mem);
 DECLARE_STATS_COUNTER(total_map_requests);
 DECLARE_STATS_COUNTER(complete_ppr);
 DECLARE_STATS_COUNTER(invalidate_iotlb);
 DECLARE_STATS_COUNTER(invalidate_iotlb_all);
 DECLARE_STATS_COUNTER(pri_requests);
 
-
 static struct dentry *stats_dir;
 static struct dentry *de_fflush;
 
 static void amd_iommu_stats_add(struct __iommu_counter *cnt)
 {
 	if (stats_dir == NULL)
 		return;
 
 	cnt-dent = debugfs_create_u64(cnt-name, 0444, stats_dir,
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index e6782fa..1b23235 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1488,29 +1488,26 @@ static void __init free_on_init_error(void)
  *
  *	3 pass) After the basic data structures are allocated and
  *		initialized we update them with information about memory
  *		remapping requirements parsed out of the ACPI table in
  *		this last pass.
  *
  * After everything is set up the IOMMUs are enabled and the necessary
  * hotplug and suspend notifiers are registered.
  */
-int __init amd_iommu_init_hardware(void)
+static int __init early_amd_iommu_init(void)
 {
 	struct acpi_table_header *ivrs_base;
 	acpi_size ivrs_size;
 	acpi_status status;
 	int i, ret = 0;
 
-	if (no_iommu || (iommu_detected  !gart_iommu_aperture))
-		return -ENODEV;
-
-	if (amd_iommu_disabled || 

Re: [PATCH 06/28] iommu/amd: Move informational prinks out of iommu_enable

2012-07-05 Thread Joe Perches
On Thu, 2012-07-05 at 14:36 +0200, Joerg Roedel wrote:
 This function will be called before the PCI subsystem is
 initialized. Therefore dev_name doen't work and IOMMU
 information can't be printed to the klog as before. Move the
 code to print that information to a later point where PCI
 initializtion has already happened.
[]
 diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
[]
 @@ -1102,6 +1085,28 @@ static int iommu_init_pci(struct amd_iommu *iommu)
[]
 +static void print_iommu_info(void)
 +{
 + static const char * const feat_str[] = {
 + PreF, PPR, X2APIC, NX, GT, [5],
 + IA, GA, HE, PC, NULL
 + };
 + struct amd_iommu *iommu;
 +
 + for_each_iommu(iommu) {
 + int i;
 + pr_info(AMD-Vi: Found IOMMU at %s cap 0x%hx\n,
 + dev_name(iommu-dev-dev), iommu-cap_ptr);
 + if (iommu-cap  (1  IOMMU_CAP_EFR)) {
 + pr_info(AMD-Vi:  Extended features: );
 + for (i = 0; feat_str[i]; ++i)
 + if (iommu_feature(iommu, (1ULL  i)))
 + pr_cont( %s, feat_str[i]);

I think this should use {} around the for loop
and this would be better as:

static const char * const feat_str[] = {
PreF, PPR, X2APIC, NX, GT, [5],
IA, GA, HE, PC
};
[]
for (i = 0; ARRAY_SIZE(feat_str); i++) {
if (iommu_feature(iommu, (1ULL  i)))
pr_cont( %s, feat_str[i]);
}

I don't see the utility of the separate function and
this could just be inlined in the calling function.

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu