Re: [PATCH] Reserve memory for IOMMU registers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



John,

Could you refresh this patch, since the file has changed locations,
and make some repairs based on feedback below?
attached a patch that could be possible update...

- Don

On 07/28/2011 05:13 PM, jharg93@xxxxxxxxx wrote:
The DMAR driver currently doesn't reserve the memory used for the IOMMU
registers.  On one specific combination of cards on our system, the kernel
pci resource allocator was assigning a BAR to the same address as the IOMMU.
When the other driver did an ioremap, suddenly the IOMMU registers were no
longer valid.

Signed-off-by: Jordan Hargrave<Jordan_Hargrave@xxxxxxxx>
---
  drivers/pci/dmar.c |    9 +++++++++
  1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 12e02bf..9650b9b 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -750,6 +750,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
  	iommu->seq_id = iommu_allocated++;
  	sprintf (iommu->name, "dmar%d", iommu->seq_id);

+	if (!request_mem_region(drhd->reg_base_addr, VTD_PAGE_SIZE, iommu->name)) {
+	  	printk(KERN_ERR "IOMMU: can't reserve memory\n");
+		goto error;
+	}
  	iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
  	if (!iommu->reg) {
  		printk(KERN_ERR "IOMMU: can't map the region\n");
probably want to introduce an err_release: at bottom of function that
does release_mem_region(), and set map_size to VTD_PAGE_SIZE here,
so it can be used in both ioremap() error checks in this function.

@@ -789,7 +793,12 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
  		cap_max_fault_reg_offset(iommu->cap));
  	map_size = VTD_PAGE_ALIGN(map_size);
  	if (map_size>  VTD_PAGE_SIZE) {
+		release_mem_region(drhd->reg_base_addr, VTD_PAGE_SIZE);
need to do release after iounmap() below, not before it.

  		iounmap(iommu->reg);
+		if (!request_mem_region(drhd->reg_base_addr, map_size, iommu->name)) {
+			printk(KERN_ERR "IOMMU: can't reserve memory\n");
+			goto error;
+		}
  		iommu->reg = ioremap(drhd->reg_base_addr, map_size);
  		if (!iommu->reg) {
  			printk(KERN_ERR "IOMMU: can't map the region\n");
this is where you need an err_release goto as well

--- drivers/iommu/dmar.c.orig	2011-09-12 14:51:11.815394493 -0400
+++ drivers/iommu/dmar.c	2011-09-12 14:58:13.994299472 -0400
@@ -745,10 +745,16 @@ int alloc_iommu(struct dmar_drhd_unit *d
 	iommu->seq_id = iommu_allocated++;
 	sprintf (iommu->name, "dmar%d", iommu->seq_id);
 
-	iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
+	map_size = VTD_PAGE_SIZE;
+	if (!request_mem_region(drhd->reg_base_addr, map_size, iommu->name)) {
+	  	printk(KERN_ERR "IOMMU: can't reserve memory\n");
+		goto error;
+	}
+
+	iommu->reg = ioremap(drhd->reg_base_addr, map_size);
 	if (!iommu->reg) {
 		printk(KERN_ERR "IOMMU: can't map the region\n");
-		goto error;
+		goto err_release;
 	}
 	iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
 	iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
@@ -785,10 +791,15 @@ int alloc_iommu(struct dmar_drhd_unit *d
 	map_size = VTD_PAGE_ALIGN(map_size);
 	if (map_size > VTD_PAGE_SIZE) {
 		iounmap(iommu->reg);
+		release_mem_region(drhd->reg_base_addr, VTD_PAGE_SIZE);
+		if (!request_mem_region(drhd->reg_base_addr, map_size, iommu->name)) {
+	  		printk(KERN_ERR "IOMMU: can't reserve memory\n");
+			goto error;
+		}
 		iommu->reg = ioremap(drhd->reg_base_addr, map_size);
 		if (!iommu->reg) {
 			printk(KERN_ERR "IOMMU: can't map the region\n");
-			goto error;
+			goto err_release;
 		}
 	}
 
@@ -807,6 +818,8 @@ int alloc_iommu(struct dmar_drhd_unit *d
 
  err_unmap:
 	iounmap(iommu->reg);
+ err_release:
+	release_mem_region(drhd->reg_base_addr, map_size);
  error:
 	kfree(iommu);
 	return -1;

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux