Re: [PATCH v11 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-05-30 Thread Li, Zhen-Hua

Thank you very much for this.

zhenhua

From My iPhone

> 在 2015年5月30日,00:22,Joerg Roedel  写道:
> 
>> On Mon, May 11, 2015 at 05:52:44PM +0800, Li, Zhen-Hua wrote:
>> Li, Zhen-Hua (10):
>>  iommu/vt-d: New function to attach domain with id
>>  iommu/vt-d: Items required for kdump
>>  iommu/vt-d: Function to get existing context entry
>>  iommu/vt-d: functions to copy data from old mem
>>  iommu/vt-d: Add functions to load and save old re
>>  iommu/vt-d: datatypes and functions used for kdump
>>  iommu/vt-d: enable kdump support in iommu module
>>  iommu/vt-d: assign new page table for dma_map
>>  iommu/vt-d: Copy functions for irte
>>  iommu/vt-d: Use old irte in kdump kernel
>> 
>> drivers/iommu/intel-iommu.c | 536 
>> ++--
>> drivers/iommu/intel_irq_remapping.c |  96 ++-
>> include/linux/intel-iommu.h |  16 ++
>> 3 files changed, 623 insertions(+), 25 deletions(-)
> 
> Applied with a few minor changes, thanks.
> 
N�Р骒r��yb�X�肚�v�^�)藓{.n�+�伐�{��赙zXФ�≤�}��财�z�&j:+v�����赙zZ+��+zf"�h���~i���z��wア�?�ㄨ��&�)撷f��^j谦y�m��@A�a囤�
0鹅h���i

Re: [PATCH v11 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-05-12 Thread Li, Zhen-Hua
ables, keep using the old ones.
>   3. Remove functions:
>  intel_iommu_did_to_domain_values_entry
>  intel_iommu_get_dids_from_old_kernel
>  device_to_domain_id
>  copy_page_addr
>  copy_page_table
>  copy_context_entry
>  copy_context_entry_table
>   4. Add new function device_to_existing_context_entry.
> 
> Changelog[v8]:
>   1. Add a missing __iommu_flush_cache in function copy_page_table.
> 
> Changelog[v7]:
>   1. Use __iommu_flush_cache to flush the data to hardware.
> 
> Changelog[v6]:
>   1. Use "unsigned long" as type of physical address.
>   2. Use new function unmap_device_dma to unmap the old dma.
>   3. Some small incorrect bits order for aw shift.
> 
> Changelog[v5]:
>   1. Do not disable and re-enable traslation and interrupt remapping. 
>   2. Use old root entry table.
>   3. Use old interrupt remapping table.
>   4. New functions to copy data from old kernel, and save to old kernel mem.
>   5. New functions to save updated root entry table and irte table.
>   6. Use intel_unmap to unmap the old dma;
>   7. Allocate new pages while driver is being loaded.
> 
> Changelog[v4]:
>   1. Cut off the patches that move some defines and functions to new files.
>   2. Reduce the numbers of patches to five, make it more easier to read.
>   3. Changed the name of functions, make them consistent with current context
>  get/set functions.
>   4. Add change to function __iommu_attach_domain.
> 
> Changelog[v3]:
>   1. Commented-out "#define DEBUG 1" to eliminate debug messages.
>   2. Updated the comments about changes in each version.
>   3. Fixed: one-line added to Copy-Translations patch to initialize the iovad
> struct as recommended by Baoquan He [b...@redhat.com]
> init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
> 
> Changelog[v2]:
>   The following series implements a fix for:
>   A kdump problem about DMA that has been discussed for a long time. That is,
>   when a kernel panics and boots into the kdump kernel, DMA started by the
>   panicked kernel is not stopped before the kdump kernel is booted and the
>   kdump kernel disables the IOMMU while this DMA continues.  This causes the
>   IOMMU to stop translating the DMA addresses as IOVAs and begin to treat
>   them as physical memory addresses -- which causes the DMA to either:
>   (1) generate DMAR errors or 
>   (2) generate PCI SERR errors or 
>       (3) transfer data to or from incorrect areas of memory. Often this 
>   causes the dump to fail.
> 
> Changelog[v1]:
>   The original version.
> 
> Changed in this version:
> 1. Do not disable and re-enable traslation and interrupt remapping. 
> 2. Use old root entry table.
> 3. Use old interrupt remapping table.
> 4. Use "unsigned long" as physical address.
> 5. Use intel_unmap to unmap the old dma;
> 
> Baoquan He  helps testing this patchset.
> Takao Indoh  gives valuable suggestions.
> 
> Li, Zhen-Hua (10):
> iommu/vt-d: New function to attach domain with id
> iommu/vt-d: Items required for kdump
> iommu/vt-d: Function to get existing context entry
> iommu/vt-d: functions to copy data from old mem
> iommu/vt-d: Add functions to load and save old re
> iommu/vt-d: datatypes and functions used for kdump
> iommu/vt-d: enable kdump support in iommu module
> iommu/vt-d: assign new page table for dma_map
> iommu/vt-d: Copy functions for irte
> iommu/vt-d: Use old irte in kdump kernel
> 
> drivers/iommu/intel-iommu.c | 536 ++--
> drivers/iommu/intel_irq_remapping.c |  96 ++-
> include/linux/intel-iommu.h |  16 ++
> 3 files changed, 623 insertions(+), 25 deletions(-)
> 
> -- 
> 2.0.0-rc0
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 01/10] iommu/vt-d: New function to attach domain with id

2015-05-11 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds a new function iommu_attach_domain_with_id, it is like
the function iommu_attach_domain(), only adding a parameter "did".

Bill Sumner:
(In older versions) Add new 'did' parameter to iommu_attach_domain();
The caller of this function.

Li, Zhenhua:
New function iommu_attach_domain_with_id(), instead of updating function
iommu_attach_domain();

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 68d43be..cb9d6cc 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1552,6 +1552,16 @@ static int iommu_attach_domain(struct dmar_domain 
*domain,
return num;
 }
 
+static int iommu_attach_domain_with_id(struct dmar_domain *domain,
+  struct intel_iommu *iommu,
+  int domain_number)
+{
+   if (domain_number >= 0)
+   return domain_number;
+
+   return iommu_attach_domain(domain, iommu);
+}
+
 static int iommu_attach_vm_domain(struct dmar_domain *domain,
  struct intel_iommu *iommu)
 {
@@ -2220,6 +2230,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2253,7 +2264,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain_with_id(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 05/10] iommu/vt-d: Add functions to load and save old re

2015-05-11 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Add __iommu_flush_cache.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 54 -
 include/linux/intel-iommu.h |  3 +++
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0b97c15..3a5d446 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -371,6 +371,10 @@ static struct context_entry 
*device_to_existing_context_entry(
struct intel_iommu *iommu,
u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
+
 /*
  * A structure used to store the address allocated by ioremap();
  * The we need to call iounmap() to free them out of spin_lock_irqsave/unlock;
@@ -382,7 +386,6 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
-
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
@@ -4935,3 +4938,52 @@ int __iommu_free_mapped_mem(void)
return 0;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+}
+
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index ced1fac..e7cac12 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -340,6 +340,9 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+   void __iomem*root_entry_old_virt; /* mapped from old root entry */
+   unsigned long   root_entry_old_phys; /* root entry in old kernel */
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 08/10] iommu/vt-d: assign new page table for dma_map

2015-05-11 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a device, we
assign a new and empty page-table, thus removing all mappings from the
old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 58 ++---
 1 file changed, 50 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 91545bf..3cc1027 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -396,6 +396,9 @@ static int copy_root_entry_table(struct intel_iommu *iommu);
 
 static int intel_iommu_load_translation_tables(struct intel_iommu *iommu);
 
+static void unmap_device_dma(struct dmar_domain *domain,
+   struct device *dev,
+   struct intel_iommu *iommu);
 static void iommu_check_pre_te_status(struct intel_iommu *iommu);
 static u8 g_translation_pre_enabled;
 
@@ -3115,6 +3118,7 @@ static struct iova *intel_alloc_iova(struct device *dev,
 static struct dmar_domain *__get_valid_domain_for_dev(struct device *dev)
 {
struct dmar_domain *domain;
+   struct intel_iommu *iommu;
int ret;
 
domain = get_domain_for_dev(dev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
@@ -3124,14 +3128,30 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
return NULL;
}
 
-   /* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   /* if in kdump kernel, we need to unmap the mapped dma pages,
+* detach this device first.
+*/
+   if (likely(domain_context_mapped(dev))) {
+   iommu = domain_get_iommu(domain);
+   if (iommu->pre_enabled_trans) {
+   unmap_device_dma(domain, dev, iommu);
+
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+   return domain;
+   }
+
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
}
 
return domain;
@@ -5168,6 +5188,28 @@ static int intel_iommu_load_translation_tables(struct 
intel_iommu *iommu)
return ret;
 }
 
+static void unmap_device_dma(struct dmar_domain *domain,
+   struct device *dev,
+   struct intel_iommu *iommu)
+{
+   struct context_entry *ce;
+   struct iova *iova;
+   phys_addr_t phys_addr;
+   dma_addr_t dev_addr;
+   struct pci_dev *pdev;
+
+   pdev = to_pci_dev(dev);
+   ce = iommu_context_addr(iommu, pdev->bus->number, pdev->devfn, 1);
+   phys_addr = context_address_root(ce) << VTD_PAGE_SHIFT;
+   dev_addr = phys_to_dma(dev, phys_addr);
+
+   iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+   if (iova)
+   intel_unmap(dev, dev_addr);
+
+   domain_remove_one_dev_info(domain, dev);
+}
+
 static void iommu_check_pre_te_status(struct intel_iommu *iommu)
 {
u32 sts;
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 04/10] iommu/vt-d: functions to copy data from old mem

2015-05-11 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Check if pfn is ram:
if (page_is_ram(pfn))

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 102 
 include/linux/intel-iommu.h |   6 +++
 2 files changed, 108 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 07e6118..0b97c15 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -371,6 +371,17 @@ static struct context_entry 
*device_to_existing_context_entry(
struct intel_iommu *iommu,
u8 bus, u8 devfn);
 
+/*
+ * A structure used to store the address allocated by ioremap();
+ * The we need to call iounmap() to free them out of spin_lock_irqsave/unlock;
+ */
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 
 /*
  * This domain is a statically identity mapping domain.
@@ -4833,3 +4844,94 @@ static struct context_entry 
*device_to_existing_context_entry(
return ret;
 }
 
+/*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 796ef96..ced1fac 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -380,4 +380,10 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *int

[PATCH v11 07/10] iommu/vt-d: enable kdump support in iommu module

2015-05-11 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
iommu_context_addr
free_context_table
get_domain_for_dev
init_dmars
intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
The name of new calling functions.
Do not disable and re-enable TE in kdump kernel.
Use the did and gaw from old context entry;

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 95 +++--
 1 file changed, 83 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 28c3c64..91545bf 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -397,6 +397,7 @@ static int copy_root_entry_table(struct intel_iommu *iommu);
 static int intel_iommu_load_translation_tables(struct intel_iommu *iommu);
 
 static void iommu_check_pre_te_status(struct intel_iommu *iommu);
+static u8 g_translation_pre_enabled;
 
 /*
  * This domain is a statically identity mapping domain.
@@ -794,6 +795,9 @@ static inline struct context_entry 
*iommu_context_addr(struct intel_iommu *iommu
phy_addr = virt_to_phys((void *)context);
*entry = phy_addr | 1;
__iommu_flush_cache(iommu, entry, sizeof(*entry));
+
+   if (iommu->pre_enabled_trans)
+   __iommu_update_old_root_entry(iommu, bus);
}
return &context[devfn];
 }
@@ -887,13 +891,15 @@ static void clear_context_table(struct intel_iommu 
*iommu, u8 bus, u8 devfn)
 
 static void free_context_table(struct intel_iommu *iommu)
 {
+   struct root_entry *root = NULL;
int i;
unsigned long flags;
struct context_entry *context;
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
context = iommu_context_addr(iommu, i, 0, 0);
@@ -908,10 +914,23 @@ static void free_context_table(struct intel_iommu *iommu)
free_pgtable_page(context);
 
}
+
+   if (iommu->pre_enabled_trans) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry_old_virt;
+   iommu->root_entry_old_virt = NULL;
+   }
+
free_pgtable_page(iommu->root_entry);
iommu->root_entry = NULL;
-out:
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+   /* We put this out of spin_unlock is because iounmap() may
+* cause error if surrounded by spin_lock and unlock;
+*/
+   if (iommu->pre_enabled_trans)
+   iounmap(root);
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2333,6 +2352,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+   struct context_entry *ce = NULL;
 
domain = find_domain(dev);
if (domain)
@@ -2366,6 +2386,20 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+   if (iommu->pre_enabled_trans) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   ce = device_to_existing_context_entry(iommu, bus, devfn);
+
+   if (ce) {
+   did = context_domain_id(ce);
+   gaw = agaw_to_width(context_address_width(ce));
+   }
+   }
+
domain->id = iommu_attach_domain_with_id(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2897,6 +2931,7 @@ static int __init init_dmars(void)
goto free_g_iommus;
}
 
+   g_translation_pre_enabled = 0; /* To know whether to skip RMRR */
for_each_active_iommu(iommu, drhd) {
g_iommus[iommu->seq_id] = iommu;
 
@@ -2904,14 +2939,30 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+   iommu_check_pre_te_status(iommu);
+   if (iommu->pre_enabled_trans) {
+   pr_info("IOMMU Copying translate tables from panicked 
kernel\n");
+  

[PATCH v11 06/10] iommu/vt-d: datatypes and functions used for kdump

2015-05-11 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
Use old root entry table, and load the old data to root_entry as cache.
Malloc new context table and copy old context table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Create new function iommu_check_pre_te_status() to check status.
Update the caller of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that loads root entry table.
Use new function to copy old context entry tables and page tables.
Use "unsigned long" for physical address.
Remove the functions to copy page table in Bill's version.
Remove usage of dve and ppap in Bill's version.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 121 
 include/linux/intel-iommu.h |   3 ++
 2 files changed, 124 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 3a5d446..28c3c64 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -386,6 +386,18 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_load_translation_tables()
+ * 
+ */
+
+static int copy_root_entry_table(struct intel_iommu *iommu);
+
+static int intel_iommu_load_translation_tables(struct intel_iommu *iommu);
+
+static void iommu_check_pre_te_status(struct intel_iommu *iommu);
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
@@ -4987,3 +4999,112 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
__iommu_flush_cache(iommu, to + start, size);
 }
 
+/*
+ * Load root entry tables from old kernel.
+ */
+static int copy_root_entry_table(struct intel_iommu *iommu)
+{
+   u32 bus;/* Index: root-entry-table */
+   struct root_entry  *re; /* Virt(iterator: new table) */
+   unsigned long context_old_phys; /* Phys(context table entry) */
+   struct context_entry *context_new_virt; /* Virt(new context_entry) */
+
+   /*
+* A new root entry table has been allocated ,
+* we need copy re from old kernel to the new allocated one.
+*/
+
+   if (!iommu->root_entry_old_phys)
+   return -ENOMEM;
+
+   for (bus = 0, re = iommu->root_entry; bus < 256; bus += 1, re += 1) {
+   if (!root_present(re))
+   continue;
+
+   context_old_phys = get_context_phys_from_root(re);
+
+   if (!context_old_phys)
+   continue;
+
+   context_new_virt =
+   (struct context_entry *)alloc_pgtable_page(iommu->node);
+
+   if (!context_new_virt)
+   return -ENOMEM;
+
+   __iommu_load_from_oldmem(context_new_virt,
+   context_old_phys,
+   VTD_PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, context_new_virt, VTD_PAGE_SIZE);
+
+   set_root_value(re, virt_to_phys(context_new_virt));
+   }
+
+   return 0;
+}
+
+/*
+ * Interface to the "load translation tables" set of functions
+ * from mainline code.
+ */
+static int intel_iommu_load_translation_tables(struct intel_iommu *iommu)
+{
+   unsigned long long q;   /* quadword scratch */
+   int ret = 0;/* Integer return code */
+   unsigned long flags;
+
+   q = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
+   if (!q)
+   return -1;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+
+   /* Load the root-entry table from the old kernel
+* foreach context_entry_table in root_entry
+*   Copy each entry table from old kernel
+*/
+   if (!iommu->root_entry) {
+   iommu->root_entry =
+   (struct root_entry *)alloc_pgtable_page(iommu->node);
+   if (!iommu->root_entry) {
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return -ENOMEM;
+   }
+   }
+
+   iommu->root_entry_old_phys = q & VTD_PAGE_MASK;
+   if (!iommu->root_entry_old_phys) {
+   pr_err("Could not read old root entry address.");
+   

[PATCH v11 09/10] iommu/vt-d: Copy functions for irte

2015-05-11 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 68 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 72 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 5709ae9..c2a4406 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -17,6 +17,10 @@
 
 #include "irq_remapping.h"
 
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+static void iommu_check_pre_ir_status(struct intel_iommu *iommu);
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1299,3 +1303,67 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   __iommu_flush_cache(iommu, iommu->ir_table->base,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+
+   return 0;
+}
+
+static void iommu_check_pre_ir_status(struct intel_iommu *iommu)
+{
+   u32 sts;
+
+   sts = readl(iommu->reg + DMAR_GSTS_REG);
+   if (sts & DMA_GSTS_IRES) {
+   pr_info("IR is enabled prior to OS.\n");
+   iommu->pre_enabled_ir = 1;
+   }
+}
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 90e122e..d7a0b5d 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -301,6 +301,8 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
 };
 #endif
 
@@ -342,6 +344,8 @@ struct intel_iommu {
 
/* whether translation is enabled prior to OS*/
u8  pre_enabled_trans;
+   /* whether interrupt remapping is enabled prior to OS*/
+   u8  pre_enabled_ir;
 
void __iomem*root_entry_old_virt; /* mapped from old root entry */
unsigned long   root_entry_old_phys; /* root entry in old kernel */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 10/10] iommu/vt-d: Use old irte in kdump kernel

2015-05-11 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in second kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 28 
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index c2a4406..46d80ad 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -197,6 +197,10 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+   if (iommu->pre_enabled_ir)
+   __iommu_update_old_irte(iommu, index);
+
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -258,6 +262,9 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+   if (iommu->pre_enabled_ir)
+   __iommu_update_old_irte(iommu, -1);
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -657,11 +664,13 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
+   iommu_check_pre_ir_status(iommu);
+
/*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
+* Here we do not disable intr remapping,
+* if already enabled prior to OS handover.
 */
-   iommu_disable_irq_remapping(iommu);
+   /* iommu_disable_irq_remapping(iommu); */
 
dmar_disable_qi(iommu);
}
@@ -697,7 +706,18 @@ static int __init intel_enable_irq_remapping(void)
 * Setup Interrupt-remapping for all the DRHD's now.
 */
for_each_iommu(iommu, drhd) {
-   iommu_set_irq_remapping(iommu, eim);
+   if (iommu->pre_enabled_ir) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+   iommu_set_irq_remapping(iommu, eim);
+
setup = true;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 02/10] iommu/vt-d: Items required for kdump

2015-05-11 Thread Li, Zhen-Hua
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.
Remove the structure dve which is not used in new version.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 72 +
 1 file changed, 72 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index cb9d6cc..1e7ceb5 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -190,6 +190,31 @@ struct root_entry {
 };
 #define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
 
+static inline bool root_present(struct root_entry *root)
+{
+   return (root->lo & 1);
+}
+
+static inline void set_root_value(struct root_entry *root, unsigned long value)
+{
+   root->lo &= ~VTD_PAGE_MASK;
+   root->lo |= value & VTD_PAGE_MASK;
+}
+
+static inline struct context_entry *
+get_context_addr_from_root(struct root_entry *root)
+{
+   return (struct context_entry *)
+   (root_present(root)?phys_to_virt(
+   root->lo & VTD_PAGE_MASK) :
+   NULL);
+}
+
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->lo & VTD_PAGE_MASK) : 0;
+}
 
 /*
  * low 64 bits:
@@ -211,6 +236,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -296,6 +347,27 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating.
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Allocate pages for new context entry, copy data from old context entries
+ *in the old kernel to the new ones.
+ *
+ * In other kinds of kernel, for example, a kernel started by kexec,
+ * do the same thing as crashdump kernel.
+ */
+
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 03/10] iommu/vt-d: Function to get existing context entry

2015-05-11 Thread Li, Zhen-Hua
Interface for when a new domain in the old kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1e7ceb5..07e6118 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -367,6 +367,10 @@ static inline int first_pte_in_page(struct dma_pte *pte)
  * do the same thing as crashdump kernel.
  */
 
+static struct context_entry *device_to_existing_context_entry(
+   struct intel_iommu *iommu,
+   u8 bus, u8 devfn);
+
 
 /*
  * This domain is a statically identity mapping domain.
@@ -4810,3 +4814,22 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+static struct context_entry *device_to_existing_context_entry(
+   struct intel_iommu *iommu,
+   u8 bus, u8 devfn)
+{
+   struct root_entry *root;
+   struct context_entry *context;
+   struct context_entry *ret = NULL;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   ret = &context[devfn];
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return ret;
+}
+
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v11 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-05-11 Thread Li, Zhen-Hua
ong" as type of physical address.
2. Use new function unmap_device_dma to unmap the old dma.
3. Some small incorrect bits order for aw shift.

Changelog[v5]:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. New functions to copy data from old kernel, and save to old kernel mem.
5. New functions to save updated root entry table and irte table.
6. Use intel_unmap to unmap the old dma;
7. Allocate new pages while driver is being loaded.

Changelog[v4]:
1. Cut off the patches that move some defines and functions to new files.
2. Reduce the numbers of patches to five, make it more easier to read.
3. Changed the name of functions, make them consistent with current context
   get/set functions.
4. Add change to function __iommu_attach_domain.

Changelog[v3]:
1. Commented-out "#define DEBUG 1" to eliminate debug messages.
2. Updated the comments about changes in each version.
3. Fixed: one-line added to Copy-Translations patch to initialize the iovad
  struct as recommended by Baoquan He [b...@redhat.com]
  init_iova_domain(&domain->iovad, DMA_32BIT_PFN);

Changelog[v2]:
The following series implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the
panicked kernel is not stopped before the kdump kernel is booted and the
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat
them as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or 
(2) generate PCI SERR errors or 
(3) transfer data to or from incorrect areas of memory. Often this 
causes the dump to fail.

Changelog[v1]:
The original version.

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. Use "unsigned long" as physical address.
5. Use intel_unmap to unmap the old dma;

Baoquan He  helps testing this patchset.
Takao Indoh  gives valuable suggestions.

Li, Zhen-Hua (10):
  iommu/vt-d: New function to attach domain with id
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Function to get existing context entry
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu module
  iommu/vt-d: assign new page table for dma_map
  iommu/vt-d: Copy functions for irte
  iommu/vt-d: Use old irte in kdump kernel

 drivers/iommu/intel-iommu.c | 536 ++--
 drivers/iommu/intel_irq_remapping.c |  96 ++-
 include/linux/intel-iommu.h |  16 ++
 3 files changed, 623 insertions(+), 25 deletions(-)

-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v9 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-04-03 Thread Li, Zhen-Hua
The hardware will do some verification, but not completely.  If people think 
the OS should also do this, then it should be another patchset, I think.

Thanks
Zhenhua 

> 在 2015年4月3日,17:21,Dave Young  写道:
> 
>> On 04/03/15 at 05:01pm, Li, ZhenHua wrote:
>> Hi Dave,
>> 
>> There may be some possibilities that the old iommu data is corrupted by
>> some other modules. Currently we do not have a better solution for the
>> dmar faults.
>> 
>> But I think when this happens, we need to fix the module that corrupted
>> the old iommu data. I once met a similar problem in normal kernel, the
>> queue used by the qi_* functions was written again by another module.
>> The fix was in that module, not in iommu module.
> 
> It is too late, there will be no chance to save vmcore then.
> 
> Also if it is possible to continue corrupt other area of oldmem because
> of using old iommu tables then it will cause more problems.
> 
> So I think the tables at least need some verifycation before being used.
> 
>> 
>> 
>> Thanks
>> Zhenhua
>> 
>> On 04/03/2015 04:40 PM, Dave Young wrote:
 To fix this problem, we modifies the behaviors of the intel vt-d in the
 crashdump kernel:
 
 For DMA Remapping:
 1. To accept the vt-d hardware in an active state,
 2. Do not disable and re-enable the translation, keep it enabled.
 3. Use the old root entry table, do not rewrite the RTA register.
 4. Malloc and use new context entry table, copy data from the old ones that
   used by the old kernel.
>>> 
>>> Have not read all the patches, but I have a question, not sure this has been
>>> answered before. Old memory is not reliable, what if the old memory get 
>>> corrupted
>>> before panic? Is it safe to continue using it in 2nd kernel, I worry that 
>>> it will
>>> cause problems.
>>> 
>>> Hope I'm wrong though.
>>> 
>>> Thanks
>>> Dave
>> 
N�Р骒r��yb�X�肚�v�^�)藓{.n�+�伐�{��赙zXФ�≤�}��财�z�&j:+v�����赙zZ+��+zf"�h���~i���z��wア�?�ㄨ��&�)撷f��^j谦y�m��@A�a囤�
0鹅h���i

[PATCH v9 01/10] iommu/vt-d: New function to attach domain with id

2015-03-18 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds a new function iommu_attach_domain_with_id, it is like
the function iommu_attach_domain(), only adding a parameter "did".

Bill Sumner:
(In older versions) Add new 'did' parameter to iommu_attach_domain();
The caller of this function.

Li, Zhenhua:
New function iommu_attach_domain_with_id(), instead of updating funtion
iommu_attach_domain();

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index ae4c1a8..76674a1 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1558,6 +1558,16 @@ static int iommu_attach_domain(struct dmar_domain 
*domain,
return num;
 }
 
+static int iommu_attach_domain_with_id(struct dmar_domain *domain,
+  struct intel_iommu *iommu,
+  int domain_number)
+{
+   if (domain_number >= 0)
+   return domain_number;
+
+   return iommu_attach_domain(domain, iommu);
+}
+
 static int iommu_attach_vm_domain(struct dmar_domain *domain,
  struct intel_iommu *iommu)
 {
@@ -2225,6 +2235,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2258,7 +2269,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain_with_id(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 02/10] iommu/vt-d: Items required for kdump

2015-03-18 Thread Li, Zhen-Hua
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.
Remove the structure dve which is not used in new version.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 56 +
 1 file changed, 56 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 76674a1..577d5de 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -211,6 +212,12 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->val & VTD_PAGE_MASK) : 0;
+}
+
 /*
  * low 64 bits:
  * 0: present
@@ -231,6 +238,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -316,6 +349,29 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating.
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Allocate pages for new context entry, copy data from old context entries
+ *in the old kernel to the new ones.
+ *
+ */
+
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 04/10] iommu/vt-d: functions to copy data from old mem

2015-03-18 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Check if pfn is ram:
if (page_is_ram(pfn))

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 102 
 include/linux/intel-iommu.h |   9 
 2 files changed, 111 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f7dbe70..7f3484a 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -374,6 +374,17 @@ static struct context_entry 
*device_to_existing_context_entry(
u8 bus, u8 devfn);
 
 
+/*
+ * A structure used to store the address allocated by ioremap();
+ * The we need to call iounmap() to free them out of spin_lock_irqsave/unlock;
+ */
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4822,4 +4833,95 @@ static struct context_entry 
*device_to_existing_context_entry(
return ret;
 }
 
+/*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..8ffa523 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -368,4 +369,12 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *intel_iom

[PATCH v9 03/10] iommu/vt-d: Function to get old context entry

2015-03-18 Thread Li, Zhen-Hua
Interface for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 577d5de..f7dbe70 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -369,6 +369,10 @@ static inline int first_pte_in_page(struct dma_pte *pte)
  *
  */
 
+static struct context_entry *device_to_existing_context_entry(
+   struct intel_iommu *iommu,
+   u8 bus, u8 devfn);
+
 
 #endif /* CONFIG_CRASH_DUMP */
 
@@ -4796,3 +4800,26 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static struct context_entry *device_to_existing_context_entry(
+   struct intel_iommu *iommu,
+   u8 bus, u8 devfn)
+{
+   struct root_entry *root;
+   struct context_entry *context;
+   struct context_entry *ret;
+   unsigned long flags;
+
+   ret = NULL;
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   ret = &context[devfn];
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return ret;
+}
+
+#endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 05/10] iommu/vt-d: Add functions to load and save old re

2015-03-18 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Add __iommu_flush_cache.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 52 +
 include/linux/intel-iommu.h |  5 +
 2 files changed, 57 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 7f3484a..1cb9780 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -373,6 +373,9 @@ static struct context_entry 
*device_to_existing_context_entry(
struct intel_iommu *iommu,
u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
 
 /*
  * A structure used to store the address allocated by ioremap();
@@ -4924,4 +4927,53 @@ int __iommu_free_mapped_mem(void)
return 0;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8ffa523..8e29b97 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -329,6 +329,11 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *root_entry_old_virt; /* mapped from old root entry */
+   unsigned long root_entry_old_phys; /* root entry in old kernel */
+#endif
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 10/10] iommu/vt-d: Use old irte in kdump kernel

2015-03-18 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in kdump kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 43 +++--
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 20c060b..4e5a02d 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -199,6 +199,11 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, index);
+#endif
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -260,6 +265,11 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, -1);
+#endif
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -662,11 +672,20 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
-   /*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
-*/
-   iommu_disable_irq_remapping(iommu);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /* Do notdisable irq and then re-enable again. */
+   } else {
+#endif
+   /*
+* Disable intr remapping and queued invalidation,
+* if already enabled prior to OS handover.
+*/
+   iommu_disable_irq_remapping(iommu);
+
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
 
dmar_disable_qi(iommu);
}
@@ -702,7 +721,19 @@ static int __init intel_enable_irq_remapping(void)
 * Setup Interrupt-remapping for all the DRHD's now.
 */
for_each_iommu(iommu, drhd) {
-   iommu_set_irq_remapping(iommu, eim);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+#endif
+   iommu_set_irq_remapping(iommu, eim);
setup = 1;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 09/10] iommu/vt-d: Copy functions for irte

2015-03-18 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 62 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 66 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 14de1ab..20c060b 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -17,6 +18,11 @@
 
 #include "irq_remapping.h"
 
+#ifdef CONFIG_CRASH_DUMP
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+#endif /* CONFIG_CRASH_DUMP */
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1302,3 +1308,59 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   __iommu_flush_cache(iommu, iommu->ir_table->base,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+
+   return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8e29b97..76c6ea5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -290,6 +290,10 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
+#endif
 };
 #endif
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 08/10] iommu/vt-d: assign new page table for dma_map

2015-03-18 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a device, we
assign a new and empty page-table, thus removing all mappings from the
old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 54 ++---
 1 file changed, 46 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 312f06b..6b691d4 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "irq_remapping.h"
 
@@ -3121,14 +3122,30 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
return NULL;
}
 
-   /* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   /* if in kdump kernel, we need to unmap the mapped dma pages,
+* detach this device first.
+*/
+   if (likely(domain_context_mapped(dev))) {
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unmap_device_dma(domain, dev);
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+#endif
+   return domain;
+   }
+
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
}
 
return domain;
@@ -5177,4 +5194,25 @@ static int intel_iommu_load_translation_tables(struct 
dmar_drhd_unit *drhd)
return ret;
 }
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev)
+{
+   struct intel_iommu *iommu;
+   struct context_entry *ce;
+   struct iova *iova;
+   u8 bus, devfn;
+   phys_addr_t phys_addr;
+   dma_addr_t dev_addr;
+
+   iommu = device_to_iommu(dev, &bus, &devfn);
+   ce = device_to_context_entry(iommu, bus, devfn);
+   phys_addr = context_address_root(ce) << VTD_PAGE_SHIFT;
+   dev_addr = phys_to_dma(dev, phys_addr);
+
+   iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+   if (iova)
+   intel_unmap(dev, dev_addr);
+
+   domain_remove_one_dev_info(domain, dev);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v9 06/10] iommu/vt-d: datatypes and functions used for kdump

2015-03-18 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
Use old root entry table, and load the old data to root_entry as cache.
Malloc new context table and copy old context table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Update the caller of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that loads root entry table.
Use new function to copy old context entry tables and page tables.
Use "unsigned long" for physical address.
Remove the functions to copy page table in Bill's version.
Remove usage of dve and ppap in Bill's version.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 113 
 1 file changed, 113 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1cb9780..44f3369 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,18 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_load_translation_tables()
+ * 
+ */
+
+static int copy_root_entry_table(struct intel_iommu *iommu);
+
+static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd);
+
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4976,4 +4988,105 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
__iommu_flush_cache(iommu, to + start, size);
 }
 
+/*
+ * Load root entry tables from old kernel.
+ */
+static int copy_root_entry_table(struct intel_iommu *iommu)
+{
+   u32 bus;/* Index: root-entry-table */
+   struct root_entry  *re; /* Virt(iterator: new table) */
+   unsigned long context_old_phys; /* Phys(context table entry) */
+   struct context_entry *context_new_virt; /* Virt(new context_entry) */
+
+   /*
+* A new root entry table has been allocated ,
+* we need copy re from old kernel to the new allocated one.
+*/
+
+   if (!iommu->root_entry_old_phys)
+   return -ENOMEM;
+
+   for (bus = 0, re = iommu->root_entry; bus < 256; bus += 1, re += 1) {
+   if (!root_present(re))
+   continue;
+
+   context_old_phys = get_context_phys_from_root(re);
+
+   if (!context_old_phys)
+   continue;
+
+   context_new_virt =
+   (struct context_entry *)alloc_pgtable_page(iommu->node);
+
+   if (!context_new_virt)
+   return -ENOMEM;
+
+   __iommu_load_from_oldmem(context_new_virt,
+   context_old_phys,
+   VTD_PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, context_new_virt, VTD_PAGE_SIZE);
+
+   set_root_value(re, virt_to_phys(context_new_virt));
+   }
+
+   return 0;
+}
+
+/*
+ * Interface to the "load translation tables" set of functions
+ * from mainline code.
+ */
+static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd)
+{
+   struct intel_iommu *iommu;  /* Virt(iommu hardware registers) */
+   unsigned long long q;   /* quadword scratch */
+   int ret = 0;/* Integer return code */
+   unsigned long flags;
+
+   iommu = drhd->iommu;
+   q = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
+   if (!q)
+   return -1;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+
+   /* Load the root-entry table from the old kernel
+* foreach context_entry_table in root_entry
+*   Copy each entry table from old kernel
+*/
+   if (!iommu->root_entry) {
+   iommu->root_entry =
+   (struct root_entry *)alloc_pgtable_page(iommu->node);
+   if (!iommu->root_entry) {
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return -ENOMEM;
+   }
+   }
+
+   iommu->root_entry_old_phys = q & VTD_PAGE_MASK;
+   if (!iommu->root_entry_old_phys) {
+   pr_err("Could not read old root entry address.");
+   return -1;
+   }
+
+   iommu->root_entry_old_virt = ioremap_cache(iommu->roo

[PATCH v9 07/10] iommu/vt-d: enable kdump support in iommu module

2015-03-18 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
device_to_context_entry
free_context_table
get_domain_for_dev
init_dmars
intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
The name of new calling functions.
Do not disable and re-enable TE in kdump kernel.
Use the did and gaw from old context entry;

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 118 ++--
 1 file changed, 103 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 44f3369..312f06b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -841,6 +841,11 @@ static struct context_entry * 
device_to_context_entry(struct intel_iommu *iommu,
set_root_value(root, phy_addr);
set_root_present(root);
__iommu_flush_cache(iommu, root, sizeof(*root));
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_root_entry(iommu, bus);
+#endif
}
spin_unlock_irqrestore(&iommu->lock, flags);
return &context[devfn];
@@ -892,7 +897,8 @@ static void free_context_table(struct intel_iommu *iommu)
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
root = &iommu->root_entry[i];
@@ -900,10 +906,23 @@ static void free_context_table(struct intel_iommu *iommu)
if (context)
free_pgtable_page(context);
}
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry_old_virt;
+   iommu->root_entry_old_virt = NULL;
+   }
+#endif
free_pgtable_page(iommu->root_entry);
iommu->root_entry = NULL;
-out:
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   iounmap(root);
+#endif
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2322,6 +2341,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct context_entry *ce = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2355,6 +2377,22 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   ce = device_to_existing_context_entry(iommu, bus, devfn);
+
+   if (ce) {
+   did = context_domain_id(ce);
+   gaw = agaw_to_width(context_address_width(ce));
+   }
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain_with_id(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2889,14 +2927,33 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   pr_info("IOMMU Copying translate tables from panicked 
kernel\n");
+   ret = intel_iommu_load_translation_tables(drhd);
+   if (ret) {
+   pr_err("IOMMU: Copy translate tables failed\n");
+
+   /* Best to stop trying */
+   goto free_iommu;
+   }
+   pr_info("IOMMU: root_cache:0x%12.12llx 
phys:0x%12.12llx\n",
+   (u64)iommu->root_entry,
+   (u64)iommu->root_entry_old_phys);
+   } else {
+#endif /* CONFIG_CRASH_DUMP */
+   /*
+* TBD:
+* we could share the same root & context tables
+ 

[PATCH v9 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-03-18 Thread Li, Zhen-Hua
tions to save updated root entry table and irte table.
6. Use intel_unmap to unmap the old dma;
7. Allocate new pages while driver is being loaded.

Changelog[v4]:
1. Cut off the patches that move some defines and functions to new files.
2. Reduce the numbers of patches to five, make it more easier to read.
3. Changed the name of functions, make them consistent with current context
   get/set functions.
4. Add change to function __iommu_attach_domain.

Changelog[v3]:
1. Commented-out "#define DEBUG 1" to eliminate debug messages.
2. Updated the comments about changes in each version.
3. Fixed: one-line added to Copy-Translations patch to initialize the iovad
  struct as recommended by Baoquan He [b...@redhat.com]
  init_iova_domain(&domain->iovad, DMA_32BIT_PFN);

Changelog[v2]:
The following series implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the
panicked kernel is not stopped before the kdump kernel is booted and the
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat
them as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or 
(2) generate PCI SERR errors or 
(3) transfer data to or from incorrect areas of memory. Often this 
causes the dump to fail.

Changelog[v1]:
The original version.

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. Use "unsigned long" as physical address.
5. Use intel_unmap to unmap the old dma;

Baoquan He  helps testing this patchset.
Takao Indoh  gives valuable suggestions.

Li, Zhen-Hua (10):
  iommu/vt-d: New function to attach domain with id
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Function to get old context entry
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu module
  iommu/vt-d: assign new page table for dma_map
  iommu/vt-d: Copy functions for irte
  iommu/vt-d: Use old irte in kdump kernel

 drivers/iommu/intel-iommu.c | 535 ++--
 drivers/iommu/intel_irq_remapping.c | 105 ++-
 include/linux/intel-iommu.h |  18 ++
 3 files changed, 628 insertions(+), 30 deletions(-)

-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 09/10] iommu/vt-d: Copy functions for irte

2015-01-11 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 62 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 66 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index a55b207..d37fd62 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -17,6 +18,11 @@
 
 #include "irq_remapping.h"
 
+#ifdef CONFIG_CRASH_DUMP
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+#endif /* CONFIG_CRASH_DUMP */
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1296,3 +1302,59 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   __iommu_flush_cache(iommu, iommu->ir_table->base,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+
+   return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8e29b97..76c6ea5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -290,6 +290,10 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
+#endif
 };
 #endif
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 10/10] iommu/vt-d: Use old irte in kdump kernel

2015-01-11 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in kdump kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 42 -
 1 file changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index d37fd62..58356cb 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -198,6 +198,11 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, index);
+#endif
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -259,6 +264,11 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, -1);
+#endif
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -640,11 +650,20 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
-   /*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
-*/
-   iommu_disable_irq_remapping(iommu);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /* Do notdisable irq and then re-enable again. */
+   } else {
+#endif
+   /*
+* Disable intr remapping and queued invalidation,
+* if already enabled prior to OS handover.
+*/
+   iommu_disable_irq_remapping(iommu);
+
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
 
dmar_disable_qi(iommu);
}
@@ -687,7 +706,20 @@ static int __init intel_enable_irq_remapping(void)
if (intel_setup_irq_remapping(iommu))
goto error;
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+#endif
iommu_set_irq_remapping(iommu, eim);
+
setup = 1;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 08/10] iommu/vt-d: assign new page table for dma_map

2015-01-11 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a
device, we assign a new and empty page-table, thus removing all
mappings from the old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 56 ++---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 324c504..ccbad3f 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "irq_remapping.h"
 
@@ -455,6 +456,8 @@ static int copy_root_entry_table(struct intel_iommu *iommu, 
void *ppap);
 static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
int g_num_of_iommus);
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -3196,14 +3199,30 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
return NULL;
}
 
-   /* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   /* if in kdump kernel, we need to unmap the mapped dma pages,
+* detach this device first.
+*/
+   if (likely(domain_context_mapped(dev))) {
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unmap_device_dma(domain, dev);
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+#endif
+   return domain;
+   }
+
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
}
 
return domain;
@@ -5691,4 +5710,25 @@ static int intel_iommu_load_translation_tables(struct 
dmar_drhd_unit *drhd,
return 0;
 }
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev)
+{
+   struct intel_iommu *iommu;
+   struct context_entry *ce;
+   struct iova *iova;
+   u8 bus, devfn;
+   phys_addr_t phys_addr;
+   dma_addr_t dev_addr;
+
+   iommu = device_to_iommu(dev, &bus, &devfn);
+   ce = device_to_context_entry(iommu, bus, devfn);
+   phys_addr = context_address_root(ce) << VTD_PAGE_SHIFT;
+   dev_addr = phys_to_dma(dev, phys_addr);
+
+   iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+   if (iova)
+   intel_unmap(dev, dev_addr);
+
+   domain_remove_one_dev_info(domain, dev);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 05/10] iommu/vt-d: Add functions to load and save old re

2015-01-11 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Add __iommu_flush_cache.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 53 +
 include/linux/intel-iommu.h |  5 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2335831..5f11f43 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,10 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
+
 struct iommu_remapped_entry {
struct list_head list;
void __iomem *mem;
@@ -4986,4 +4990,53 @@ static int device_to_domain_id(struct intel_iommu 
*iommu, u8 bus, u8 devfn)
return did;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8ffa523..8e29b97 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -329,6 +329,11 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *root_entry_old_virt; /* mapped from old root entry */
+   unsigned long root_entry_old_phys; /* root entry in old kernel */
+#endif
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 06/10] iommu/vt-d: datatypes and functions used for kdump

2015-01-11 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
malloc new context table and copy old context table to the new one.
malloc new page table and copy old page table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Minor change:
Update the usage of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that copies root entry table.
Use new function to copy old context entry tables and page tables.
Use "unsigned long" for physical address.
Change incorrect aw_shift[4] and a few comments in copy_context_entry().

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 547 
 1 file changed, 547 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 5f11f43..277b294 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -399,6 +399,62 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_load_translation_tables()
+ * 
+ */
+
+/*
+ * Lists of domain_values_entry to hold domain values found during the copy.
+ * One list for each iommu in g_number_of_iommus.
+ */
+static struct list_head *domain_values_list;
+
+
+#define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+   u32 first;  /* flag: first-time  */
+   u32 last;   /* flag: last-time */
+   u32 bus;/* last bus number we saw */
+   u32 devfn;  /* last devfn we saw */
+   u32 shift;  /* last shift we saw */
+   u64 pte;/* Page Table Entry */
+   u64 next_addr;  /* next-expected page_addr */
+
+   u64 page_addr;  /* page_addr accumulating size */
+   u64 page_size;  /* page_size accumulated */
+
+   struct domain_values_entry *dve;/* to accumulate iova ranges */
+};
+
+enum returns_from_copy_context_entry {
+RET_CCE_NOT_PRESENT = 1,
+RET_CCE_NEW_PAGE_TABLES,
+RET_CCE_PASS_THROUGH_1,
+RET_CCE_PASS_THROUGH_2,
+RET_CCE_RESERVED_VALUE,
+RET_CCE_PREVIOUS_DID
+};
+
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+ void *ppap, struct context_entry *ce);
+
+static int copy_context_entry_table(struct intel_iommu *iommu,
+   u32 bus, void *ppap,
+   unsigned long *context_new_p,
+   unsigned long context_old_phys);
+
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap);
+
+static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
+   int g_num_of_iommus);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -5039,4 +5095,495 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
__iommu_flush_cache(iommu, to + start, size);
 }
 
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. a change in the bus or device owning the presented page
+ * 2. a change in the page-size of the presented page (parameter shift)
+ * 3. a change in the page-table entry of the presented page
+ * 4. a presented IOVA that does not match the expected next-page address
+ * 5. the 'last' flag is set, indicating that all IOVAs have been seen.
+ */
+static int copy_page_addr(u64 page_addr, u32 shift, u32 bus, u32 devfn,
+   u64 pte, struct domain_values_entry *dve,
+   void *parms)
+{
+   struct copy_page_addr_parms *ppap = parms;
+
+   u64 page_size = ((u64)1 << shift);  /* page_size */
+   u64 pfn_lo

[PATCH v8 07/10] iommu/vt-d: enable kdump support in iommu module

2015-01-11 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
device_to_domain_id
get_domain_for_dev
init_dmars
intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
Minor change,
The name of new calling functions.
Do not disable and re-enable TE in kdump kernel.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 135 +++-
 1 file changed, 120 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 277b294..324c504 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -907,6 +907,11 @@ static struct context_entry * 
device_to_context_entry(struct intel_iommu *iommu,
set_root_value(root, phy_addr);
set_root_present(root);
__iommu_flush_cache(iommu, root, sizeof(*root));
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_root_entry(iommu, bus);
+#endif
}
spin_unlock_irqrestore(&iommu->lock, flags);
return &context[devfn];
@@ -958,7 +963,8 @@ static void free_context_table(struct intel_iommu *iommu)
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
root = &iommu->root_entry[i];
@@ -966,10 +972,23 @@ static void free_context_table(struct intel_iommu *iommu)
if (context)
free_pgtable_page(context);
}
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry_old_virt;
+   iommu->root_entry_old_virt = NULL;
+   }
+#endif
free_pgtable_page(iommu->root_entry);
iommu->root_entry = NULL;
-out:
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   iounmap(root);
+#endif
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2381,6 +2400,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct domain_values_entry *dve = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2414,6 +2436,24 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   did = device_to_domain_id(iommu, bus, devfn);
+   if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap)))
+   dve = intel_iommu_did_to_domain_values_entry(did,
+   iommu);
+   if (dve)
+   gaw = dve->gaw;
+   else
+   did = -1;
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2425,6 +2465,18 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
return NULL;
}
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel() && dve) {
+
+   if (domain->pgd)
+   free_pgtable_page(domain->pgd);
+
+   domain->pgd = dve->pgd;
+
+   copy_reserved_iova(&dve->iovad, &domain->iovad);
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
/* register PCI DMA alias device */
if (dev_is_pci(dev)) {
tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
@@ -2948,14 +3000,35 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   pr_info("IOMMU Copying translate tables from panicked 
kernel\n");
+   

[PATCH v8 02/10] iommu/vt-d: Items required for kdump

2015-01-11 Thread Li, Zhen-Hua
Add structure type domain_values_entry used for kdump;
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 70 +
 1 file changed, 70 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 8d5c400..a71de3f 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -208,6 +209,12 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->val & VTD_PAGE_MASK) : 0;
+}
+
 /*
  * low 64 bits:
  * 0: present
@@ -228,6 +235,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -313,6 +346,43 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA).
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Leaves the current translations in-place so that legacy DMA will
+ *continue to use its current buffers.
+ * 5. Allocates to the device drivers in the crashdump kernel
+ *portions of the iova address ranges that are different
+ *from the iova address ranges that were being used by the old kernel
+ *at the time of the panic.
+ *
+ */
+
+struct domain_values_entry {
+   struct list_head link;  /* link entries into a list */
+   struct iova_domain iovad;   /* iova's that belong to this domain */
+   struct dma_pte  *pgd;   /* virtual address */
+   intdid; /* domain id */
+   intgaw; /* max guest address width */
+   intiommu_superpage; /* Level of superpages supported:
+  0 == 4KiB (no superpages), 1 == 2MiB,
+  2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
+};
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 03/10] iommu/vt-d: Add domain-id functions

2015-01-11 Thread Li, Zhen-Hua
Interfaces for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a71de3f..c594b2c 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -381,6 +381,13 @@ struct domain_values_entry {
   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
 };
 
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4828,3 +4835,58 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ *
+ */
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link)
+   if (dve->did == did)
+   return dve;
+   return NULL;
+}
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   pr_info("IOMMU:%d Domain ids from panicked kernel:\n", iommu->seq_id);
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link) {
+   set_bit(dve->did, iommu->domain_ids);
+   pr_info("DID did:%d(0x%4.4x)\n", dve->did, dve->did);
+   }
+
+   pr_info("\n");
+   return 0;
+}
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+   int did = -1;   /* domain-id returned */
+   struct root_entry *root;
+   struct context_entry *context;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   did = context_domain_id(context+devfn);
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return did;
+}
+
+#endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 04/10] iommu/vt-d: functions to copy data from old mem

2015-01-11 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Check if pfn is ram:
if (page_is_ram(pfn))

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 97 +
 include/linux/intel-iommu.h |  9 +
 2 files changed, 106 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c594b2c..2335831 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,13 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4839,6 +4846,96 @@ static void __init check_tylersburg_isoch(void)
 #ifdef CONFIG_CRASH_DUMP
 
 /*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+/*
  * Interfaces for when a new domain in the crashdump kernel needs some
  * values from the panicked kernel's context entries
  *
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..8ffa523 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -368,4 +369,12 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *intel_iommu_groups[];
 

[PATCH v8 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-01-11 Thread Li, Zhen-Hua
f functions, make them consistent with current context
   get/set functions.
4. Add change to function __iommu_attach_domain.

Changelog[v3]:
1. Commented-out "#define DEBUG 1" to eliminate debug messages.
2. Updated the comments about changes in each version.
3. Fixed: one-line added to Copy-Translations patch to initialize the iovad
  struct as recommended by Baoquan He [b...@redhat.com]
  init_iova_domain(&domain->iovad, DMA_32BIT_PFN);

Changelog[v2]:
The following series implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the
panicked kernel is not stopped before the kdump kernel is booted and the
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat
them as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or 
(2) generate PCI SERR errors or 
(3) transfer data to or from incorrect areas of memory. Often this 
causes the dump to fail.

Changelog[v1]:
The original version.

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. Use "unsigned long" as physical address.
5. Use intel_unmap to unmap the old dma;

Baoquan He  helps testing this patchset.
Takao Indoh  gives valuable suggestions.

  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu module
  iommu/vt-d: assign new page table for dma_map
  iommu/vt-d: Copy functions for irte
  iommu/vt-d: Use old irte in kdump kernel

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
Tested-by: Baoquan He 
---
 drivers/iommu/intel-iommu.c | 1054 +--
 drivers/iommu/intel_irq_remapping.c |  104 +++-
 include/linux/intel-iommu.h |   18 +
 3 files changed, 1134 insertions(+), 42 deletions(-)

-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v8 01/10] iommu/vt-d: Update iommu_attach_domain() and its callers

2015-01-11 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds the 'did' parameter to iommu_attach_domain()
and modifies all of its callers to specify the default value of -1
which says "no did specified, allocate a new one".

This is no functional change from current behaviour -- just enables
a functional change to be made in a later patch.

Bill Sumner:
Original version.

Li, Zhenhua:
Minor change, add change to function __iommu_attach_domain.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 40dfbc0..8d5c400 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1534,31 +1534,36 @@ static struct dmar_domain *alloc_domain(int flags)
 }
 
 static int __iommu_attach_domain(struct dmar_domain *domain,
-struct intel_iommu *iommu)
+struct intel_iommu *iommu,
+int domain_number)
 {
int num;
unsigned long ndomains;
 
ndomains = cap_ndoms(iommu->cap);
-   num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num < ndomains) {
-   set_bit(num, iommu->domain_ids);
-   iommu->domains[num] = domain;
-   } else {
-   num = -ENOSPC;
-   }
+   if (domain_number < 0) {
+   num = find_first_zero_bit(iommu->domain_ids, ndomains);
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
+   }
+   } else
+   num = domain_number;
 
return num;
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+  struct intel_iommu *iommu,
+  int domain_number)
 {
int num;
unsigned long flags;
 
spin_lock_irqsave(&iommu->lock, flags);
-   num = __iommu_attach_domain(domain, iommu);
+   num = __iommu_attach_domain(domain, iommu, domain_number);
spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
@@ -1577,7 +1582,7 @@ static int iommu_attach_vm_domain(struct dmar_domain 
*domain,
if (iommu->domains[num] == domain)
return num;
 
-   return __iommu_attach_domain(domain, iommu);
+   return __iommu_attach_domain(domain, iommu, -1);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -2231,6 +2236,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2264,7 +2270,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
@@ -2442,7 +2448,7 @@ static int __init si_domain_init(int hw)
return -EFAULT;
 
for_each_active_iommu(iommu, drhd) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
@@ -3866,7 +3872,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
iommu_enable_translation(iommu);
 
if (si_domain) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0 || si_domain->id != ret)
goto disable_iommu;
domain_attach_iommu(si_domain, iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v7 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-01-07 Thread Li, Zhen-Hua
In your log, it seems something incorrect while copying pages.

Your last DMAR fault is:
DMAR:[fault reason 01] Present bit in root entry is clear

But this time, it is:
DMAR:[fault reason 05] PTE Write access is not set


So I think this line I added to this version , it works.
function intel_iommu_load_translation_tables, line:
__iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);


I checked the code, found I missed one flush in function copy_page_table.
How do you think we add one flush after this lines:

ret = copy_page_table(&dma_pte_next, 
(p->val & VTD_PAGE_MASK),
shift-9, page_addr | (u << shift),
iommu, bus, devfn, dve, ppap);

+   __iommu_flush_cache(iommu, phys_to_virt(dma_pte_next),
+   VTD_PAGE_SIZE);

If this does not work, I have no ideas currently, need to dig the code more.

Regards
Zhenhua

-Original Message-
From: Takao Indoh [mailto:indou.ta...@jp.fujitsu.com] 
Sent: Thursday, January 08, 2015 9:00 AM
To: Li, Zhen-Hua; b...@redhat.com
Cc: dw...@infradead.org; j...@8bytes.org; vgo...@redhat.com; dyo...@redhat.com; 
io...@lists.linux-foundation.org; linux-kernel@vger.kernel.org; 
linux-...@vger.kernel.org; ke...@lists.infradead.org; 
alex.william...@redhat.com; ddut...@redhat.com; ishii.hiron...@jp.fujitsu.com; 
bhelg...@google.com; Hatch, Douglas B (HPS Linux PM); Hoemann, Jerry; Vaden, 
Tom (HP Server OS Architecture); Zhang, Li (Zoe@HPservers-Core-OE-PSC); 
Mitchell, Lisa (MCLinux in Fort Collins); billsumnerli...@gmail.com; Wright, 
Randy (HP Servers Linux)
Subject: Re: [PATCH v7 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

On 2015/01/07 17:52, Li, ZhenHua wrote:
> Well, that's quite good news.
> Looking forward Takao's testing on his system.

Unfortunately DMAR fault still occurs with this patch...
I attach console log.

Thanks,
Takao Indoh

> 
> Regards
> Zhenhua
> On 01/07/2015 04:28 PM, Baoquan He wrote:
>> On 01/07/15 at 01:25pm, Li, ZhenHua wrote:
>>> It is same as the last one I send to you yesterday.
>>>
>>> The continuous memory that needed for data in this patchset:
>>> RE: PAGE_SIZE, 4096 Bytes;
>>> IRTE: 65536 * 16 ; 1M Bytes;
>>>
>>> It should use same memory as the old versions of this patchset. The 
>>> changes for the last version do not need more memory.
>>
>> Hi Zhenhua,
>>
>> It was my mistake because I didn't strip the debug info of modules, 
>> then initramfs is bloated very big. Just now I tested the latest 
>> version, it works well and dump is successful. No dmar fault and 
>> intr-remap fault seen any more, good job!
>>
>> Thanks
>> Baoquan
>>
>>
>>>
>>> Regards
>>> Zhenhua
>>>
>>> On 01/07/2015 01:02 PM, Baoquan He wrote:
>>>> On 01/07/15 at 12:11pm, Li, ZhenHua wrote:
>>>>> Many thanks to Takao Indoh and Baoquan He, for your testing on 
>>>>> more different systems.
>>>>>
>>>>> The calling of flush functions are added to this version.
>>>>>
>>>>> The usage of __iommu_flush_cache function :
>>>>> 1. Fixes a dump on Takao's system.
>>>>> 2. Reduces the count of faults on Baoquan's system.
>>>>
>>>> I am testing the version you sent to me yesterday afternoon. Is 
>>>> that different with this patchset? I found your patchset man 
>>>> reserve a big contiguous memory region under 896M, this will cause 
>>>> the crashkernel reservation failed when I set crashkernel=320M. The 
>>>> reason I increase the crashkerenl reservation to 320M is 256M is 
>>>> not enough and cause OOM when that patchset is tested.
>>>>
>>>> I am checking what happened.
>>>>
>>>>
>>>> Thanks
>>>> Baoquan
>>>>
>>>>>
>>>>> Regards
>>>>> Zhenhua
>>>>>
>>>>> On 01/07/2015 12:04 PM, Li, Zhen-Hua wrote:
>>>>>> This patchset is an update of Bill Sumner's patchset, implements a fix 
>>>>>> for:
>>>>>> If a kernel boots with intel_iommu=on on a system that supports 
>>>>>> intel vt-d, when a panic happens, the kdump kernel will boot with these 
>>>>>> faults:
>>>>>>
>>>>>>  dmar: DRHD: handling fault status reg 102
>>>>>>  dmar: DMAR:[DMA Read] Request device [01:00.0] fault addr fff8
>>>>>

[PATCH v7 02/10] iommu/vt-d: Items required for kdump

2015-01-06 Thread Li, Zhen-Hua
Add structure type domain_values_entry used for kdump;
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 70 +
 1 file changed, 70 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2dc6250..5ce2850 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -208,6 +209,12 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->val & VTD_PAGE_MASK) : 0;
+}
+
 /*
  * low 64 bits:
  * 0: present
@@ -228,6 +235,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -313,6 +346,43 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA).
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Leaves the current translations in-place so that legacy DMA will
+ *continue to use its current buffers.
+ * 5. Allocates to the device drivers in the crashdump kernel
+ *portions of the iova address ranges that are different
+ *from the iova address ranges that were being used by the old kernel
+ *at the time of the panic.
+ *
+ */
+
+struct domain_values_entry {
+   struct list_head link;  /* link entries into a list */
+   struct iova_domain iovad;   /* iova's that belong to this domain */
+   struct dma_pte  *pgd;   /* virtual address */
+   intdid; /* domain id */
+   intgaw; /* max guest address width */
+   intiommu_superpage; /* Level of superpages supported:
+  0 == 4KiB (no superpages), 1 == 2MiB,
+  2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
+};
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 10/10] iommu/vt-d: Use old irte in kdump kernel

2015-01-06 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in kdump kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 42 -
 1 file changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index d37fd62..58356cb 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -198,6 +198,11 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, index);
+#endif
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -259,6 +264,11 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, -1);
+#endif
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -640,11 +650,20 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
-   /*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
-*/
-   iommu_disable_irq_remapping(iommu);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /* Do notdisable irq and then re-enable again. */
+   } else {
+#endif
+   /*
+* Disable intr remapping and queued invalidation,
+* if already enabled prior to OS handover.
+*/
+   iommu_disable_irq_remapping(iommu);
+
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
 
dmar_disable_qi(iommu);
}
@@ -687,7 +706,20 @@ static int __init intel_enable_irq_remapping(void)
if (intel_setup_irq_remapping(iommu))
goto error;
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+#endif
iommu_set_irq_remapping(iommu, eim);
+
setup = 1;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 07/10] iommu/vt-d: enable kdump support in iommu module

2015-01-06 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
device_to_domain_id
get_domain_for_dev
init_dmars
intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
Minor change,
The name of new calling functions.
Do not disable and re-enable TE in kdump kernel.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 135 +++-
 1 file changed, 120 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index d2c19a0..8807710 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -907,6 +907,11 @@ static struct context_entry * 
device_to_context_entry(struct intel_iommu *iommu,
set_root_value(root, phy_addr);
set_root_present(root);
__iommu_flush_cache(iommu, root, sizeof(*root));
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_root_entry(iommu, bus);
+#endif
}
spin_unlock_irqrestore(&iommu->lock, flags);
return &context[devfn];
@@ -958,7 +963,8 @@ static void free_context_table(struct intel_iommu *iommu)
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
root = &iommu->root_entry[i];
@@ -966,10 +972,23 @@ static void free_context_table(struct intel_iommu *iommu)
if (context)
free_pgtable_page(context);
}
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry_old_virt;
+   iommu->root_entry_old_virt = NULL;
+   }
+#endif
free_pgtable_page(iommu->root_entry);
iommu->root_entry = NULL;
-out:
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   iounmap(root);
+#endif
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2381,6 +2400,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct domain_values_entry *dve = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2414,6 +2436,24 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   did = device_to_domain_id(iommu, bus, devfn);
+   if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap)))
+   dve = intel_iommu_did_to_domain_values_entry(did,
+   iommu);
+   if (dve)
+   gaw = dve->gaw;
+   else
+   did = -1;
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2425,6 +2465,18 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
return NULL;
}
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel() && dve) {
+
+   if (domain->pgd)
+   free_pgtable_page(domain->pgd);
+
+   domain->pgd = dve->pgd;
+
+   copy_reserved_iova(&dve->iovad, &domain->iovad);
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
/* register PCI DMA alias device */
if (dev_is_pci(dev)) {
tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
@@ -2948,14 +3000,35 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   pr_info("IOMMU Copying translate tables from panicked 
kernel\n");
+   

[PATCH v7 08/10] iommu/vt-d: assign new page table for dma_map

2015-01-06 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a
device, we assign a new and empty page-table, thus removing all
mappings from the old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 56 ++---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 8807710..57ae08b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "irq_remapping.h"
 
@@ -455,6 +456,8 @@ static int copy_root_entry_table(struct intel_iommu *iommu, 
void *ppap);
 static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
int g_num_of_iommus);
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -3196,14 +3199,30 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
return NULL;
}
 
-   /* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   /* if in kdump kernel, we need to unmap the mapped dma pages,
+* detach this device first.
+*/
+   if (likely(domain_context_mapped(dev))) {
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unmap_device_dma(domain, dev);
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+#endif
+   return domain;
+   }
+
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
}
 
return domain;
@@ -5691,4 +5710,25 @@ static int intel_iommu_load_translation_tables(struct 
dmar_drhd_unit *drhd,
return 0;
 }
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev)
+{
+   struct intel_iommu *iommu;
+   struct context_entry *ce;
+   struct iova *iova;
+   u8 bus, devfn;
+   phys_addr_t phys_addr;
+   dma_addr_t dev_addr;
+
+   iommu = device_to_iommu(dev, &bus, &devfn);
+   ce = device_to_context_entry(iommu, bus, devfn);
+   phys_addr = context_address_root(ce) << VTD_PAGE_SHIFT;
+   dev_addr = phys_to_dma(dev, phys_addr);
+
+   iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+   if (iova)
+   intel_unmap(dev, dev_addr);
+
+   domain_remove_one_dev_info(domain, dev);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 09/10] iommu/vt-d: Copy functions for irte

2015-01-06 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 62 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 66 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index a55b207..d37fd62 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -17,6 +18,11 @@
 
 #include "irq_remapping.h"
 
+#ifdef CONFIG_CRASH_DUMP
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+#endif /* CONFIG_CRASH_DUMP */
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1296,3 +1302,59 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   __iommu_flush_cache(iommu, iommu->ir_table->base,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+
+   return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8e29b97..76c6ea5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -290,6 +290,10 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
+#endif
 };
 #endif
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 04/10] iommu/vt-d: functions to copy data from old mem

2015-01-06 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Check if pfn is ram:
if (page_is_ram(pfn))

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 97 +
 include/linux/intel-iommu.h |  9 +
 2 files changed, 106 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c0bebd6..8a7ad72 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,13 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4843,6 +4850,96 @@ static void __init check_tylersburg_isoch(void)
 #ifdef CONFIG_CRASH_DUMP
 
 /*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+/*
  * Interfaces for when a new domain in the crashdump kernel needs some
  * values from the panicked kernel's context entries
  *
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..8ffa523 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -368,4 +369,12 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *intel_iommu_groups[];
 

[PATCH v7 06/10] iommu/vt-d: datatypes and functions used for kdump

2015-01-06 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
malloc new context table and copy old context table to the new one.
malloc new page table and copy old page table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Minor change:
Update the usage of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that copies root entry table.
Use new function to copy old context entry tables and page tables.
Use "unsigned long" for physical address.
Change incorrect aw_shift[4] and a few comments in copy_context_entry().

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 543 
 1 file changed, 543 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f3059b8..d2c19a0 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -399,6 +399,62 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_load_translation_tables()
+ * 
+ */
+
+/*
+ * Lists of domain_values_entry to hold domain values found during the copy.
+ * One list for each iommu in g_number_of_iommus.
+ */
+static struct list_head *domain_values_list;
+
+
+#define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+   u32 first;  /* flag: first-time  */
+   u32 last;   /* flag: last-time */
+   u32 bus;/* last bus number we saw */
+   u32 devfn;  /* last devfn we saw */
+   u32 shift;  /* last shift we saw */
+   u64 pte;/* Page Table Entry */
+   u64 next_addr;  /* next-expected page_addr */
+
+   u64 page_addr;  /* page_addr accumulating size */
+   u64 page_size;  /* page_size accumulated */
+
+   struct domain_values_entry *dve;/* to accumulate iova ranges */
+};
+
+enum returns_from_copy_context_entry {
+RET_CCE_NOT_PRESENT = 1,
+RET_CCE_NEW_PAGE_TABLES,
+RET_CCE_PASS_THROUGH_1,
+RET_CCE_PASS_THROUGH_2,
+RET_CCE_RESERVED_VALUE,
+RET_CCE_PREVIOUS_DID
+};
+
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+ void *ppap, struct context_entry *ce);
+
+static int copy_context_entry_table(struct intel_iommu *iommu,
+   u32 bus, void *ppap,
+   unsigned long *context_new_p,
+   unsigned long context_old_phys);
+
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap);
+
+static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
+   int g_num_of_iommus);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -5043,4 +5099,491 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
__iommu_flush_cache(iommu, to + start, size);
 }
 
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. a change in the bus or device owning the presented page
+ * 2. a change in the page-size of the presented page (parameter shift)
+ * 3. a change in the page-table entry of the presented page
+ * 4. a presented IOVA that does not match the expected next-page address
+ * 5. the 'last' flag is set, indicating that all IOVAs have been seen.
+ */
+static int copy_page_addr(u64 page_addr, u32 shift, u32 bus, u32 devfn,
+   u64 pte, struct domain_values_entry *dve,
+   void *parms)
+{
+   struct copy_page_addr_parms *ppap = parms;
+
+   u64 page_size = ((u64)1 << shift);  /* page_size */
+   u64 pfn_lo

[PATCH v7 05/10] iommu/vt-d: Add functions to load and save old re

2015-01-06 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Li, Zhen-hua:
The functions and logics.

Takao Indoh:
Add __iommu_flush_cache.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
---
 drivers/iommu/intel-iommu.c | 53 +
 include/linux/intel-iommu.h |  5 +
 2 files changed, 58 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 8a7ad72..f3059b8 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,10 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
+
 struct iommu_remapped_entry {
struct list_head list;
void __iomem *mem;
@@ -4990,4 +4994,53 @@ static int device_to_domain_id(struct intel_iommu 
*iommu, u8 bus, u8 devfn)
return did;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+
+   __iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+
+   __iommu_flush_cache(iommu, to + start, size);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8ffa523..8e29b97 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -329,6 +329,11 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *root_entry_old_virt; /* mapped from old root entry */
+   unsigned long root_entry_old_phys; /* root entry in old kernel */
+#endif
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 01/10] iommu/vt-d: Update iommu_attach_domain() and its callers

2015-01-06 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds the 'did' parameter to iommu_attach_domain()
and modifies all of its callers to specify the default value of -1
which says "no did specified, allocate a new one".

This is no functional change from current behaviour -- just enables
a functional change to be made in a later patch.

Bill Sumner:
Original version.

Li, Zhenhua:
Minor change, add change to function __iommu_attach_domain.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1232336..2dc6250 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1534,31 +1534,36 @@ static struct dmar_domain *alloc_domain(int flags)
 }
 
 static int __iommu_attach_domain(struct dmar_domain *domain,
-struct intel_iommu *iommu)
+struct intel_iommu *iommu,
+int domain_number)
 {
int num;
unsigned long ndomains;
 
ndomains = cap_ndoms(iommu->cap);
-   num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num < ndomains) {
-   set_bit(num, iommu->domain_ids);
-   iommu->domains[num] = domain;
-   } else {
-   num = -ENOSPC;
-   }
+   if (domain_number < 0) {
+   num = find_first_zero_bit(iommu->domain_ids, ndomains);
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
+   }
+   } else
+   num = domain_number;
 
return num;
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+  struct intel_iommu *iommu,
+  int domain_number)
 {
int num;
unsigned long flags;
 
spin_lock_irqsave(&iommu->lock, flags);
-   num = __iommu_attach_domain(domain, iommu);
+   num = __iommu_attach_domain(domain, iommu, domain_number);
spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
@@ -1577,7 +1582,7 @@ static int iommu_attach_vm_domain(struct dmar_domain 
*domain,
if (iommu->domains[num] == domain)
return num;
 
-   return __iommu_attach_domain(domain, iommu);
+   return __iommu_attach_domain(domain, iommu, -1);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -2231,6 +2236,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2264,7 +2270,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
@@ -2442,7 +2448,7 @@ static int __init si_domain_init(int hw)
return -EFAULT;
 
for_each_active_iommu(iommu, drhd) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
@@ -3866,7 +3872,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
iommu_enable_translation(iommu);
 
if (si_domain) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0 || si_domain->id != ret)
goto disable_iommu;
domain_attach_iommu(si_domain, iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2015-01-06 Thread Li, Zhen-Hua
.

Changelog[v3]:
1. Commented-out "#define DEBUG 1" to eliminate debug messages.
2. Updated the comments about changes in each version.
3. Fixed: one-line added to Copy-Translations patch to initialize the iovad
  struct as recommended by Baoquan He [b...@redhat.com]
  init_iova_domain(&domain->iovad, DMA_32BIT_PFN);

Changelog[v2]:
The following series implements a fix for:
A kdump problem about DMA that has been discussed for a long time. That is,
when a kernel panics and boots into the kdump kernel, DMA started by the
panicked kernel is not stopped before the kdump kernel is booted and the
kdump kernel disables the IOMMU while this DMA continues.  This causes the
IOMMU to stop translating the DMA addresses as IOVAs and begin to treat
them as physical memory addresses -- which causes the DMA to either:
(1) generate DMAR errors or 
(2) generate PCI SERR errors or 
(3) transfer data to or from incorrect areas of memory. Often this 
causes the dump to fail.

Changelog[v1]:
The original version.

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. Use "unsigned long" as physical address.
5. Use intel_unmap to unmap the old dma;

Baoquan He  helps testing this patchset.

  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu module
  iommu/vt-d: assign new page table for dma_map
  iommu/vt-d: Copy functions for irte
  iommu/vt-d: Use old irte in kdump kernel

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
Tested-by: Baoquan He 
---
 drivers/iommu/intel-iommu.c | 1050 +--
 drivers/iommu/intel_irq_remapping.c |  104 +++-
 include/linux/intel-iommu.h |   18 +
 3 files changed, 1130 insertions(+), 42 deletions(-)

-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v7 03/10] iommu/vt-d: Add domain-id functions

2015-01-06 Thread Li, Zhen-Hua
Interfaces for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 5ce2850..c0bebd6 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -381,6 +381,13 @@ struct domain_values_entry {
   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
 };
 
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4832,3 +4839,58 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ *
+ */
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link)
+   if (dve->did == did)
+   return dve;
+   return NULL;
+}
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   pr_info("IOMMU:%d Domain ids from panicked kernel:\n", iommu->seq_id);
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link) {
+   set_bit(dve->did, iommu->domain_ids);
+   pr_info("DID did:%d(0x%4.4x)\n", dve->did, dve->did);
+   }
+
+   pr_info("\n");
+   return 0;
+}
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+   int did = -1;   /* domain-id returned */
+   struct root_entry *root;
+   struct context_entry *context;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   did = context_domain_id(context+devfn);
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return did;
+}
+
+#endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 02/10] iommu/vt-d: Items required for kdump

2014-12-22 Thread Li, Zhen-Hua
Add structure type domain_values_entry used for kdump;
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 70 +
 1 file changed, 70 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2dc6250..5ce2850 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -208,6 +209,12 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->val & VTD_PAGE_MASK) : 0;
+}
+
 /*
  * low 64 bits:
  * 0: present
@@ -228,6 +235,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -313,6 +346,43 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA).
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Leaves the current translations in-place so that legacy DMA will
+ *continue to use its current buffers.
+ * 5. Allocates to the device drivers in the crashdump kernel
+ *portions of the iova address ranges that are different
+ *from the iova address ranges that were being used by the old kernel
+ *at the time of the panic.
+ *
+ */
+
+struct domain_values_entry {
+   struct list_head link;  /* link entries into a list */
+   struct iova_domain iovad;   /* iova's that belong to this domain */
+   struct dma_pte  *pgd;   /* virtual address */
+   intdid; /* domain id */
+   intgaw; /* max guest address width */
+   intiommu_superpage; /* Level of superpages supported:
+  0 == 4KiB (no superpages), 1 == 2MiB,
+  2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
+};
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 01/10] iommu/vt-d: Update iommu_attach_domain() and its callers

2014-12-22 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds the 'did' parameter to iommu_attach_domain()
and modifies all of its callers to specify the default value of -1
which says "no did specified, allocate a new one".

This is no functional change from current behaviour -- just enables
a functional change to be made in a later patch.

Bill Sumner:
Original version.

Li, Zhenhua:
Minor change, add change to function __iommu_attach_domain.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1232336..2dc6250 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1534,31 +1534,36 @@ static struct dmar_domain *alloc_domain(int flags)
 }
 
 static int __iommu_attach_domain(struct dmar_domain *domain,
-struct intel_iommu *iommu)
+struct intel_iommu *iommu,
+int domain_number)
 {
int num;
unsigned long ndomains;
 
ndomains = cap_ndoms(iommu->cap);
-   num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num < ndomains) {
-   set_bit(num, iommu->domain_ids);
-   iommu->domains[num] = domain;
-   } else {
-   num = -ENOSPC;
-   }
+   if (domain_number < 0) {
+   num = find_first_zero_bit(iommu->domain_ids, ndomains);
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
+   }
+   } else
+   num = domain_number;
 
return num;
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+  struct intel_iommu *iommu,
+  int domain_number)
 {
int num;
unsigned long flags;
 
spin_lock_irqsave(&iommu->lock, flags);
-   num = __iommu_attach_domain(domain, iommu);
+   num = __iommu_attach_domain(domain, iommu, domain_number);
spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
@@ -1577,7 +1582,7 @@ static int iommu_attach_vm_domain(struct dmar_domain 
*domain,
if (iommu->domains[num] == domain)
return num;
 
-   return __iommu_attach_domain(domain, iommu);
+   return __iommu_attach_domain(domain, iommu, -1);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -2231,6 +2236,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2264,7 +2270,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
@@ -2442,7 +2448,7 @@ static int __init si_domain_init(int hw)
return -EFAULT;
 
for_each_active_iommu(iommu, drhd) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
@@ -3866,7 +3872,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
iommu_enable_translation(iommu);
 
if (si_domain) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0 || si_domain->id != ret)
goto disable_iommu;
domain_attach_iommu(si_domain, iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 06/10] iommu/vt-d: datatypes and functions used for kdump

2014-12-22 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
malloc new context table and copy old context table to the new one.
malloc new page table and copy old page table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Minor change:
Update the usage of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that copies root entry table.
Use new function to copy old context entry tables and page tables.
Use "unsigned long" for physical address.
Change incorrect aw_shift[4] and a few comments in copy_context_entry().

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 540 
 1 file changed, 540 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 126294db..f9849cb 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -399,6 +399,62 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_load_translation_tables()
+ * 
+ */
+
+/*
+ * Lists of domain_values_entry to hold domain values found during the copy.
+ * One list for each iommu in g_number_of_iommus.
+ */
+static struct list_head *domain_values_list;
+
+
+#define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+   u32 first;  /* flag: first-time  */
+   u32 last;   /* flag: last-time */
+   u32 bus;/* last bus number we saw */
+   u32 devfn;  /* last devfn we saw */
+   u32 shift;  /* last shift we saw */
+   u64 pte;/* Page Table Entry */
+   u64 next_addr;  /* next-expected page_addr */
+
+   u64 page_addr;  /* page_addr accumulating size */
+   u64 page_size;  /* page_size accumulated */
+
+   struct domain_values_entry *dve;/* to accumulate iova ranges */
+};
+
+enum returns_from_copy_context_entry {
+RET_CCE_NOT_PRESENT = 1,
+RET_CCE_NEW_PAGE_TABLES,
+RET_CCE_PASS_THROUGH_1,
+RET_CCE_PASS_THROUGH_2,
+RET_CCE_RESERVED_VALUE,
+RET_CCE_PREVIOUS_DID
+};
+
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+ void *ppap, struct context_entry *ce);
+
+static int copy_context_entry_table(struct intel_iommu *iommu,
+   u32 bus, void *ppap,
+   unsigned long *context_new_p,
+   unsigned long context_old_phys);
+
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap);
+
+static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
+   int g_num_of_iommus);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -5039,4 +5095,488 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
memcpy(to + start, from + start, size);
 }
 
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. a change in the bus or device owning the presented page
+ * 2. a change in the page-size of the presented page (parameter shift)
+ * 3. a change in the page-table entry of the presented page
+ * 4. a presented IOVA that does not match the expected next-page address
+ * 5. the 'last' flag is set, indicating that all IOVAs have been seen.
+ */
+static int copy_page_addr(u64 page_addr, u32 shift, u32 bus, u32 devfn,
+   u64 pte, struct domain_values_entry *dve,
+   void *parms)
+{
+   struct copy_page_addr_parms *ppap = parms;
+
+   u64 page_size = ((u64)1 << shift);  /* page_size */
+   u64 pfn_lo;

[PATCH 09/10] iommu/vt-d: Copy functions for irte

2014-12-22 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 57 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 61 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index a55b207..13f2034 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -17,6 +18,11 @@
 
 #include "irq_remapping.h"
 
+#ifdef CONFIG_CRASH_DUMP
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+#endif /* CONFIG_CRASH_DUMP */
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1296,3 +1302,54 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8e29b97..76c6ea5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -290,6 +290,10 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
+#endif
 };
 #endif
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 08/10] iommu/vtd: assign new page table for dma_map

2014-12-22 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a
device, we assign a new and empty page-table, thus removing all
mappings from the old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 56 ++---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 4efed7c..7f8b546 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "irq_remapping.h"
 
@@ -455,6 +456,8 @@ static int copy_root_entry_table(struct intel_iommu *iommu, 
void *ppap);
 static int intel_iommu_load_translation_tables(struct dmar_drhd_unit *drhd,
int g_num_of_iommus);
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -3199,14 +3202,30 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
return NULL;
}
 
-   /* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   /* if in kdump kernel, we need to unmap the mapped dma pages,
+* detach this device first.
+*/
+   if (likely(domain_context_mapped(dev))) {
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unmap_device_dma(domain, dev);
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+#endif
+   return domain;
+   }
+
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
}
 
return domain;
@@ -5687,4 +5706,25 @@ static int intel_iommu_load_translation_tables(struct 
dmar_drhd_unit *drhd,
return 0;
 }
 
+static void unmap_device_dma(struct dmar_domain *domain, struct device *dev)
+{
+   struct intel_iommu *iommu;
+   struct context_entry *ce;
+   struct iova *iova;
+   u8 bus, devfn;
+   phys_addr_t phys_addr;
+   dma_addr_t dev_addr;
+
+   iommu = device_to_iommu(dev, &bus, &devfn);
+   ce = device_to_context_entry(iommu, bus, devfn);
+   phys_addr = context_address_root(ce) << VTD_PAGE_SHIFT;
+   dev_addr = phys_to_dma(dev, phys_addr);
+
+   iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+   if (iova)
+   intel_unmap(dev, dev_addr);
+
+   domain_remove_one_dev_info(domain, dev);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 10/10] iommu/vt-d: Use old irte in kdump kernel

2014-12-22 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in kdump kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 42 -
 1 file changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 13f2034..e244186 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -198,6 +198,11 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, index);
+#endif
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -259,6 +264,11 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, -1);
+#endif
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -640,11 +650,20 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
-   /*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
-*/
-   iommu_disable_irq_remapping(iommu);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /* Do notdisable irq and then re-enable again. */
+   } else {
+#endif
+   /*
+* Disable intr remapping and queued invalidation,
+* if already enabled prior to OS handover.
+*/
+   iommu_disable_irq_remapping(iommu);
+
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
 
dmar_disable_qi(iommu);
}
@@ -687,7 +706,20 @@ static int __init intel_enable_irq_remapping(void)
if (intel_setup_irq_remapping(iommu))
goto error;
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+#endif
iommu_set_irq_remapping(iommu, eim);
+
setup = 1;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2014-12-22 Thread Li, Zhen-Hua
This patchset is an update of Bill Sumner's patchset, implements a fix for:
If a kernel boots with intel_iommu=on on a system that supports intel vt-d, 
when a panic happens, the kdump kernel will boot with these faults:

dmar: DRHD: handling fault status reg 102
dmar: DMAR:[DMA Read] Request device [01:00.0] fault addr fff8
DMAR:[fault reason 01] Present bit in root entry is clear

dmar: DRHD: handling fault status reg 2
dmar: INTR-REMAP: Request device [[61:00.0] fault index 42
INTR-REMAP:[fault reason 34] Present field in the IRTE entry is clear

On some system, the interrupt remapping fault will also happen even if the 
intel_iommu is not set to on, because the interrupt remapping will be enabled 
when x2apic is needed by the system.

The cause of the DMA fault is described in Bill's original version, and the 
INTR-Remap fault is caused by a similar reason. In short, the initialization 
of vt-d drivers causes the in-flight DMA and interrupt requests get wrong 
response.

To fix this problem, we modifies the behaviors of the intel vt-d in the 
crashdump kernel:

For DMA Remapping:
1. To accept the vt-d hardware in an active state,
2. Do not disable and re-enable the translation, keep it enabled.
3. Use the old root entry table, do not rewrite the RTA register.
4. Malloc and use new context entry table and page table, copy data from the 
   old ones that used by the old kernel.
5. to use different portions of the iova address ranges for the device drivers
   in the crashdump kernel than the iova ranges that were in-use at the time
   of the panic.  
6. After device driver is loaded, when it issues the first dma_map command, 
   free the dmar_domain structure for this device, and generate a new one, so 
   that the device can be assigned a new and empty page table. 
7. When a new context entry table is generated, we also save its address to 
   the old root entry table.

For Interrupt Remapping:
1. To accept the vt-d hardware in an active state,
2. Do not disable and re-enable the interrupt remapping, keep it enabled.
3. Use the old interrupt remapping table, do not rewrite the IRTA register.
4. When ioapic entry is setup, the interrupt remapping table is changed, and 
   the updated data will be stored to the old interrupt remapping table.

Advantages of this approach:
1. All manipulation of the IO-device is done by the Linux device-driver
   for that device.
2. This approach behaves in a manner very similar to operation without an
   active iommu.
3. Any activity between the IO-device and its RMRR areas is handled by the
   device-driver in the same manner as during a non-kdump boot.
4. If an IO-device has no driver in the kdump kernel, it is simply left alone.
   This supports the practice of creating a special kdump kernel without
   drivers for any devices that are not required for taking a crashdump. 
5. Minimal code-changes among the existing mainline intel vt-d code.

Summary of changes in this patch set:
1. Added some useful function for root entry table in code intel-iommu.c
2. Added new members to struct root_entry and struct irte;
3. Functions to load old root entry table to iommu->root_entry from the memory 
   of old kernel.
4. Functions to malloc new context entry table and page table and copy the data
   from the old ones to the malloced new ones.
5. Functions to enable support for DMA remapping in kdump kernel.
6. Functions to load old irte data from the old kernel to the kdump kernel.
7. Some code changes that support other behaviours that have been listed.
8. In the new functions, use physical address as "unsigned long" type, not 
   pointers.

Original version by Bill Sumner:
https://lkml.org/lkml/2014/1/10/518
https://lkml.org/lkml/2014/4/15/716
https://lkml.org/lkml/2014/4/24/836

Zhenhua's last of Bill's patchset:
https://lkml.org/lkml/2014/10/21/134
https://lkml.org/lkml/2014/12/15/121

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.
4. Use "unsigned long" as physical address.
5. Use intel_unmap to unmap the old dma;

This patchset should be applied with this one together:
https://lkml.org/lkml/2014/11/5/43
x86/iommu: fix incorrect bit operations in setting values

Bill Sumner (5):
  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: data types and functions used for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: enable kdump support in iommu module

Li, Zhen-Hua (10):
  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu mo

[PATCH 05/10] iommu/vt-d: Add functions to load and save old re

2014-12-22 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 49 +
 include/linux/intel-iommu.h |  5 +
 2 files changed, 54 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 8a7ad72..126294db 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,10 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
+
 struct iommu_remapped_entry {
struct list_head list;
void __iomem *mem;
@@ -4990,4 +4994,49 @@ static int device_to_domain_id(struct intel_iommu 
*iommu, u8 bus, u8 devfn)
return did;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8ffa523..8e29b97 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -329,6 +329,11 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *root_entry_old_virt; /* mapped from old root entry */
+   unsigned long root_entry_old_phys; /* root entry in old kernel */
+#endif
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 03/10] iommu/vt-d: Add domain-id functions

2014-12-22 Thread Li, Zhen-Hua
Interfaces for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Bill Sumner 
---
 drivers/iommu/intel-iommu.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 5ce2850..c0bebd6 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -381,6 +381,13 @@ struct domain_values_entry {
   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
 };
 
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4832,3 +4839,58 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ *
+ */
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link)
+   if (dve->did == did)
+   return dve;
+   return NULL;
+}
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   pr_info("IOMMU:%d Domain ids from panicked kernel:\n", iommu->seq_id);
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link) {
+   set_bit(dve->did, iommu->domain_ids);
+   pr_info("DID did:%d(0x%4.4x)\n", dve->did, dve->did);
+   }
+
+   pr_info("\n");
+   return 0;
+}
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+   int did = -1;   /* domain-id returned */
+   struct root_entry *root;
+   struct context_entry *context;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   did = context_domain_id(context+devfn);
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return did;
+}
+
+#endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 04/10] iommu/vt-d: functions to copy data from old mem

2014-12-22 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 97 +
 include/linux/intel-iommu.h |  9 +
 2 files changed, 106 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c0bebd6..8a7ad72 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,13 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4843,6 +4850,96 @@ static void __init check_tylersburg_isoch(void)
 #ifdef CONFIG_CRASH_DUMP
 
 /*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+/*
  * Interfaces for when a new domain in the crashdump kernel needs some
  * values from the panicked kernel's context entries
  *
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..8ffa523 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -368,4 +369,12 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *intel_iommu_groups[];
 
+#ifdef CONFIG_CRASH_DUMP
+extern int __iommu_load_from_oldmem(void *to, unsigned long from,
+

[PATCH 07/10] iommu/vt-d: enable kdump support in iommu module

2014-12-22 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
device_to_domain_id
get_domain_for_dev
init_dmars
intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
Minor change,
The name of new calling functions.
Do not disable and re-enable TE in kdump kernel.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 142 ++--
 1 file changed, 125 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f9849cb..4efed7c 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -907,6 +907,11 @@ static struct context_entry * 
device_to_context_entry(struct intel_iommu *iommu,
set_root_value(root, phy_addr);
set_root_present(root);
__iommu_flush_cache(iommu, root, sizeof(*root));
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_root_entry(iommu, bus);
+#endif
}
spin_unlock_irqrestore(&iommu->lock, flags);
return &context[devfn];
@@ -958,7 +963,8 @@ static void free_context_table(struct intel_iommu *iommu)
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
root = &iommu->root_entry[i];
@@ -966,10 +972,26 @@ static void free_context_table(struct intel_iommu *iommu)
if (context)
free_pgtable_page(context);
}
-   free_pgtable_page(iommu->root_entry);
-   iommu->root_entry = NULL;
-out:
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry;
+   iommu->root_entry = NULL;
+   } else {
+#endif
+   free_pgtable_page(iommu->root_entry);
+   iommu->root_entry = NULL;
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   iounmap(root);
+#endif
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2381,6 +2403,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct domain_values_entry *dve = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2414,6 +2439,24 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   did = device_to_domain_id(iommu, bus, devfn);
+   if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap)))
+   dve = intel_iommu_did_to_domain_values_entry(did,
+   iommu);
+   if (dve)
+   gaw = dve->gaw;
+   else
+   did = -1;
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2425,6 +2468,18 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
return NULL;
}
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel() && dve) {
+
+   if (domain->pgd)
+   free_pgtable_page(domain->pgd);
+
+   domain->pgd = dve->pgd;
+
+   copy_reserved_iova(&dve->iovad, &domain->iovad);
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
/* register PCI DMA alias device */
if (dev_is_pci(dev)) {
tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
@@ -2948,14 +3003,35 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+ 

[PATCH 09/10] iommu/vt-d: Copy functions for irte

2014-12-15 Thread Li, Zhen-Hua
Functions to copy the irte data from the old kernel into the kdump kernel.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 57 +
 include/linux/intel-iommu.h |  4 +++
 2 files changed, 61 insertions(+)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 27541d4..090ba32 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -17,6 +18,11 @@
 
 #include "irq_remapping.h"
 
+#ifdef CONFIG_CRASH_DUMP
+static int __iommu_load_old_irte(struct intel_iommu *iommu);
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index);
+#endif /* CONFIG_CRASH_DUMP */
+
 struct ioapic_scope {
struct intel_iommu *iommu;
unsigned int id;
@@ -1296,3 +1302,54 @@ int dmar_ir_hotplug(struct dmar_drhd_unit *dmaru, bool 
insert)
 
return ret;
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+static int __iommu_load_old_irte(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   memcpy(iommu->ir_table->base,
+   iommu->ir_table->base_old_virt,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+
+   return 0;
+}
+
+static int __iommu_update_old_irte(struct intel_iommu *iommu, int index)
+{
+   int start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->ir_table)
+   || (!iommu->ir_table->base)
+   || (!iommu->ir_table->base_old_phys)
+   || (!iommu->ir_table->base_old_virt))
+   return -1;
+
+   if (index < -1 || index >= INTR_REMAP_TABLE_ENTRIES)
+   return -1;
+
+   if (index == -1) {
+   start = 0;
+   size = INTR_REMAP_TABLE_ENTRIES * sizeof(struct irte);
+   } else {
+   start = index * sizeof(struct irte);
+   size = sizeof(struct irte);
+   }
+
+   to = iommu->ir_table->base_old_virt;
+   from = iommu->ir_table->base;
+   memcpy(to + start, from + start, size);
+
+   return 0;
+}
+#endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8e29b97..76c6ea5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -290,6 +290,10 @@ struct q_inval {
 struct ir_table {
struct irte *base;
unsigned long *bitmap;
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *base_old_virt;
+   unsigned long base_old_phys;
+#endif
 };
 #endif
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 06/10] iommu/vt-d: datatypes and functions used for kdump

2014-12-15 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Functions:
malloc new context table and copy old context table to the new one.
malloc new page table and copy old page table to the new one.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Minor change:
Update the usage of context_get_* and context_put*, use context_*
and context_set_* for replacement.
Update the name of the function that copies root entry table.
Use new function to copy old context entry tables and page tables.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 542 
 1 file changed, 542 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 126294db..9b2f725 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -399,6 +399,62 @@ struct iommu_remapped_entry {
 static LIST_HEAD(__iommu_remapped_mem);
 static DEFINE_MUTEX(__iommu_mem_list_lock);
 
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_copy_translation_tables()
+ * 
+ */
+
+/*
+ * Lists of domain_values_entry to hold domain values found during the copy.
+ * One list for each iommu in g_number_of_iommus.
+ */
+static struct list_head *domain_values_list;
+
+
+#define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+   u32 first;  /* flag: first-time  */
+   u32 last;   /* flag: last-time */
+   u32 bus;/* last bus number we saw */
+   u32 devfn;  /* last devfn we saw */
+   u32 shift;  /* last shift we saw */
+   u64 pte;/* Page Table Entry */
+   u64 next_addr;  /* next-expected page_addr */
+
+   u64 page_addr;  /* page_addr accumulating size */
+   u64 page_size;  /* page_size accumulated */
+
+   struct domain_values_entry *dve;/* to accumulate iova ranges */
+};
+
+enum returns_from_copy_context_entry {
+RET_CCE_NOT_PRESENT = 1,
+RET_CCE_NEW_PAGE_TABLES,
+RET_CCE_PASS_THROUGH_1,
+RET_CCE_PASS_THROUGH_2,
+RET_CCE_RESERVED_VALUE,
+RET_CCE_PREVIOUS_DID
+};
+
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+ void *ppap, struct context_entry *ce);
+
+static int copy_context_entry_table(struct intel_iommu *iommu,
+   u32 bus, void *ppap,
+   struct context_entry **context_new_p,
+   unsigned long context_old_phys);
+
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap);
+
+static int intel_iommu_copy_translation_tables(struct dmar_drhd_unit *drhd,
+   int g_num_of_iommus);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -5039,4 +5095,490 @@ static void __iommu_update_old_root_entry(struct 
intel_iommu *iommu, int index)
memcpy(to + start, from + start, size);
 }
 
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. a change in the bus or device owning the presented page
+ * 2. a change in the page-size of the presented page (parameter shift)
+ * 3. a change in the page-table entry of the presented page
+ * 4. a presented IOVA that does not match the expected next-page address
+ * 5. the 'last' flag is set, indicating that all IOVAs have been seen.
+ */
+static int copy_page_addr(u64 page_addr, u32 shift, u32 bus, u32 devfn,
+   u64 pte, struct domain_values_entry *dve,
+   void *parms)
+{
+   struct copy_page_addr_parms *ppap = parms;
+
+   u64 page_size = ((u64)1 << shift);  /* page_size */
+   u64 pfn_lo; /* For reserving IOVA range */
+   u64 pfn_hi; /* For re

[PATCH 02/10] iommu/vt-d: Items required for kdump

2014-12-15 Thread Li, Zhen-Hua
Add structure type domain_values_entry used for kdump;
Add context entry functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 70 +
 1 file changed, 70 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2dc6250..5ce2850 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -208,6 +209,12 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline unsigned long
+get_context_phys_from_root(struct root_entry *root)
+{
+   return  root_present(root) ? (root->val & VTD_PAGE_MASK) : 0;
+}
+
 /*
  * low 64 bits:
  * 0: present
@@ -228,6 +235,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -313,6 +346,43 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA).
+ * 2. Do not re-enable IOMMU's translating.
+ * 3. In kdump kernel, use the old root entry table.
+ * 4. Leaves the current translations in-place so that legacy DMA will
+ *continue to use its current buffers.
+ * 5. Allocates to the device drivers in the crashdump kernel
+ *portions of the iova address ranges that are different
+ *from the iova address ranges that were being used by the old kernel
+ *at the time of the panic.
+ *
+ */
+
+struct domain_values_entry {
+   struct list_head link;  /* link entries into a list */
+   struct iova_domain iovad;   /* iova's that belong to this domain */
+   struct dma_pte  *pgd;   /* virtual address */
+   intdid; /* domain id */
+   intgaw; /* max guest address width */
+   intiommu_superpage; /* Level of superpages supported:
+  0 == 4KiB (no superpages), 1 == 2MiB,
+  2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
+};
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 10/10] iommu/vt-d: Use old irte in kdump kernel

2014-12-15 Thread Li, Zhen-Hua
Fix the intr-remapping fault.

[1.594890] dmar: DRHD: handling fault status reg 2
[1.594894] dmar: INTR-REMAP: Request device [[41:00.0] fault index 4d
[1.594894] INTR-REMAP:[fault reason 34] Present field in the IRTE entry
is clear

Use old irte in kdump kernel, do not disable and re-enable interrupt
remapping.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel_irq_remapping.c | 42 -
 1 file changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c 
b/drivers/iommu/intel_irq_remapping.c
index 090ba32..fee7d66 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -198,6 +198,11 @@ static int modify_irte(int irq, struct irte *irte_modified)
 
set_64bit(&irte->low, irte_modified->low);
set_64bit(&irte->high, irte_modified->high);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, index);
+#endif
__iommu_flush_cache(iommu, irte, sizeof(*irte));
 
rc = qi_flush_iec(iommu, index, 0);
@@ -259,6 +264,11 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
bitmap_release_region(iommu->ir_table->bitmap, index,
  irq_iommu->irte_mask);
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_irte(iommu, -1);
+#endif
+
return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
 
@@ -640,11 +650,20 @@ static int __init intel_enable_irq_remapping(void)
 */
dmar_fault(-1, iommu);
 
-   /*
-* Disable intr remapping and queued invalidation, if already
-* enabled prior to OS handover.
-*/
-   iommu_disable_irq_remapping(iommu);
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /* Do notdisable irq and then re-enable again. */
+   } else {
+#endif
+   /*
+* Disable intr remapping and queued invalidation,
+* if already enabled prior to OS handover.
+*/
+   iommu_disable_irq_remapping(iommu);
+
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
 
dmar_disable_qi(iommu);
}
@@ -687,7 +706,20 @@ static int __init intel_enable_irq_remapping(void)
if (intel_setup_irq_remapping(iommu))
goto error;
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   unsigned long long q;
+
+   q = dmar_readq(iommu->reg + DMAR_IRTA_REG);
+   iommu->ir_table->base_old_phys = q & VTD_PAGE_MASK;
+   iommu->ir_table->base_old_virt = ioremap_cache(
+   iommu->ir_table->base_old_phys,
+   INTR_REMAP_TABLE_ENTRIES*sizeof(struct irte));
+   __iommu_load_old_irte(iommu);
+   } else
+#endif
iommu_set_irq_remapping(iommu, eim);
+
setup = 1;
}
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 05/10] iommu/vt-d: Add functions to load and save old re

2014-12-15 Thread Li, Zhen-Hua
Add functions to load root entry table from old kernel, and to save updated
root entry table.
Add two member in struct intel_iommu, to store the RTA in old kernel, and
the mapped virt address of it.

We use the old RTA in dump kernel, and when the iommu->root_entry is used as
a cache in kdump kernel, its phys address will not be save to RTA register,
but when its data is changed, we will save the new data to old root entry table.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 49 +
 include/linux/intel-iommu.h |  5 +
 2 files changed, 54 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 8a7ad72..126294db 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,10 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu);
+
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int 
index);
+
 struct iommu_remapped_entry {
struct list_head list;
void __iomem *mem;
@@ -4990,4 +4994,49 @@ static int device_to_domain_id(struct intel_iommu 
*iommu, u8 bus, u8 devfn)
return did;
 }
 
+/*
+ * Load the old root entry table to new root entry table.
+ */
+static void __iommu_load_old_root_entry(struct intel_iommu *iommu)
+{
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+   memcpy(iommu->root_entry, iommu->root_entry_old_virt, PAGE_SIZE);
+}
+
+/*
+ * When the data in new root entry table is changed, this function
+ * must be called to save the updated data to old root entry table.
+ */
+static void __iommu_update_old_root_entry(struct intel_iommu *iommu, int index)
+{
+   u8 start;
+   unsigned long size;
+   void __iomem *to;
+   void *from;
+
+   if ((!iommu)
+   || (!iommu->root_entry)
+   || (!iommu->root_entry_old_virt)
+   || (!iommu->root_entry_old_phys))
+   return;
+
+   if (index < -1 || index >= ROOT_ENTRY_NR)
+   return;
+
+   if (index == -1) {
+   start = 0;
+   size = ROOT_ENTRY_NR * sizeof(struct root_entry);
+   } else {
+   start = index * sizeof(struct root_entry);
+   size = sizeof(struct root_entry);
+   }
+   to = iommu->root_entry_old_virt;
+   from = iommu->root_entry;
+   memcpy(to + start, from + start, size);
+}
+
 #endif /* CONFIG_CRASH_DUMP */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 8ffa523..8e29b97 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -329,6 +329,11 @@ struct intel_iommu {
spinlock_t  lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */
 
+#ifdef CONFIG_CRASH_DUMP
+   void __iomem *root_entry_old_virt; /* mapped from old root entry */
+   unsigned long root_entry_old_phys; /* root entry in old kernel */
+#endif
+
struct iommu_flush flush;
 #endif
struct q_inval  *qi;/* Queued invalidation info */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 04/10] iommu/vt-d: functions to copy data from old mem

2014-12-15 Thread Li, Zhen-Hua
Add some functions to copy the data from old kernel.
These functions are used to copy context tables and page tables.

To avoid calling iounmap between spin_lock_irqsave and spin_unlock_irqrestore,
use a link here, store the pointers , and then use iounmap to free them in
another place.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 97 +
 include/linux/intel-iommu.h |  9 +
 2 files changed, 106 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c0bebd6..8a7ad72 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -388,6 +388,13 @@ static int intel_iommu_get_dids_from_old_kernel(struct 
intel_iommu *iommu);
 
 static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
 
+struct iommu_remapped_entry {
+   struct list_head list;
+   void __iomem *mem;
+};
+static LIST_HEAD(__iommu_remapped_mem);
+static DEFINE_MUTEX(__iommu_mem_list_lock);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4843,6 +4850,96 @@ static void __init check_tylersburg_isoch(void)
 #ifdef CONFIG_CRASH_DUMP
 
 /*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+int __iommu_load_from_oldmem(void *to, unsigned long from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = from >> VTD_PAGE_SHIFT;
+   offset = from & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(to, pfn_to_kaddr(pfn) + offset, csize);
+   } else{
+
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)from, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(to, virt_mem, size);
+
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Copy memory from a virtually-addressed area into a physically-addressed area
+ */
+int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size)
+{
+   unsigned long pfn;  /* Page Frame Number */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of to */
+   void __iomem *virt_mem;
+   struct iommu_remapped_entry *mapped;
+
+   pfn = to >> VTD_PAGE_SHIFT;
+   offset = to & (~VTD_PAGE_MASK);
+
+   if (page_is_ram(pfn)) {
+   memcpy(pfn_to_kaddr(pfn) + offset, from, csize);
+   } else{
+   mapped = kzalloc(sizeof(struct iommu_remapped_entry),
+   GFP_KERNEL);
+   if (!mapped)
+   return -ENOMEM;
+
+   virt_mem = ioremap_cache((unsigned long)to, size);
+   if (!virt_mem) {
+   kfree(mapped);
+   return -ENOMEM;
+   }
+   memcpy(virt_mem, from, size);
+   mutex_lock(&__iommu_mem_list_lock);
+   mapped->mem = virt_mem;
+   list_add_tail(&mapped->list, &__iommu_remapped_mem);
+   mutex_unlock(&__iommu_mem_list_lock);
+   }
+   return size;
+}
+
+/*
+ * Free the mapped memory for ioremap;
+ */
+int __iommu_free_mapped_mem(void)
+{
+   struct iommu_remapped_entry *mem_entry, *tmp;
+
+   mutex_lock(&__iommu_mem_list_lock);
+   list_for_each_entry_safe(mem_entry, tmp, &__iommu_remapped_mem, list) {
+   iounmap(mem_entry->mem);
+   list_del(&mem_entry->list);
+   kfree(mem_entry);
+   }
+   mutex_unlock(&__iommu_mem_list_lock);
+   return 0;
+}
+/*
  * Interfaces for when a new domain in the crashdump kernel needs some
  * values from the panicked kernel's context entries
  *
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..8ffa523 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -368,4 +369,12 @@ extern int dmar_ir_support(void);
 
 extern const struct attribute_group *intel_iommu_groups[];
 
+#ifdef CONFIG_CRASH_DUMP
+extern int __iommu_load_from_oldmem(void *to, unsigned long from,
+

[PATCH 07/10] iommu/vt-d: enable kdump support in iommu module

2014-12-15 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
 device_to_domain_id
 get_domain_for_dev
 init_dmars
 intel_iommu_init

Bill Sumner:
Original version.

Zhenhua:
Minor change, change some function name, add spin_lock_irqsave.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 142 ++--
 1 file changed, 125 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 9b2f725..4837ce5 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -907,6 +907,11 @@ static struct context_entry * 
device_to_context_entry(struct intel_iommu *iommu,
set_root_value(root, phy_addr);
set_root_present(root);
__iommu_flush_cache(iommu, root, sizeof(*root));
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   __iommu_update_old_root_entry(iommu, bus);
+#endif
}
spin_unlock_irqrestore(&iommu->lock, flags);
return &context[devfn];
@@ -958,7 +963,8 @@ static void free_context_table(struct intel_iommu *iommu)
 
spin_lock_irqsave(&iommu->lock, flags);
if (!iommu->root_entry) {
-   goto out;
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return;
}
for (i = 0; i < ROOT_ENTRY_NR; i++) {
root = &iommu->root_entry[i];
@@ -966,10 +972,26 @@ static void free_context_table(struct intel_iommu *iommu)
if (context)
free_pgtable_page(context);
}
-   free_pgtable_page(iommu->root_entry);
-   iommu->root_entry = NULL;
-out:
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   iommu->root_entry_old_phys = 0;
+   root = iommu->root_entry;
+   iommu->root_entry = NULL;
+   } else {
+#endif
+   free_pgtable_page(iommu->root_entry);
+   iommu->root_entry = NULL;
+#ifdef CONFIG_CRASH_DUMP
+   }
+#endif
+
spin_unlock_irqrestore(&iommu->lock, flags);
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel())
+   iounmap(root);
+#endif
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
@@ -2381,6 +2403,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct domain_values_entry *dve = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2414,6 +2439,24 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   did = device_to_domain_id(iommu, bus, devfn);
+   if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap)))
+   dve = intel_iommu_did_to_domain_values_entry(did,
+   iommu);
+   if (dve)
+   gaw = dve->gaw;
+   else
+   did = -1;
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2425,6 +2468,18 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
return NULL;
}
 
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel() && dve) {
+
+   if (domain->pgd)
+   free_pgtable_page(domain->pgd);
+
+   domain->pgd = dve->pgd;
+
+   copy_reserved_iova(&dve->iovad, &domain->iovad);
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
/* register PCI DMA alias device */
if (dev_is_pci(dev)) {
tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
@@ -2948,14 +3003,35 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret)
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   

[PATCH 08/10] iommu/vtd: assign new page table for dma_map

2014-12-15 Thread Li, Zhen-Hua
When a device driver issues the first dma_map command for a
device, we assign a new and empty page-table, thus removing all
mappings from the old kernel for the device.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 27 ---
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 4837ce5..f11a9b1 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3200,15 +3200,28 @@ static struct dmar_domain 
*__get_valid_domain_for_dev(struct device *dev)
}
 
/* make sure context mapping is ok */
-   if (unlikely(!domain_context_mapped(dev))) {
-   ret = domain_context_mapping(domain, dev, 
CONTEXT_TT_MULTI_LEVEL);
-   if (ret) {
-   printk(KERN_ERR "Domain context map for %s failed",
-  dev_name(dev));
-   return NULL;
-   }
+   if (likely(domain_context_mapped(dev))) {
+#ifdef CONFIG_CRASH_DUMP
+   if (is_kdump_kernel()) {
+   domain_exit(domain);
+   domain = get_domain_for_dev(dev,
+   DEFAULT_DOMAIN_ADDRESS_WIDTH);
+   if (!domain) {
+   pr_err("Allocating domain for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
+   } else
+#endif
+   return domain;
}
 
+   ret = domain_context_mapping(domain, dev, CONTEXT_TT_MULTI_LEVEL);
+   if (ret) {
+   pr_err("Domain context map for %s failed",
+  dev_name(dev));
+   return NULL;
+   }
return domain;
 }
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 03/10] iommu/vt-d: Add domain-id functions

2014-12-15 Thread Li, Zhen-Hua
Interfaces for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Bill Sumner 
---
 drivers/iommu/intel-iommu.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 5ce2850..c0bebd6 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -381,6 +381,13 @@ struct domain_values_entry {
   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
 };
 
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4832,3 +4839,58 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ *
+ */
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link)
+   if (dve->did == did)
+   return dve;
+   return NULL;
+}
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   pr_info("IOMMU:%d Domain ids from panicked kernel:\n", iommu->seq_id);
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link) {
+   set_bit(dve->did, iommu->domain_ids);
+   pr_info("DID did:%d(0x%4.4x)\n", dve->did, dve->did);
+   }
+
+   pr_info("\n");
+   return 0;
+}
+
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+   int did = -1;   /* domain-id returned */
+   struct root_entry *root;
+   struct context_entry *context;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   did = context_domain_id(context+devfn);
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return did;
+}
+
+#endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/10] iommu/vt-d: Fix intel vt-d faults in kdump kernel

2014-12-15 Thread Li, Zhen-Hua
This patchset is an update of Bill Sumner's patchset, implements a fix for:
If a kernel boots with intel_iommu=on on a system that supports intel vt-d, 
when a panic happens, the kdump kernel will boot with these faults:

dmar: DRHD: handling fault status reg 102
dmar: DMAR:[DMA Read] Request device [01:00.0] fault addr fff8
DMAR:[fault reason 01] Present bit in root entry is clear

dmar: DRHD: handling fault status reg 2
dmar: INTR-REMAP: Request device [[61:00.0] fault index 42
INTR-REMAP:[fault reason 34] Present field in the IRTE entry is clear

On some system, the interrupt remapping fault will also happen even if the 
intel_iommu is not set to on, because the interrupt remapping will be enabled 
when x2apic is needed by the system.

The cause of the DMA fault is described in Bill's original version, and the 
INTR-Remap fault is caused by a similar reason. In short, the initialization 
of vt-d drivers causes the in-flight DMA and interrupt requests get wrong 
response.

To fix this problem, we modifies the behaviors of the intel vt-d in the 
crashdump kernel:

For DMA Remapping:
1. To accept the vt-d hardware in an active state,
2. Do not disable and re-enable the translation, keep it enabled.
3. Use the old root entry table, do not rewrite the RTA register.
4. Malloc and use new context entry table and page table, copy data from the 
   old ones that used by the old kernel.
5. to use different portions of the iova address ranges for the device drivers
   in the crashdump kernel than the iova ranges that were in-use at the time
   of the panic.  
6. After device driver is loaded, when it issues the first dma_map command, 
   free the dmar_domain structure for this device, and generate a new one, so 
   that the device can be assigned a new and empty page table. 
7. When a new context entry table is generated, we also save its address to 
   the old root entry table.

For Interrupt Remapping:
1. To accept the vt-d hardware in an active state,
2. Do not disable and re-enable the interrupt remapping, keep it enabled.
3. Use the old interrupt remapping table, do not rewrite the IRTA register.
4. When ioapic entry is setup, the interrupt remapping table is changed, and 
   the updated data will be stored to the old interrupt remapping table.

Advantages of this approach:
1. All manipulation of the IO-device is done by the Linux device-driver
   for that device.
2. This approach behaves in a manner very similar to operation without an
   active iommu.
3. Any activity between the IO-device and its RMRR areas is handled by the
   device-driver in the same manner as during a non-kdump boot.
4. If an IO-device has no driver in the kdump kernel, it is simply left alone.
   This supports the practice of creating a special kdump kernel without
   drivers for any devices that are not required for taking a crashdump. 
5. Minimal code-changes among the existing mainline intel vt-d code.

Summary of changes in this patch set:
1. Added some useful function for root entry table in code intel-iommu.c
2. Added new members to struct root_entry and struct irte;
3. Functions to load old root entry table to iommu->root_entry from the memory 
   of old kernel.
4. Functions to malloc new context entry table and page table and copy the data
   from the old ones to the malloced new ones.
5. Functions to enable support for DMA remapping in kdump kernel.
6. Functions to load old irte data from the old kernel to the kdump kernel.
7. Some code changes that support other behaviours that have been listed.
8. In the new functions, use physical address as "unsigned long" type, not 
   pointers.

Original version by Bill Sumner:
https://lkml.org/lkml/2014/1/10/518
https://lkml.org/lkml/2014/4/15/716
https://lkml.org/lkml/2014/4/24/836

Zhenhua's last of Bill's patchset:
https://lkml.org/lkml/2014/10/21/134

Changed in this version:
1. Do not disable and re-enable traslation and interrupt remapping. 
2. Use old root entry table.
3. Use old interrupt remapping table.

This patchset should be applied with this one together:
https://lkml.org/lkml/2014/11/5/43
x86/iommu: fix incorrect bit operations in setting values

Bill Sumner (5):
  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: data types and functions used for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: enable kdump support in iommu module

Li, Zhen-Hua (10):
  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: functions to copy data from old mem
  iommu/vt-d: Add functions to load and save old re
  iommu/vt-d: datatypes and functions used for kdump
  iommu/vt-d: enable kdump support in iommu module
  iommu/vtd: assign new page table for dma_map
  iommu/vt-d: Copy functions for irte
  iommu/vt-d: Use old irt

[PATCH 01/10] iommu/vt-d: Update iommu_attach_domain() and its callers

2014-12-15 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds the 'did' parameter to iommu_attach_domain()
and modifies all of its callers to specify the default value of -1
which says "no did specified, allocate a new one".

This is no functional change from current behaviour -- just enables
a functional change to be made in a later patch.

Bill Sumner:
Original version.

Li, Zhenhua:
Minor change, add change to function __iommu_attach_domain.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 34 --
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1232336..2dc6250 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1534,31 +1534,36 @@ static struct dmar_domain *alloc_domain(int flags)
 }
 
 static int __iommu_attach_domain(struct dmar_domain *domain,
-struct intel_iommu *iommu)
+struct intel_iommu *iommu,
+int domain_number)
 {
int num;
unsigned long ndomains;
 
ndomains = cap_ndoms(iommu->cap);
-   num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num < ndomains) {
-   set_bit(num, iommu->domain_ids);
-   iommu->domains[num] = domain;
-   } else {
-   num = -ENOSPC;
-   }
+   if (domain_number < 0) {
+   num = find_first_zero_bit(iommu->domain_ids, ndomains);
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
+   }
+   } else
+   num = domain_number;
 
return num;
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+  struct intel_iommu *iommu,
+  int domain_number)
 {
int num;
unsigned long flags;
 
spin_lock_irqsave(&iommu->lock, flags);
-   num = __iommu_attach_domain(domain, iommu);
+   num = __iommu_attach_domain(domain, iommu, domain_number);
spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
@@ -1577,7 +1582,7 @@ static int iommu_attach_vm_domain(struct dmar_domain 
*domain,
if (iommu->domains[num] == domain)
return num;
 
-   return __iommu_attach_domain(domain, iommu);
+   return __iommu_attach_domain(domain, iommu, -1);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -2231,6 +2236,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2264,7 +2270,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
@@ -2442,7 +2448,7 @@ static int __init si_domain_init(int hw)
return -EFAULT;
 
for_each_active_iommu(iommu, drhd) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
@@ -3866,7 +3872,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
iommu_enable_translation(iommu);
 
if (si_domain) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0 || si_domain->id != ret)
goto disable_iommu;
domain_attach_iommu(si_domain, iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] x86/iommu: fix incorrect bit operations in setting values

2014-11-04 Thread Li, Zhen-Hua
The function context_set_address_root() and set_root_value are setting new
address in a wrong way, and this patch is trying to fix this problem.

According to Intel Vt-d specs(Feb 2011, Revision 1.3), Chapter 9.1 and 9.2,
field ctp in root entry is using bits 12:63, field asr in context entry is
using bits 12:63.

To set these fields, the following functions are used:
static inline void context_set_address_root(struct context_entry *context,
unsigned long value);
and
static inline void set_root_value(struct root_entry *root, unsigned long value)

But they are using an invalid method to set these fields, in current code, only
a '|' operator is used to set it. This will not set the asr to the expected
value if it has an old value.

For example:
Before calling this function,
context->lo = 0x3456789012111;
value = 0x123456789abcef12;

After we call context_set_address_root(context, value), expected result is
context->lo == 0x123456789abce111;

But the actual result is:
context->lo == 0x1237577f9bbde111;

So we need to clear bits 12:63 before setting the new value, this will fix
this problem.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a27d6cb..11ac47b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -195,6 +195,7 @@ static inline void set_root_present(struct root_entry *root)
 }
 static inline void set_root_value(struct root_entry *root, unsigned long value)
 {
+   root->val &= ~VTD_PAGE_MASK;
root->val |= value & VTD_PAGE_MASK;
 }
 
@@ -247,6 +248,7 @@ static inline void context_set_translation_type(struct 
context_entry *context,
 static inline void context_set_address_root(struct context_entry *context,
unsigned long value)
 {
+   context->lo &= ~VTD_PAGE_MASK;
context->lo |= value & VTD_PAGE_MASK;
 }
 
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 0/5] iommu/vt-d: Fix crash dump failure caused by legacy DMA/IO

2014-10-22 Thread Li, Zhen-Hua

Hi Baoquan,
I tested it on 3.17, it does not have these faults. There are little 
differences between this version and Bill's last version.

I will test it on 3.18.0-rc1+ on my system and let you know the result.

And could you send me the result of "lspci -vvv " on your system?

Thanks
Zhenhua

> 在 2014年10月22日,18:05,"Baoquan He"  写道:
> 
> Hi Zhenhua,
> 
> I tested your latest patch on 3.18.0-rc1+, there are still some dmar
> errors. I remember it worked well with Bill's original patchset.
> 
> 
> 0console [earlya[0.00] allocate tes of page_cg  'a ong[
> 0.00] tsc: Fast TSC calibration using PIT
> 0031] Calibrating delay loop (skipped), value calculated using timer
> frequency.. 5586.77 BogoMIPS (lpj=2793386)
> [0.010682] pid_max: default: 32768 minimum: 301
> [0.015317] ACPI: Core revision 20140828
> [0.044598] ACPI: All ACPI Tables successfully acquired
> [0.126450] Security Framework initialized
> [0.130569] SELinux:  Initializing.
> [0.135211] Dentry cache hash table entries: 2097152 (order: 12,
> 16777216 bytes)
> [0.145731] Inode-cache hash table entries: 1048576 (order: 11,
> 8388608 bytes)
> [0.154249] Mount-cache hash table entries: 32768 (order: 6, 262144
> bytes)
> [0.161163] Mountpoint-cache hash table entries: 32768 (order: 6,
> 262144 bytes)
> [0.168731] Initializing cgroup subsys memory
> [0.173110] Initializing cgroup subsys devices
> [0.177570] Initializing cgroup subsys freezer
> [0.182026] Initializing cgroup subsys net_cls
> [0.186483] Initializing cgroup subsys blkio
> [0.190763] Initializing cgroup subsys perf_event
> [0.195479] Initializing cgroup subsys hugetlb
> [0.199955] CPU: Physical Processor ID: 0
> [0.203972] CPU: Processor Core ID: 0
> [0.207649] ENERGY_PERF_BIAS: Set to 'normal', was 'performance'
> [0.207649] ENERGY_PERF_BIAS: View and update with
> x86_energy_perf_policy(8)
> [0.220704] mce: CPU supports 16 MCE banks
> [0.224832] CPU0: Thermal monitoring enabled (TM1)
> [0.229658] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
> [0.229658] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
> [0.241537] Freeing SMP alternatives memory: 24K (81e8 -
> 81e86000)
> [0.250740] ftrace: allocating 27051 entries in 106 pages
> [0.268137] dmar: Host address width 46
> [0.271986] dmar: DRHD base: 0x00dfffc000 flags: 0x1
> [0.277314] dmar: IOMMU 0: reg_base_addr dfffc000 ver 1:0 cap
> d2078c106f0462 ecap f020fe
> [0.285423] dmar: RMRR base: 0x00cba11000 end: 0x00cba27fff
> [0.291703] dmar: ATSR flags: 0x0
> [0.295122] IOAPIC id 0 under DRHD base  0xdfffc000 IOMMU 0
> [0.300704] IOAPIC id 2 under DRHD base  0xdfffc000 IOMMU 0
> [0.306281] HPET id 0 under DRHD base 0xdfffc000
> [0.311011] Enabled IRQ remapping in xapic mode
> [0.316070] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
> [0.332096] smpboot: CPU0: Intel(R) Xeon(R) CPU E5-1603 0 @ 2.80GHz
> (fam: 06, model: 2d, stepping: 07)
> [0.341495] Performance Events: PEBS fmt1+, 16-deep LBR, SandyBridge
> events, full-width counters, Intel PMU driver.
> [0.352047] perf_event_intel: PEBS disabled due to CPU errata, please
> upgrade microcode
> [0.360060] ... version:3
> [0.364081] ... bit width:  48
> [0.368182] ... generic registers:  8
> [0.372196] ... value mask: 
> [0.377513] ... max period: 
> [0.382829] ... fixed-purpose events:   3
> [0.386842] ... event mask: 000700ff
> [0.393368] x86: Booting SMP configuration:
> [0.397563]  node  #0, CPUs:  #1
> [0.414672] NMI watchdog: enabled on all CPUs, permanently consumes
> one hw-PMU counter.
> [0.422957]  #2 #3
> [0.451320] x86: Booted up 1 node, 4 CPUs
> [0.455539] smpboot: Total of 4 processors activated (22347.08
> BogoMIPS)
> [0.466369] devtmpfs: initialized
> [0.472993] PM: Registering ACPI NVS region [mem
> 0xcb75-0xcb7dafff] (569344 bytes)
> [0.480930] PM: Registering ACPI NVS region [mem
> 0xcbaad000-0xcbaaefff] (8192 bytes)
> [0.488689] PM: Registering ACPI NVS region [mem
> 0xcbabb000-0xcbacdfff] (77824 bytes)
> [0.496535] PM: Registering ACPI NVS region [mem
> 0xcbb56000-0xcbb5dfff] (32768 bytes)
> [0.504380] PM: Registering ACPI NVS region [mem
> 0xcbb71000-0xcbff] (4780032 bytes)
> [0.513294] atomic64_test: passed for x86-64 platform with CX8 and
> with SSE
> [0.520272] pinctrl core: initialized pinctrl subsystem
> [0.525549] RTC time:  9:52:43, date: 10/22/14
> [0.530096] NET: Registered protocol family 16
> [0.539573] cpuidle: using governor menu
> [0.543583] ACPI: bus type PCI registered
> [0.547608] acpiphp: ACPI Hot Plug PCI Controller Driver version: 0.5
> [0.554133] PCI: MMCONFIG for domain  [bus 00-ff] at [mem
> 0xe000-

[PATCH 3/5] iommu/vt-d: data types and functions used for kdump

2014-10-21 Thread Li, Zhen-Hua
Populate it with support functions to copy iommu translation tables from
from the panicked kernel into the kdump kernel in the event of a crash.

Bill Sumner:
Original version, the creation of the data types and functions.

Li, Zhenhua:
Minor change: update the usage of context_get_* and context_put*,
use context_* and context_set_* for replacement.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 562 
 1 file changed, 562 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 99fe408..73afed4 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -378,6 +378,65 @@ struct domain_values_entry {
   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
 };
 
+/*
+ * Lists of domain_values_entry to hold domain values found during the copy.
+ * One list for each iommu in g_number_of_iommus.
+ */
+static struct list_head *domain_values_list;
+
+
+/* 
+ * Copy iommu translation tables from old kernel into new  kernel.
+ * Entry to this set of functions is: intel_iommu_copy_translation_tables()
+ * 
+ */
+#define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
+
+/*
+ * Struct copy_page_addr_parms is used to allow copy_page_addr()
+ * to accumulate values across multiple calls and returns.
+ */
+struct copy_page_addr_parms {
+   u32 first;  /* flag: first-time  */
+   u32 last;   /* flag: last-time */
+   u32 bus;/* last bus number we saw */
+   u32 devfn;  /* last devfn we saw */
+   u32 shift;  /* last shift we saw */
+   u64 pte;/* Page Table Entry */
+   u64 next_addr;  /* next-expected page_addr */
+
+   u64 page_addr;  /* page_addr accumulating size */
+   u64 page_size;  /* page_size accumulated */
+
+   struct domain_values_entry *dve;/* to accumulate iova ranges */
+};
+
+enum returns_from_copy_context_entry {
+RET_CCE_NOT_PRESENT = 1,
+RET_CCE_NEW_PAGE_TABLES,
+RET_CCE_PASS_THROUGH_1,
+RET_CCE_PASS_THROUGH_2,
+RET_CCE_RESERVED_VALUE,
+RET_CCE_PREVIOUS_DID
+};
+
+static int copy_context_entry(struct intel_iommu *iommu, u32 bus, u32 devfn,
+ void *ppap, struct context_entry *ce);
+
+static int copy_context_entry_table(struct intel_iommu *iommu,
+   u32 bus, void *ppap,
+   struct context_entry **context_new_p,
+   struct context_entry *context_old_phys);
+
+static int copy_root_entry_table(struct intel_iommu *iommu, void *ppap,
+struct root_entry  **root_new_virt_p,
+struct root_entry  *root_old_phys);
+
+static int intel_iommu_copy_translation_tables(struct dmar_drhd_unit *drhd,
+   struct root_entry **root_old_phys_p,
+   struct root_entry **root_new_virt_p,
+   int g_num_of_iommus);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -4669,3 +4728,506 @@ static void __init check_tylersburg_isoch(void)
printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 
16; your BIOS set %d\n",
   vtisochctrl);
 }
+
+#ifdef CONFIG_CRASH_DUMP
+
+/*
+ * Copy memory from a physically-addressed area into a virtually-addressed area
+ */
+static int oldcopy(void *to, void *from, int size)
+{
+   size_t ret = 0; /* Length copied */
+   unsigned long pfn;  /* Page Frame Number */
+   char *buf = to; /* Adr(Output buffer) */
+   size_t csize = (size_t)size;/* Num(bytes to copy) */
+   unsigned long offset;   /* Lower 12 bits of from */
+   int userbuf = 0;/* to is in kernel space */
+
+
+   pfn = ((unsigned long) from) >> VTD_PAGE_SHIFT;
+   offset = ((unsigned long) from) & (~VTD_PAGE_MASK);
+   ret = copy_oldmem_page(pfn, buf, csize, offset, userbuf);
+
+   return (int) ret;
+}
+
+
+/*
+ * constant for initializing instances of copy_page_addr_parms properly.
+ */
+static struct copy_page_addr_parms copy_page_addr_parms_init = {1, 0};
+
+
+
+/*
+ * Lowest-level function in the 'Copy Page Tables' set
+ * Called once for each page_addr present in an iommu page-address table.
+ *
+ * Because of the depth-first traversal of the page-tables by the
+ * higher-level functions that call 'copy_page_addr', all pages
+ * of a domain will be presented in ascending order of IO Virtual Address.
+ *
+ * This function accumulates each contiguous range of these IOVAs and
+ * reserves it within the proper domain in the crashdump kernel when a
+ * non-contiguous range is detected, as determined by any of the following:
+ * 1. 

[PATCH 5/5] iommu/vt-d: enable kdump support in iommu module

2014-10-21 Thread Li, Zhen-Hua
Modify the operation of the following functions when called during crash dump:
 device_to_domain_id
 get_domain_for_dev
 init_dmars
 intel_iommu_init

Signed-off-by: Bill Sumner 
---
 drivers/iommu/intel-iommu.c | 134 +++-
 1 file changed, 121 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index bde8f22..be12dab 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -393,6 +394,8 @@ static struct list_head *domain_values_list;
  */
 #define RET_BADCOPY -1 /* Return-code: Cannot copy translate tables */
 
+static int intel_iommu_in_crashdump;
+
 /*
  * Struct copy_page_addr_parms is used to allow copy_page_addr()
  * to accumulate values across multiple calls and returns.
@@ -2287,6 +2290,24 @@ static void domain_remove_dev_info(struct dmar_domain 
*domain)
spin_unlock_irqrestore(&device_domain_lock, flags);
 }
 
+#ifdef CONFIG_CRASH_DUMP
+static int device_to_domain_id(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+   int did = -1;   /* domain-id returned */
+   struct root_entry *root;
+   struct context_entry *context;
+   unsigned long flags;
+
+   spin_lock_irqsave(&iommu->lock, flags);
+   root = &iommu->root_entry[bus];
+   context = get_context_addr_from_root(root);
+   if (context && context_present(context+devfn))
+   did = context_domain_id(context+devfn);
+   spin_unlock_irqrestore(&iommu->lock, flags);
+   return did;
+}
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * find_domain
  * Note: we use struct device->archdata.iommu stores the info
@@ -2375,6 +2396,9 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
unsigned long flags;
u8 bus, devfn;
int did = -1;   /* Default to "no domain_id supplied" */
+#ifdef CONFIG_CRASH_DUMP
+   struct domain_values_entry *dve = NULL;
+#endif /* CONFIG_CRASH_DUMP */
 
domain = find_domain(dev);
if (domain)
@@ -2408,6 +2432,24 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
+
+#ifdef CONFIG_CRASH_DUMP
+   if (intel_iommu_in_crashdump) {
+   /*
+* if this device had a did in the old kernel
+* use its values instead of generating new ones
+*/
+   did = device_to_domain_id(iommu, bus, devfn);
+   if (did > 0 || (did == 0 && !cap_caching_mode(iommu->cap)))
+   dve = intel_iommu_did_to_domain_values_entry(did,
+   iommu);
+   if (dve)
+   gaw = dve->gaw;
+   else
+   did = -1;
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
@@ -2419,6 +2461,18 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
return NULL;
}
 
+#ifdef CONFIG_CRASH_DUMP
+   if (intel_iommu_in_crashdump && dve) {
+
+   if (domain->pgd)
+   free_pgtable_page(domain->pgd);
+
+   domain->pgd = dve->pgd;
+
+   copy_reserved_iova(&dve->iovad, &domain->iovad);
+   }
+#endif /* CONFIG_CRASH_DUMP */
+
/* register PCI DMA alias device */
if (dev_is_pci(dev)) {
tmp = dmar_insert_dev_info(iommu, PCI_BUS_NUM(dma_alias),
@@ -2860,6 +2914,10 @@ static int __init init_dmars(void)
struct device *dev;
struct intel_iommu *iommu;
int i, ret;
+#ifdef CONFIG_CRASH_DUMP
+   struct root_entry *root_old_phys;
+   struct root_entry *root_new_virt;
+#endif /* CONFIG_CRASH_DUMP */
 
/*
 * for each drhd
@@ -2903,16 +2961,40 @@ static int __init init_dmars(void)
if (ret)
goto free_iommu;
 
-   /*
-* TBD:
-* we could share the same root & context tables
-* among all IOMMU's. Need to Split it later.
-*/
-   ret = iommu_alloc_root_entry(iommu);
-   if (ret) {
-   printk(KERN_ERR "IOMMU: allocate root entry failed\n");
-   goto free_iommu;
+#ifdef CONFIG_CRASH_DUMP
+   if (intel_iommu_in_crashdump) {
+   pr_info("IOMMU Copying translate tables from panicked 
kernel\n");
+   ret = intel_iommu_copy_translation_tables(drhd,
+   &root_old_phys, &root_new_virt,
+   g_num_of_iommus);
+   if (ret) {
+   

[PATCH 4/5] iommu/vt-d: Add domain-id functions

2014-10-21 Thread Li, Zhen-Hua
Interfaces for when a new domain in the crashdump kernel needs some
values from the panicked kernel's context entries.

Signed-off-by: Bill Sumner 
---
 drivers/iommu/intel-iommu.c | 46 +
 1 file changed, 46 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 73afed4..bde8f22 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -348,6 +348,7 @@ static inline int first_pte_in_page(struct dma_pte *pte)
 
 
 #ifdef CONFIG_CRASH_DUMP
+
 /*
  * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
  *
@@ -437,6 +438,16 @@ static int intel_iommu_copy_translation_tables(struct 
dmar_drhd_unit *drhd,
struct root_entry **root_new_virt_p,
int g_num_of_iommus);
 
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu);
+
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu);
+
 #endif /* CONFIG_CRASH_DUMP */
 
 /*
@@ -5230,4 +5241,39 @@ static int intel_iommu_copy_translation_tables(struct 
dmar_drhd_unit *drhd,
return 0;
 }
 
+/*
+ * Interfaces for when a new domain in the crashdump kernel needs some
+ * values from the panicked kernel's context entries
+ *
+ */
+static struct domain_values_entry *intel_iommu_did_to_domain_values_entry(
+   int did, struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link)
+   if (dve->did == did)
+   return dve;
+   return NULL;
+}
+
+/* Mark domain-id's from old kernel as in-use on this iommu so that a new
+ * domain-id is allocated in the case where there is a device in the new kernel
+ * that was not in the old kernel -- and therefore a new domain-id is needed.
+ */
+static int intel_iommu_get_dids_from_old_kernel(struct intel_iommu *iommu)
+{
+   struct domain_values_entry *dve;/* iterator */
+
+   pr_info("IOMMU:%d Domain ids from panicked kernel:\n", iommu->seq_id);
+
+   list_for_each_entry(dve, &domain_values_list[iommu->seq_id], link) {
+   set_bit(dve->did, iommu->domain_ids);
+   pr_info("DID did:%d(0x%4.4x)\n", dve->did, dve->did);
+   }
+
+   pr_info("\n");
+   return 0;
+}
+
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/5] iommu/vt-d: Items required for kdump

2014-10-21 Thread Li, Zhen-Hua
Add structure type domain_values_entry used for kdump;
Add context functions needed for kdump.

Bill Sumner:
Original version;

Li, Zhenhua:
Changed the name of new functions, make them consistent with current
context get/set functions.

Signed-off-by: Bill Sumner
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 69 +
 1 file changed, 69 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 1c7350d..99fe408 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -207,6 +207,15 @@ get_context_addr_from_root(struct root_entry *root)
NULL);
 }
 
+static inline struct context_entry *
+get_context_phys_from_root(struct root_entry *root)
+{
+   return (struct context_entry *)
+   (root_present(root) ? (void *) (root->val & VTD_PAGE_MASK)
+   : NULL);
+}
+
+
 /*
  * low 64 bits:
  * 0: present
@@ -227,6 +236,32 @@ static inline bool context_present(struct context_entry 
*context)
 {
return (context->lo & 1);
 }
+
+static inline int context_fault_enable(struct context_entry *c)
+{
+   return((c->lo >> 1) & 0x1);
+}
+
+static inline int context_translation_type(struct context_entry *c)
+{
+   return((c->lo >> 2) & 0x3);
+}
+
+static inline u64 context_address_root(struct context_entry *c)
+{
+   return((c->lo >> VTD_PAGE_SHIFT));
+}
+
+static inline int context_address_width(struct context_entry *c)
+{
+   return((c->hi >> 0) & 0x7);
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+   return((c->hi >> 8) & 0x);
+}
+
 static inline void context_set_present(struct context_entry *context)
 {
context->lo |= 1;
@@ -311,6 +346,40 @@ static inline int first_pte_in_page(struct dma_pte *pte)
return !((unsigned long)pte & ~VTD_PAGE_MASK);
 }
 
+
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * Fix Crashdump failure caused by leftover DMA through a hardware IOMMU
+ *
+ * Fixes the crashdump kernel to deal with an active iommu and legacy
+ * DMA from the (old) panicked kernel in a manner similar to how legacy
+ * DMA is handled when no hardware iommu was in use by the old kernel --
+ * allow the legacy DMA to continue into its current buffers.
+ *
+ * In the crashdump kernel, this code:
+ * 1. skips disabling the IOMMU's translating of IO Virtual Addresses (IOVA)
+ * 2. leaves the current translations in-place so that legacy DMA will
+ *continue to use its current buffers,
+ * 3. allocates to the device drivers in the crashdump kernel
+ *portions of the iova address ranges that are different
+ *from the iova address ranges that were being used by the old kernel
+ *at the time of the panic.
+ *
+ */
+
+struct domain_values_entry {
+   struct list_head link;  /* link entries into a list */
+   struct iova_domain iovad;   /* iova's that belong to this domain */
+   struct dma_pte  *pgd;   /* virtual address */
+   intdid; /* domain id */
+   intgaw; /* max guest address width */
+   intiommu_superpage; /* Level of superpages supported:
+  0 == 4KiB (no superpages), 1 == 2MiB,
+  2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
+};
+
+#endif /* CONFIG_CRASH_DUMP */
+
 /*
  * This domain is a statically identity mapping domain.
  * 1. This domain creats a static 1:1 mapping to all usable memory.
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/5] iommu/vt-d: Fix crash dump failure caused by legacy DMA/IO

2014-10-21 Thread Li, Zhen-Hua
The following series implements a fix for:
A kdump problem about DMA that has been discussed for a long time.
That is, when a kernel panics and boots into the kdump kernel, DMA that was
started by the panicked kernel is not stopped before the kdump kernel is booted;
and the kdump kernel disables the IOMMU while this DMA continues.
This causes the IOMMU to stop translating the DMA addresses as IOVAs and
begin to treat them as physical memory addresses -- which causes the DMA to 
either:
1. generate DMAR errors or
2. generate PCI SERR errors or
3. transfer data to or from incorrect areas of memory.
Often this causes the dump to fail.

This patch set modifies the behavior of the Intel iommu in the crashdump 
kernel: 
1. to accept the iommu hardware in an active state,
2. to leave the current translations in-place so that legacy DMA will continue
   using its current buffers until the device drivers in the crashdump kernel
   initialize and initialize their devices,
3. to use different portions of the iova address ranges for the device drivers
   in the crashdump kernel than the iova ranges that were in-use at the time
   of the panic.  

Advantages of this approach:
1. All manipulation of the IO-device is done by the Linux device-driver
   for that device.
2. This approach behaves in a manner very similar to operation without an
   active iommu.
3. Any activity between the IO-device and its RMRR areas is handled by the
   device-driver in the same manner as during a non-kdump boot.
4. If an IO-device has no driver in the kdump kernel, it is simply left alone.
   This supports the practice of creating a special kdump kernel without
   drivers for any devices that are not required for taking a crashdump. 
5. Minimal code-changes among the existing mainline intel-iommu code.

Summary of changes in this patch set:
1. Updated to a more current top-of-tree and merged the code with the
   large number of changes that were recently taken-in to intel-iommu.c
2. Returned to the structure of a patch-set
3. Enabled the intel-iommu driver to consist of multiple *.c files
   by moving many of the #defines, prototypes, and inline functions
   into a new file: intel-iommu-private.h (First three patches implement
   only this enhancement -- could be applied independent of the last 5)
4. Moved the new "crashdump fix" code into a new file: intel-iommu-kdump.c 
5. Removed the pr_debug constructs from the new code that implements the
   "crashdump fix" -- making the code much cleaner and easier to read.
6. Miscellaneous cleanups such as enum-values for return-codes.
7. Simplified the code that retrieves the values needed to initialize a new
   domain by using the linked-list of previously-collected values
   instead of stepping back into the tree of translation tables.

Original version by Bill Sumner:
https://lkml.org/lkml/2014/4/24/836

Changed in this version:
Split the original patchset into two sets. This patchset includes 
4~8 patches in the original set.

Bill Sumner (5):
  iommu/vt-d: Update iommu_attach_domain() and its callers
  iommu/vt-d: Items required for kdump
  iommu/vt-d: data types and functions used for kdump
  iommu/vt-d: Add domain-id functions
  iommu/vt-d: enable kdump support in iommu module

 drivers/iommu/intel-iommu.c | 829 ++--
 1 file changed, 803 insertions(+), 26 deletions(-)

-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/5] iommu/vt-d: Update iommu_attach_domain() and its callers

2014-10-21 Thread Li, Zhen-Hua
Allow specification of the domain-id for the new domain.
This patch only adds the 'did' parameter to iommu_attach_domain()
and modifies all of its callers to specify the default value of -1
which says "no did specified, allocate a new one".

This is no functional change from current behaviour -- just enables
a functional change to be made in a later patch.

Bill Sumner:
Original version.

Li, Zhenhua:
Minor change, add change to function __iommu_attach_domain.

Signed-off-by: Bill Sumner 
Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/intel-iommu.c | 32 +++-
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a27d6cb..1c7350d 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1531,31 +1531,36 @@ static struct dmar_domain *alloc_domain(int flags)
 }
 
 static int __iommu_attach_domain(struct dmar_domain *domain,
-struct intel_iommu *iommu)
+struct intel_iommu *iommu,
+int domain_number)
 {
int num;
unsigned long ndomains;
 
ndomains = cap_ndoms(iommu->cap);
-   num = find_first_zero_bit(iommu->domain_ids, ndomains);
-   if (num < ndomains) {
-   set_bit(num, iommu->domain_ids);
-   iommu->domains[num] = domain;
-   } else {
-   num = -ENOSPC;
-   }
+   if (domain_number < 0) {
+   num = find_first_zero_bit(iommu->domain_ids, ndomains);
+   if (num < ndomains) {
+   set_bit(num, iommu->domain_ids);
+   iommu->domains[num] = domain;
+   } else {
+   num = -ENOSPC;
+   }
+   } else
+   num = domain_number;
 
return num;
 }
 
 static int iommu_attach_domain(struct dmar_domain *domain,
-  struct intel_iommu *iommu)
+  struct intel_iommu *iommu,
+  int domain_number)
 {
int num;
unsigned long flags;
 
spin_lock_irqsave(&iommu->lock, flags);
-   num = __iommu_attach_domain(domain, iommu);
+   num = __iommu_attach_domain(domain, iommu, domain_number);
spin_unlock_irqrestore(&iommu->lock, flags);
if (num < 0)
pr_err("IOMMU: no free domain ids\n");
@@ -1574,7 +1579,7 @@ static int iommu_attach_vm_domain(struct dmar_domain 
*domain,
if (iommu->domains[num] == domain)
return num;
 
-   return __iommu_attach_domain(domain, iommu);
+   return __iommu_attach_domain(domain, iommu, -1);
 }
 
 static void iommu_detach_domain(struct dmar_domain *domain,
@@ -2230,6 +2235,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
u16 dma_alias;
unsigned long flags;
u8 bus, devfn;
+   int did = -1;   /* Default to "no domain_id supplied" */
 
domain = find_domain(dev);
if (domain)
@@ -2263,7 +2269,7 @@ static struct dmar_domain *get_domain_for_dev(struct 
device *dev, int gaw)
domain = alloc_domain(0);
if (!domain)
return NULL;
-   domain->id = iommu_attach_domain(domain, iommu);
+   domain->id = iommu_attach_domain(domain, iommu, did);
if (domain->id < 0) {
free_domain_mem(domain);
return NULL;
@@ -2441,7 +2447,7 @@ static int __init si_domain_init(int hw)
return -EFAULT;
 
for_each_active_iommu(iommu, drhd) {
-   ret = iommu_attach_domain(si_domain, iommu);
+   ret = iommu_attach_domain(si_domain, iommu, -1);
if (ret < 0) {
domain_exit(si_domain);
return -EFAULT;
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] pci: reset all pci endpoints to stop on going dma

2014-10-17 Thread Li, Zhen-Hua
This is an update of the patch
https://lkml.org/lkml/2014/10/10/37

This patch is doing the reset works before the kdump kernel boots.

On a Linux system with iommu supported and many PCI devices on it,
when kernel crashed and the kdump kernel boots with intel_iommu=on,
there may be some unexpected DMA requests on this adapter, which will
cause DMA Remapping faults like:
dmar: DRHD: handling fault status reg 102
dmar: DMAR:[DMA Read] Request device [41:00.0] fault addr fff81000
DMAR:[fault reason 01] Present bit in root entry is clear

This bug may happen on *any* PCI device.
Analysis for this bug:

The present bit is set in this function:

static struct context_entry * device_to_context_entry(
struct intel_iommu *iommu, u8 bus, u8 devfn)
{
..
set_root_present(root);
..
}

Calling tree:
device driver
intel_alloc_coherent
__intel_map_single
domain_context_mapping
domain_context_mapping_one
device_to_context_entry

This means, the present bit in root entry will not be set until the device
driver is loaded.

But in the kdump kernel, hardware devices are not aware that control has
transferred to the second kernel, and those drivers must initialize again.
Consequently there may be unexpected DMA requests from devices activity
initiated in the first kernel leading to the DMA Remapping errors in the
second kernel.

To fix this DMAR fault, we need to reset the bus that this device on. Reset
the device itself does not work.

A patch for this bug that has been sent before:
https://lkml.org/lkml/2014/9/30/55
As in discussion, this bug may happen on *any* device, so we need to reset
all pci devices.

There was an original version(Takao Indoh) that resets the pcie devices:
https://lkml.org/lkml/2013/5/14/9

According to the previous discussion, On sparc, the IOMMU is initialized
before PCI devices are enumerated, this patch does the resetting works before
the kdump kernel boots, so it can also fix the problems on sparc.

Update of this new version, comparing with Takao Indoh's version:
Add support for legacy PCI devices.
Use pci_try_reset_bus instead of do_downstream_device_reset.
Reset all PCI/PCIe deviecs in the first kernel, before kdump kernel boots.

Randy Wright corrects some misunderstanding in this description.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
Signed-off-by: Randy Wright 
---
 drivers/pci/pci.c   | 82 +
 include/linux/pci.h |  6 
 kernel/kexec.c  |  2 ++
 3 files changed, 90 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 625a4ac..aa9192a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "pci.h"
@@ -4466,6 +4467,87 @@ void __weak pci_fixup_cardbus(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_fixup_cardbus);
 
+/*
+ * Return true if dev is PCI root port or downstream port whose child is PCI
+ * endpoint except VGA device.
+ */
+static int __pci_dev_need_reset(struct pci_dev *dev)
+{
+   struct pci_bus *subordinate;
+   struct pci_dev *child;
+
+   if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+   return 0;
+
+   if (pci_is_pcie(dev)) {
+   if ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
+   (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM))
+   return 0;
+   }
+
+   subordinate = dev->subordinate;
+   list_for_each_entry(child, &subordinate->devices, bus_list) {
+   /* Don't reset switch, bridge, VGA device */
+   if ((child->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
+   ((child->class >> 16) == PCI_BASE_CLASS_BRIDGE) ||
+   ((child->class >> 16) == PCI_BASE_CLASS_DISPLAY))
+   return 0;
+
+   if (pci_is_pcie(child)) {
+   if ((pci_pcie_type(child) == PCI_EXP_TYPE_UPSTREAM) ||
+   (pci_pcie_type(child) == PCI_EXP_TYPE_PCI_BRIDGE))
+   return 0;
+   }
+   }
+
+   return 1;
+}
+
+struct pci_dev_reset_entry {
+   struct list_head list;
+   struct pci_dev *dev;
+};
+int pci_reset_endpoints(void)
+{
+   struct pci_dev *dev = NULL;
+   struct pci_dev_reset_entry *pdev_entry, *tmp;
+   struct pci_bus *subordinate = NULL;
+   int has_it;
+
+   LIST_HEAD(pdev_list);
+
+
+   for_each_pci_dev(dev) {
+   subordinate = dev->subordinate;
+   if (!subordinate || list_empty(&subordinate->devices))
+   continue;
+
+   has_it = 0;
+   list_for_each_entry(pdev_entry, &pdev_list, list) {
+   

[PATCH 1/1] pci: fix dmar fault for kdump kernel

2014-10-10 Thread Li, Zhen-Hua
On a HP system with Intel vt-d supported and many PCI devices on it, 
when kernel crashed and the kdump kernel boots with intel_iommu=on, 
there may be some unexpected DMA requests on this adapter, which will 
cause DMA Remapping faults like:
dmar: DRHD: handling fault status reg 102
dmar: DMAR:[DMA Read] Request device [41:00.0] fault addr fff81000
DMAR:[fault reason 01] Present bit in root entry is clear

This bug may happen on *any* PCI device.
Analysis for this bug:

The present bit is set in this function:

static struct context_entry * device_to_context_entry(
struct intel_iommu *iommu, u8 bus, u8 devfn)
{
..
set_root_present(root);
..
}

Calling tree:
device driver
intel_alloc_coherent
__intel_map_single
domain_context_mapping
domain_context_mapping_one
device_to_context_entry

This means, the present bit in root entry will not be set until the device 
driver is loaded.

But in the kdump kernel, hardware devices are not aware that control has 
transferred to the second kernel, and those drivers must initialize again. 
Consequently there may be unexpected DMA requests from devices activity
initiated in the first kernel leading to the DMA Remapping errors in the 
second kernel.

To fix this DMAR fault, we need to reset the bus that this device on. Reset 
the device itself does not work.

A patch for this bug that has been sent before:
https://lkml.org/lkml/2014/9/30/55
As in discussion, this bug may happen on *any* device, so we need to reset all 
pci devices.

There was an original version(Takao Indoh) that resets the pcie devices:
https://lkml.org/lkml/2013/5/14/9

Update of this new version, comparing with Takao Indoh's version:
Add support for legacy PCI devices.
Use pci_try_reset_bus instead of do_downstream_device_reset in original 
version

Randy Wright corrects some misunderstanding in this description.

Signed-off-by: Li, Zhen-Hua 
Signed-off-by: Takao Indoh 
Signed-off-by: Randy Wright 
---
 drivers/pci/pci.c | 84 +++
 1 file changed, 84 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..8cb146c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include "pci.h"
@@ -4423,6 +4424,89 @@ void __weak pci_fixup_cardbus(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_fixup_cardbus);
 
+/*
+ * Return true if dev is PCI root port or downstream port whose child is PCI
+ * endpoint except VGA device.
+ */
+static int __pci_dev_need_reset(struct pci_dev *dev)
+{
+   struct pci_bus *subordinate;
+   struct pci_dev *child;
+
+   if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+   return 0;
+
+   if (pci_is_pcie(dev)) {
+   if ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
+   (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM))
+   return 0;
+   }
+
+   subordinate = dev->subordinate;
+   list_for_each_entry(child, &subordinate->devices, bus_list) {
+   /* Don't reset switch, bridge, VGA device */
+   if ((child->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
+   ((child->class >> 16) == PCI_BASE_CLASS_BRIDGE) ||
+   ((child->class >> 16) == PCI_BASE_CLASS_DISPLAY))
+   return 0;
+
+   if (pci_is_pcie(child)) {
+   if ((pci_pcie_type(child) == PCI_EXP_TYPE_UPSTREAM) ||
+   (pci_pcie_type(child) == PCI_EXP_TYPE_PCI_BRIDGE))
+   return 0;
+   }
+   }
+
+   return 1;
+}
+
+struct pci_dev_reset_entry {
+   struct list_head list;
+   struct pci_dev *dev;
+};
+int __init pci_reset_endpoints(void)
+{
+   struct pci_dev *dev = NULL;
+   struct pci_dev_reset_entry *pdev_entry, *tmp;
+   struct pci_bus *subordinate = NULL;
+   int has_it;
+
+   LIST_HEAD(pdev_list);
+
+   if (likely(!is_kdump_kernel()))
+   return 0;
+
+   for_each_pci_dev(dev) {
+   subordinate = dev->subordinate;
+   if (!subordinate || list_empty(&subordinate->devices))
+   continue;
+
+   has_it = 0;
+   list_for_each_entry(pdev_entry, &pdev_list, list) {
+   if (dev == pdev_entry->dev) {
+   has_it = 1;
+   break;
+   }
+   }
+   if (has_it)
+   continue;
+
+   if (__pci_dev_need_reset(dev)) {
+   pdev_entry = kmalloc(sizeof(*pdev_entry), GFP_KERNEL);
+   pdev_e

[PATCH 1/1] pci/quirks: fix a dmar fault for intel 82599 card

2014-09-29 Thread Li, Zhen-Hua
On a HP system with Intel Corporation 82599 ethernet adapter, when kernel
crashed and the kdump kernel boots with intel_iommu=on, there may be some
unexpected DMA requests on this adapter, which will cause DMA Remapping
faults like:
dmar: DRHD: handling fault status reg 102
dmar: DMAR:[DMA Read] Request device [41:00.0] fault addr fff81000
DMAR:[fault reason 01] Present bit in root entry is clear

Analysis for this bug:

The present bit is set in this function:

static struct context_entry * device_to_context_entry(
struct intel_iommu *iommu, u8 bus, u8 devfn)
{
..
set_root_present(root);
..
}

Calling tree:
ixgbe_open
ixgbe_setup_tx_resources
intel_alloc_coherent
__intel_map_single
domain_context_mapping
domain_context_mapping_one
device_to_context_entry

This means, the present bit in root entry will not be set until the device
 driver is loaded.

But in the kdump kernel, some hardware device does not know the OS is the
 second kernel and the drivers should be loaded again, this causes there are
 some unexpected DMA requsts on this device when it has not been initialized,
 and then the DMA Remapping errors come.

To fix this DMAR fault, we need to reset the bus that this device on. Reset
 the device itself does not work.

There also was a discussion:
https://lkml.org/lkml/2013/5/14/9

Signed-off-by: Li, Zhen-Hua 
---
 drivers/pci/quirks.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 80c2d01..5198af3 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include/* isa_dma_bridge_buggy */
+#include 
 #include "pci.h"
 
 /*
@@ -3832,3 +3833,13 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
}
}
 }
+
+#ifdef CONFIG_CRASH_DUMP
+void quirk_reset_buggy_devices(struct pci_dev *dev)
+{
+   if (unlikely(is_kdump_kernel()))
+   pci_try_reset_bus(dev->bus);
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_INTEL, 0x10f8,
+   PCI_CLASS_NETWORK_ETHERNET, 8, quirk_reset_buggy_devices);
+#endif
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] driver/drx39xyj: fix some compiling warnings

2014-09-21 Thread Li, Zhen-Hua
When compiling kernel, in module drx39xyj, there are some warnings
showing some variables may be used uninitialized, though they have
 been initialized in fact.

drivers/media/dvb-frontends/drx39xyj/drxj.c: In function
 ‘drxj_dap_atomic_read_reg32.isra.17’:
drivers/media/dvb-frontends/drx39xyj/drxj.c:2190:7: warning:
 ‘*((void *)&buf+3)’ may be used uninitialized in this function
[-Wmaybe-uninitialized]
  word = (u32) buf[3];
   ^
drivers/media/dvb-frontends/drx39xyj/drxj.c:2192:10: warning:
 ‘*((void *)&buf+2)’ may be used uninitialized in this function
 [-Wmaybe-uninitialized]
  word |= (u32) buf[2];
  ^
drivers/media/dvb-frontends/drx39xyj/drxj.c:2194:10: warning:
 ‘*((void *)&buf+1)’ may be used uninitialized in this function
 [-Wmaybe-uninitialized]
  word |= (u32) buf[1];
  ^
drivers/media/dvb-frontends/drx39xyj/drxj.c:2196:10: warning:
 ‘buf’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  word |= (u32) buf[0];
  ^
drivers/media/dvb-frontends/drx39xyj/drxj.c: In function
 ‘drx39xxj_read_status’:
drivers/media/dvb-frontends/drx39xyj/drxj.c:10671:11: warning:
 ‘strength’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  u16 mer, strength;
   ^
drivers/media/dvb-frontends/drx39xyj/drxj.c: In function
 ‘drxj_dap_scu_atomic_read_reg16’:
drivers/media/dvb-frontends/drx39xyj/drxj.c:4208:9: warning:
 ‘*((void *)&buf+1)’ may be used uninitialized in this function
 [-Wmaybe-uninitialized]
  word = (u16) (buf[0] + (buf[1] << 8));
 ^
drivers/media/dvb-frontends/drx39xyj/drxj.c:4208:9: warning:
 ‘buf’ may be used uninitialized in this function [-Wmaybe-uninitialized]

Signed-off-by: Li, Zhen-Hua 
---
 drivers/media/dvb-frontends/drx39xyj/drxj.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c 
b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 7ca7a21..afb14c70 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -2181,6 +2181,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr 
*dev_addr,
if (!data)
return -EINVAL;
 
+   memset(buf, 0, sizeof(*data));
rc = drxj_dap_atomic_read_write_block(dev_addr, addr,
  sizeof(*data), buf, true);
 
@@ -4200,6 +4201,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr 
*dev_addr,
if (!data)
return -EINVAL;
 
+   memset(buf, 0, 2);
rc = drxj_dap_scu_atomic_read_write_block(dev_addr, addr, 2, buf, true);
if (rc < 0)
return rc;
@@ -10667,7 +10669,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod,
enum drx_standard standard = ext_attr->standard;
int rc;
u32 ber, cnt, err, pkt;
-   u16 mer, strength;
+   u16 mer, strength = 0;
 
rc = get_sig_strength(demod, &strength);
if (rc < 0) {
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] kdump: fix compiling error: undefined elfcorehdr_addr

2014-09-17 Thread Li, Zhen-Hua
While debugging the kdump kernel, I found there is a compiling error:
If is_kdump_kernel() is called in some driver(for example, add it in
debugging code in module qla2xxx), there will be a compiling error:

ERROR: "elfcorehdr_addr" [drivers/scsi/qla2xxx/qla2xxx.ko] undefined!

Add EXPORT_SYMBOL for elfcorehdr_addr will fix this.

Signed-off-by: Li, Zhen-Hua 
---
 kernel/crash_dump.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
index c766ee5..8cb4838 100644
--- a/kernel/crash_dump.c
+++ b/kernel/crash_dump.c
@@ -18,6 +18,7 @@ unsigned long saved_max_pfn;
  * it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
  */
 unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+EXPORT_SYMBOL(elfcorehdr_addr);
 
 /*
  * stores the size of elf header of crash image
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

2014-08-18 Thread Li, Zhen-Hua
My debugging result is this: 

1. Clear the old root entry table, dump kernel will choose another
 memory region for root entry.
2. Do NOT clear the old root entry, when dump kernel initializing 
the iommu data structure, it  will allocate memory for root entry, 
this is different from the old address. 

If not clear old entry , the error message appears before dump kernel
finishes the iommu init works, and also appears in other places(before 
device inits). 

If I clear the old root entry, the error message disappears before iommu
init work finish, but still appears in other places. 

-Original Message-
From: Li, Zhen-Hua 
Sent: Tuesday, August 19, 2014 7:48 AM
To: Li, Zhen-Hua; Joerg Roedel
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

When the dump kernel boots, it will initialize iommu again, and the root entry 
will be allocted 
in another memory region.

That means, no matter kernel clears the old root entry table or not,  the dump 
kernel will use 
another memory region when iommu initializing.

-Original Message-
From: Li, Zhen-Hua 
Sent: Tuesday, August 19, 2014 7:27 AM
To: 'Joerg Roedel'
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

: [fault reason 01] Present bit in root entry is clear
It appears when iommu initializing in the kdump kernel.

-Original Message-
From: Joerg Roedel [mailto:j...@8bytes.org] 
Sent: Tuesday, August 19, 2014 7:23 AM
To: Li, Zhen-Hua
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

On Mon, Aug 18, 2014 at 11:01:56PM +, Li, Zhen-Hua wrote:
> There is a bug when Linux running on an HP large system: 
>   when kdump kernel runs, the hardware is still using the old 
> root entry. This causes error message when iommu not finished initialization.

What error message are you seeing? When the kdump kernel boots the iommu
should be still enabled from the old kernel with the old root-entry. So
any in-flight DMA initiated from the old kernel can still pass and there
should be no error messages.

When you clear the root-entry that in-flight DMA might go to another
random location in system memory or just fail, no?


Joerg

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

2014-08-18 Thread Li, Zhen-Hua
When the dump kernel boots, it will initialize iommu again, and the root entry 
will be allocted 
in another memory region.

That means, no matter kernel clears the old root entry table or not,  the dump 
kernel will use 
another memory region when iommu initializing.

-Original Message-
From: Li, Zhen-Hua 
Sent: Tuesday, August 19, 2014 7:27 AM
To: 'Joerg Roedel'
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

: [fault reason 01] Present bit in root entry is clear
It appears when iommu initializing in the kdump kernel.

-Original Message-
From: Joerg Roedel [mailto:j...@8bytes.org] 
Sent: Tuesday, August 19, 2014 7:23 AM
To: Li, Zhen-Hua
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

On Mon, Aug 18, 2014 at 11:01:56PM +, Li, Zhen-Hua wrote:
> There is a bug when Linux running on an HP large system: 
>   when kdump kernel runs, the hardware is still using the old 
> root entry. This causes error message when iommu not finished initialization.

What error message are you seeing? When the kdump kernel boots the iommu
should be still enabled from the old kernel with the old root-entry. So
any in-flight DMA initiated from the old kernel can still pass and there
should be no error messages.

When you clear the root-entry that in-flight DMA might go to another
random location in system memory or just fail, no?


Joerg

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

2014-08-18 Thread Li, Zhen-Hua
: [fault reason 01] Present bit in root entry is clear
It appears when iommu initializing in the kdump kernel.

-Original Message-
From: Joerg Roedel [mailto:j...@8bytes.org] 
Sent: Tuesday, August 19, 2014 7:23 AM
To: Li, Zhen-Hua
Cc: David Woodhouse; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

On Mon, Aug 18, 2014 at 11:01:56PM +, Li, Zhen-Hua wrote:
> There is a bug when Linux running on an HP large system: 
>   when kdump kernel runs, the hardware is still using the old 
> root entry. This causes error message when iommu not finished initialization.

What error message are you seeing? When the kdump kernel boots the iommu
should be still enabled from the old kernel with the old root-entry. So
any in-flight DMA initiated from the old kernel can still pass and there
should be no error messages.

When you clear the root-entry that in-flight DMA might go to another
random location in system memory or just fail, no?


Joerg

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

2014-08-18 Thread Li, Zhen-Hua
There is a bug when Linux running on an HP large system: 
when kdump kernel runs, the hardware is still using the old 
root entry. This causes error message when iommu not finished initialization.

-Original Message-
From: Li, Zhen-Hua 
Sent: Monday, August 18, 2014 4:59 PM
To: David Woodhouse; Joerg Roedel; io...@lists.linux-foundation.org; 
linux-kernel@vger.kernel.org
Cc: Li, Zhen-Hua
Subject: [PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

If intel_iommu is enabled, when kdump kernel boots, the old root entry
 should be cleared, otherwise it may cause DMAR error.

To make it works for more enviroments, this patch does not use 
is_kdump_kernel() to check it,  but reads the register to check whether 
hardware is using old root entry.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/dmar.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 60ab474..7b4fa90 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -66,6 +66,8 @@ static int dmar_dev_scope_status = 1;
 static int alloc_iommu(struct dmar_drhd_unit *drhd);
 static void free_iommu(struct intel_iommu *iommu);
 
+static int iommu_check_root_entry(struct intel_iommu *iommu);
+
 static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 {
/*
@@ -987,6 +989,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
   intel_iommu_groups,
   iommu->name);
 
+   iommu_check_root_entry(iommu);
+
return 0;
 
  err_unmap:
@@ -1666,5 +1670,32 @@ static int __init dmar_free_unused_resources(void)
return 0;
 }
 
+static int iommu_check_root_entry(struct intel_iommu *iommu)
+{
+   u64 re_pa;
+
+   re_pa = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
+
+   /* This only works for hardware error and kdump kernel */
+   if (unlikely(re_pa != 0)) {
+   u32 sts;
+   unsigned long flag;
+
+   raw_spin_lock_irqsave(&iommu->register_lock, flag);
+   dmar_writeq(iommu->reg + DMAR_RTADDR_REG, 0);
+
+   writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
+
+   /* Make sure hardware complete it */
+   IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (sts & DMA_GSTS_RTPS), sts);
+
+   raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+   }
+
+   return 0;
+}
+
 late_initcall(dmar_free_unused_resources);
 IOMMU_INIT_POST(detect_intel_iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] iommu/vt-d : clear old root entry for dump kernel

2014-08-18 Thread Li, Zhen-Hua
If intel_iommu is enabled, when kdump kernel boots, the old root entry
 should be cleared, otherwise it may cause DMAR error.

To make it works for more enviroments, this patch does not use 
is_kdump_kernel() to check it,  but reads the register to check whether 
hardware is using old root entry.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/iommu/dmar.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 60ab474..7b4fa90 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -66,6 +66,8 @@ static int dmar_dev_scope_status = 1;
 static int alloc_iommu(struct dmar_drhd_unit *drhd);
 static void free_iommu(struct intel_iommu *iommu);
 
+static int iommu_check_root_entry(struct intel_iommu *iommu);
+
 static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 {
/*
@@ -987,6 +989,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
   intel_iommu_groups,
   iommu->name);
 
+   iommu_check_root_entry(iommu);
+
return 0;
 
  err_unmap:
@@ -1666,5 +1670,32 @@ static int __init dmar_free_unused_resources(void)
return 0;
 }
 
+static int iommu_check_root_entry(struct intel_iommu *iommu)
+{
+   u64 re_pa;
+
+   re_pa = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
+
+   /* This only works for hardware error and kdump kernel */
+   if (unlikely(re_pa != 0)) {
+   u32 sts;
+   unsigned long flag;
+
+   raw_spin_lock_irqsave(&iommu->register_lock, flag);
+   dmar_writeq(iommu->reg + DMAR_RTADDR_REG, 0);
+
+   writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
+
+   /* Make sure hardware complete it */
+   IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (sts & DMA_GSTS_RTPS), sts);
+
+   raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+   }
+
+   return 0;
+}
+
 late_initcall(dmar_free_unused_resources);
 IOMMU_INIT_POST(detect_intel_iommu);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] iommu/vt-d: Add new macros for invalidation event

2014-08-14 Thread Li, Zhen-Hua
According to intel's spec
Intel® Virtualization Technology for Directed I/O,
Revision: 1.3 , February 2011,
Chaper 10.4.25 to 10.4.28

There are four registers

IECTL_REG   0xa0Invalidation event control register
IEDATA_REG  0xa4Invalidation event data register
IEADDR_REG  0xa8Invalidation event address register
IEUADDR_REG 0xacInvalidation event upper address register

Through they are not used in kernel in the latest version, the defination
 should be added to kernel as well as other registers.

Signed-off-by: Li, Zhen-Hua 
---
 include/linux/intel-iommu.h | 4 
 1 file changed, 4 insertions(+)

diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a..15fafd5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -56,6 +56,10 @@
 #define DMAR_IQ_SHIFT  4   /* Invalidation queue head/tail shift */
 #define DMAR_IQA_REG   0x90/* Invalidation queue addr register */
 #define DMAR_ICS_REG   0x9c/* Invalidation complete status register */
+#define DMAR_IECTL_REG 0xa0/* Invalidation event control register */
+#define DMAR_IEDATA_REG0xa4/* Invalidation event data register */
+#define DMAR_IEADDR_REG0xa8/* Invalidation event address register 
*/
+#define DMAR_IEUADDR_REG 0xac  /* Invalidation event upper address register */
 #define DMAR_IRTA_REG  0xb8/* Interrupt remapping table addr register */
 
 #define OFFSET_STRIDE  (9)
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] driver/tty: Fix a warning in check_tty_count

2014-07-13 Thread Li, Zhen-Hua
When there are to many open/close on a tty device in the same time,
there may be a warning like:
  Warning: dev (ttyS0) tty->count(4) != #fd's(3) in tty_release_dev

That's because tty->count and files in tty->tty_files are not synchronized
in time.
So I add a lock to avoid this.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/tty/tty_io.c | 13 +
 include/linux/tty.h  |  1 +
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 3411071..9283fc2 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -297,6 +297,7 @@ static int check_tty_count(struct tty_struct *tty, const 
char *routine)
struct list_head *p;
int count = 0;
 
+   spin_lock(&tty->count_lock);
spin_lock(&tty_files_lock);
list_for_each(p, &tty->tty_files) {
count++;
@@ -310,8 +311,10 @@ static int check_tty_count(struct tty_struct *tty, const 
char *routine)
printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
"!= #fd's(%d) in %s\n",
   tty->name, tty->count, count, routine);
+   spin_unlock(&tty->count_lock);
return count;
}
+   spin_unlock(&tty->count_lock);
 #endif
return 0;
 }
@@ -1337,7 +1340,6 @@ int tty_standard_install(struct tty_driver *driver, 
struct tty_struct *tty)
return ret;
 
tty_driver_kref_get(driver);
-   tty->count++;
driver->ttys[tty->index] = tty;
return 0;
 }
@@ -1408,7 +1410,6 @@ static int tty_reopen(struct tty_struct *tty)
 
tty->link->count++;
}
-   tty->count++;
 
WARN_ON(!tty->ldisc);
 
@@ -1796,6 +1797,7 @@ int tty_release(struct inode *inode, struct file *filp)
 * We must *not* drop the tty_mutex until we ensure that a further
 * entry into tty_open can not pick up this tty.
 */
+   spin_lock(&tty->count_lock);
if (pty_master) {
if (--o_tty->count < 0) {
printk(KERN_WARNING "%s: bad pty slave count (%d) for 
%s\n",
@@ -1819,7 +1821,7 @@ int tty_release(struct inode *inode, struct file *filp)
 *something that needs to be handled for hangups.
 */
tty_del_file(filp);
-
+   spin_unlock(&tty->count_lock);
/*
 * Perform some housekeeping before deciding whether to return.
 *
@@ -2046,8 +2048,10 @@ retry_open:
retval = PTR_ERR(tty);
goto err_file;
}
-
+   spin_lock(&tty->count_lock);
+   tty->count++;
tty_add_file(tty, filp);
+   spin_unlock(&tty->count_lock);
 
check_tty_count(tty, __func__);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -3031,6 +3035,7 @@ void initialize_tty_struct(struct tty_struct *tty,
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->ctrl_lock);
+   spin_lock_init(&tty->count_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
 
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 1c3316a..2959300 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -284,6 +284,7 @@ struct tty_struct {
/* If the tty has a pending do_SAK, queue it here - akpm */
struct work_struct SAK_work;
struct tty_port *port;
+   spinlock_t count_lock;
 };
 
 /* Each of a tty's open files has private_data pointing to tty_file_private */
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] script/kconfig: remove a warning for menucofig

2014-06-30 Thread Li, Zhen-Hua
When malloc for jump, 
if (head && location) {
jump = xmalloc(sizeof(struct jump_key));

}
And here it is used:
if (head && location && menu == location)
jump->offset = strlen(r->s);


So I think when jump is used, it must not be NULL; then !=NULL is not needed.
-Original Message-
From: Heinrich Schuchardt [mailto:xypron.g...@gmx.de] 
Sent: Tuesday, July 01, 2014 1:03 AM
To: Li, Zhen-Hua; Yann E. MORIN; linux-kbu...@vger.kernel.org; 
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/1] script/kconfig: remove a warning for menucofig

On 30.06.2014 05:16, Li, Zhen-Hua wrote:
> There is a warning when run "make menuconfig".
>
> scripts/kconfig/menu.c: In function ‘get_symbol_str’:
> scripts/kconfig/menu.c:591:18: warning: ‘jump’ may be used uninitialized in
> this function [-Wmaybe-uninitialized]
>   jump->offset = strlen(r->s);
>^
> scripts/kconfig/menu.c:551:19: note: ‘jump’ was declared here
>struct jump_key *jump;
> ^
>
> It is because the compiler think "jump" is not initialized, though in fact
> it is already initialized.
>
> Signed-off-by: Li, Zhen-Hua 
> ---
>   scripts/kconfig/menu.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
> index a26cc5d..584e0fc 100644
> --- a/scripts/kconfig/menu.c
> +++ b/scripts/kconfig/menu.c
> @@ -548,7 +548,7 @@ static void get_prompt_str(struct gstr *r, struct 
> property *prop,
>   {
>   int i, j;
>   struct menu *submenu[8], *menu, *location = NULL;
> - struct jump_key *jump;
> + struct jump_key *jump = NULL;
>
>   str_printf(r, _("Prompt: %s\n"), _(prop->text));
>   menu = prop->menu->parent;
>
Hello Zhen-Hua,

the patch looks incomplete to me. A check
jump != NULL
should be added before accessing parts of structure jump_key.

Best regards

Heinrich Schuchardt


[PATCH 1/1] script/kconfig: remove a warning for menucofig

2014-06-29 Thread Li, Zhen-Hua
There is a warning when run "make menuconfig".

scripts/kconfig/menu.c: In function ‘get_symbol_str’:
scripts/kconfig/menu.c:591:18: warning: ‘jump’ may be used uninitialized in
this function [-Wmaybe-uninitialized]
 jump->offset = strlen(r->s);
  ^
scripts/kconfig/menu.c:551:19: note: ‘jump’ was declared here
  struct jump_key *jump;
   ^

It is because the compiler think "jump" is not initialized, though in fact
it is already initialized.

Signed-off-by: Li, Zhen-Hua 
---
 scripts/kconfig/menu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index a26cc5d..584e0fc 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -548,7 +548,7 @@ static void get_prompt_str(struct gstr *r, struct property 
*prop,
 {
int i, j;
struct menu *submenu[8], *menu, *location = NULL;
-   struct jump_key *jump;
+   struct jump_key *jump = NULL;
 
str_printf(r, _("Prompt: %s\n"), _(prop->text));
menu = prop->menu->parent;
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH 1/1] driver/md/block: Alloc space for member flush_rq

2014-05-28 Thread Li, Zhen-Hua
I tested it on 3.14-rc5.
I will checkout the latest kernel and test it on my system for this bug.

Thanks
Zhenhua

-Original Message-
From: Mike Snitzer [mailto:snit...@redhat.com] 
Sent: Wednesday, May 28, 2014 11:03 PM
To: Li, Zhen-Hua
Cc: linux-kernel@vger.kernel.org; Alasdair Kergon; dm-de...@redhat.com; Neil 
Brown; linux-r...@vger.kernel.org
Subject: Re: [PATCH 1/1] driver/md/block: Alloc space for member flush_rq

On Wed, May 28 2014 at  2:22am -0400,
Li, Zhen-Hua  wrote:

> This patch is trying to fix a kernel crash bug.
> 
> When kernel boots on a HP large system, it crashes.
> The reason is when blk_rq_init is called, the second parameter rq , which
> is a member as q->flush_rq, is NULL. Kernel does not allocate space for it.
> 
> This fix adds an alloc for flush_rq member when request_queue is created in
> struct mapped_device *alloc_dev(int minor);
> 
> Bug Details:
> Error message:
> 
> [   62.931942] BUG: unable to handle kernel NULL pointer dereference at (null)
> [   62.931949] IP: [] blk_rq_init+0x40/0x160^M
> [   62.931949] PGD 0 ^M
> [   62.931951] Oops: 0002 [#1] SMP

You didn't specify which kernel you're running.  But this was fixed for
v3.15-rc6 via linux.git commit 7982e90c3a5 ("block: fix q->flush_rq NULL
pointer crash on dm-mpath flush").  And then there was the follow-on fix
from linux.git commit 708f04d2ab ("block: free q->flush_rq in
blk_init_allocated_queue error paths")

So all this is to say: Nack to your patch, we've already fixed the issue
differently.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] driver/md/block: Alloc space for member flush_rq

2014-05-27 Thread Li, Zhen-Hua
This patch is trying to fix a kernel crash bug.

When kernel boots on a HP large system, it crashes.
The reason is when blk_rq_init is called, the second parameter rq , which
is a member as q->flush_rq, is NULL. Kernel does not allocate space for it.

This fix adds an alloc for flush_rq member when request_queue is created in
struct mapped_device *alloc_dev(int minor);

Bug Details:
Error message:

[   62.931942] BUG: unable to handle kernel NULL pointer dereference at (null)
[   62.931949] IP: [] blk_rq_init+0x40/0x160^M
[   62.931949] PGD 0 ^M
[   62.931951] Oops: 0002 [#1] SMP

[   62.932019] Call Trace:
[   62.932025]  [] blk_flush_complete_seq+0x2d8/0x300
[   62.932027]  [] blk_insert_flush+0x1e5/0x250
[   62.932029]  [] __elv_add_request+0x1d8/0x2d0
[   62.932031]  [] blk_flush_plug_list+0x140/0x230
[   62.932033]  [] blk_finish_plug+0x14/0x40
[   62.932041]  [] _xfs_buf_ioapply+0x2fc/0x3d0 [xfs]
[   62.932053]  [] ? xlog_bdstrat+0x1f/0x50 [xfs]
[   62.932061]  [] xfs_buf_iorequest+0x46/0x90 [xfs]
[   62.932071]  [] xlog_bdstrat+0x1f/0x50 [xfs]
[   62.932080]  [] xlog_sync+0x265/0x450 [xfs]
[   62.932090]  [] xlog_state_release_iclog+0x92/0xb0 [xfs]
[   62.932099]  [] _xfs_log_force+0x15a/0x290 [xfs]
[   62.932108]  [] xfs_log_force+0x26/0x80 [xfs]
[   62.932117]  [] xfs_log_worker+0x24/0x50 [xfs]
[   62.932122]  [] process_one_work+0x17b/0x460
[   62.932125]  [] worker_thread+0x11b/0x400
[   62.932126]  [] ? rescuer_thread+0x400/0x400
[   62.932130]  [] kthread+0xe1/0x100
[   62.932133]  [] ? kthread_create_on_node+0x1a0/0x1a0
[   62.932140]  [] ret_from_fork+0x7c/0xb0
[   62.932141]  [] ? kthread_create_on_node+0x1a0/0x1a0

Signed-off-by: Li, Zhen-Hua 
---
 drivers/md/dm.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 455e649..9ff6df6 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1893,6 +1893,10 @@ static struct mapped_device *alloc_dev(int minor)
if (!md->queue)
goto bad_queue;
 
+   md->queue->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
+   if (!md->queue->flush_rq)
+   goto bad_disk;
+
dm_init_md_queue(md);
 
md->disk = alloc_disk(1);
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] kvm: increase max vcpu count

2014-05-15 Thread Li, Zhen-Hua
This patch is trying to increase the maximum supported vcpu number.

There has been big system supporting more than 256 logical CPUs, and vmware
can also support guest system with more than logical 256 CPUs. So kvm should 
also increase the maximum supported cpu number.

This patch only includes kernel kvm's part. The qemu support will be another 
thread.

Signed-off-by: Li, Zhen-Hua 
---
 arch/x86/include/asm/kvm_host.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7de069af..92cc83c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -31,8 +31,8 @@
 #include 
 #include 
 
-#define KVM_MAX_VCPUS 255
-#define KVM_SOFT_MAX_VCPUS 160
+#define KVM_MAX_VCPUS 4096
+#define KVM_SOFT_MAX_VCPUS 4096
 #define KVM_USER_MEM_SLOTS 125
 /* memory slots that are not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 3
-- 
2.0.0-rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] net: Add rtnl_lock for netif_device_attach/detach

2014-04-16 Thread Li, Zhen-Hua
From: "Li, Zhen-Hua" 

As netif_running is called in netif_device_attach/detach. There should be
rtnl_lock/unlock called, to avoid dev stat change during netif_device_attach
and detach being called.
I checked NIC some drivers,  some of them have netif_device_attach/detach
called between rtnl_lock/unlock, while some drivers do not.

This patch is tring to find a generic way to fix this for all NIC drivers.

Signed-off-by: Li, Zhen-Hua 
---
 net/core/dev.c |   18 ++
 1 file changed, 18 insertions(+)

diff --git a/net/core/dev.c b/net/core/dev.c
index 5b3042e..795bbc5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2190,10 +2190,19 @@ EXPORT_SYMBOL(__dev_kfree_skb_any);
  */
 void netif_device_detach(struct net_device *dev)
 {
+   /**
+* As netif_running is called , rtnl_lock and unlock are needed to
+* avoid __LINK_STATE_START bit changes during this function call.
+*/
+   int need_unlock;
+
+   need_unlock = rtnl_trylock();
if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
netif_running(dev)) {
netif_tx_stop_all_queues(dev);
}
+   if (need_unlock)
+   rtnl_unlock();
 }
 EXPORT_SYMBOL(netif_device_detach);
 
@@ -2205,11 +2214,20 @@ EXPORT_SYMBOL(netif_device_detach);
  */
 void netif_device_attach(struct net_device *dev)
 {
+   /**
+* As netif_running is called , rtnl_lock and unlock are needed to
+* avoid __LINK_STATE_START bit changes during this function call.
+*/
+   int need_unlock;
+
+   need_unlock = rtnl_trylock();
if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
netif_running(dev)) {
netif_tx_wake_all_queues(dev);
__netdev_watchdog_up(dev);
}
+   if (need_unlock)
+   rtnl_unlock();
 }
 EXPORT_SYMBOL(netif_device_attach);
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/1] driver/net: add missing rtnl lock/unlock for benet

2014-04-15 Thread Li, Zhen-Hua
Yes, that's ok for me.

发自我的 iPhone

在 2014年4月15日,下午7:57,"Sathya Perla"  写道:

>> -Original Message-
>> From: Li, ZhenHua [mailto:zhen-h...@hp.com]
>> 
>> Because netif_running() is called in netif_device_detach and
>> netif_device_attach. To avoid dev status changed while
>> netif_device_detach/attach is not finished, I think a rtnl_lock and
>> unlock should be called to avoid this.
> 
> Ok. I'd like to then factor the code slightly differently by using
> routines like this:
> 
> be_close_sync() {
>rtnl_lock();
> 
>  netif_device_detach(netdev);
>   if (netif_running(netdev))
>   be_close(netdev);
> 
>rtnl_unlock();
> }
> 
> and similarly for be_open_sync()
> 
> And, I'd need some time to test these flows too.
> Would you be OK with this?
> 
> thanks,
> -Sathya


[PATCH 1/1] driver/net: add missing rtnl lock/unlock for benet

2014-04-14 Thread Li, Zhen-Hua
From: "Li, Zhen-Hua" 

In benet driver, netif_device_detach and netif_device_attach should be
called between rtnl_lock and rtnl_unlock.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/net/ethernet/emulex/benet/be_main.c |   17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/emulex/benet/be_main.c 
b/drivers/net/ethernet/emulex/benet/be_main.c
index 3e6df47..9c44b3f 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4555,8 +4555,11 @@ static void be_func_recovery_task(struct work_struct 
*work)
rtnl_unlock();
 
status = lancer_recover_func(adapter);
-   if (!status)
+   if (!status) {
+   rtnl_lock();
netif_device_attach(adapter->netdev);
+   rtnl_unlock();
+   }
}
 
/* In Lancer, for all errors other than provisioning error (-EAGAIN),
@@ -4784,12 +4787,12 @@ static int be_suspend(struct pci_dev *pdev, 
pm_message_t state)
be_intr_set(adapter, false);
cancel_delayed_work_sync(&adapter->func_recovery_work);
 
+   rtnl_lock();
netif_device_detach(netdev);
if (netif_running(netdev)) {
-   rtnl_lock();
be_close(netdev);
-   rtnl_unlock();
}
+   rtnl_unlock();
be_clear(adapter);
 
pci_save_state(pdev);
@@ -4804,7 +4807,9 @@ static int be_resume(struct pci_dev *pdev)
struct be_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev =  adapter->netdev;
 
+   rtnl_lock();
netif_device_detach(netdev);
+   rtnl_unlock();
 
status = pci_enable_device(pdev);
if (status)
@@ -4832,7 +4837,9 @@ static int be_resume(struct pci_dev *pdev)
 
schedule_delayed_work(&adapter->func_recovery_work,
  msecs_to_jiffies(1000));
+   rtnl_lock();
netif_device_attach(netdev);
+   rtnl_unlock();
 
if (adapter->wol_en)
be_setup_wol(adapter, false);
@@ -4853,7 +4860,9 @@ static void be_shutdown(struct pci_dev *pdev)
cancel_delayed_work_sync(&adapter->work);
cancel_delayed_work_sync(&adapter->func_recovery_work);
 
+   rtnl_lock();
netif_device_detach(adapter->netdev);
+   rtnl_unlock();
 
be_cmd_reset_function(adapter);
 
@@ -4957,7 +4966,9 @@ static void be_eeh_resume(struct pci_dev *pdev)
 
schedule_delayed_work(&adapter->func_recovery_work,
  msecs_to_jiffies(1000));
+   rtnl_lock();
netif_device_attach(netdev);
+   rtnl_unlock();
return;
 err:
dev_err(&adapter->pdev->dev, "EEH resume failed\n");
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] driver/net: cosa driver uses udelay incorrectly

2014-04-14 Thread Li, Zhen-Hua
From: "Li, Zhen-Hua" 

In cosa driver, udelay with more than 2 may cause __bad_udelay.
Use msleep for instead.

Signed-off-by: Li, Zhen-Hua 
---
 drivers/net/wan/cosa.c |4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 84734a8..83c39e2 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1521,11 +1521,7 @@ static int cosa_reset_and_read_id(struct cosa_data 
*cosa, char *idstring)
cosa_putstatus(cosa, 0);
cosa_getdata8(cosa);
cosa_putstatus(cosa, SR_RST);
-#ifdef MODULE
msleep(500);
-#else
-   udelay(5*10);
-#endif
/* Disable all IRQs from the card */
cosa_putstatus(cosa, 0);
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/1] driver/net: remove unused code in cosa module

2014-04-14 Thread Li, Zhen-Hua
From: "Li, Zhen-Hua" 

For the cosa module, CONFIG_COSA can only be checked as 'm',
and cosa module can only be compiled as a module.

So remove unused code in cosa.c

Signed-off-by: Li, Zhen-Hua 
---
 drivers/net/wan/cosa.c |4 
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 84734a8..83c39e2 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1521,11 +1521,7 @@ static int cosa_reset_and_read_id(struct cosa_data 
*cosa, char *idstring)
cosa_putstatus(cosa, 0);
cosa_getdata8(cosa);
cosa_putstatus(cosa, SR_RST);
-#ifdef MODULE
msleep(500);
-#else
-   udelay(5*10);
-#endif
/* Disable all IRQs from the card */
cosa_putstatus(cosa, 0);
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   >