[PATCH 1/2] resource: add devm_request_mem_region_ram() for reserving RAM regions

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

 



Early x86 code reserves a buffer called "RAM buffer" to prevent MMIO
reservations from landing on top of potential RAM space, which can fail
due to decode priority in the chipset.

However, some drivers need to reserve RAM regions that may overlap the
padding, and may not be described in the E820 map (like the i915
driver).  So add a new entry point to allow this, that will shrink the
"RAM buffer" padding if needed.

Signed-off-by: Jesse Barnes <jbarnes@xxxxxxxxxxxxxxxx>
---
 include/linux/ioport.h |    6 ++++
 kernel/resource.c      |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 89b7c24..f44a4ad 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -209,11 +209,17 @@ struct device;
 	__devm_request_region(dev, &ioport_resource, (start), (n), (name))
 #define devm_request_mem_region(dev,start,n,name) \
 	__devm_request_region(dev, &iomem_resource, (start), (n), (name))
+#define devm_request_mem_region_ram(dev,start,n,name) \
+	__devm_request_region_ram(dev, &iomem_resource, (start), (n), (name))
 
 extern struct resource * __devm_request_region(struct device *dev,
 				struct resource *parent, resource_size_t start,
 				resource_size_t n, const char *name);
 
+extern struct resource * __devm_request_region_ram(struct device *dev,
+				struct resource *parent, resource_size_t start,
+				resource_size_t n, const char *name);
+
 #define devm_release_region(dev, start, n) \
 	__devm_release_region(dev, &ioport_resource, (start), (n))
 #define devm_release_mem_region(dev, start, n) \
diff --git a/kernel/resource.c b/kernel/resource.c
index 3f285dc..d8f8783 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1216,6 +1216,81 @@ struct resource * __devm_request_region(struct device *dev,
 }
 EXPORT_SYMBOL(__devm_request_region);
 
+/* Same as above, but conflicts with "RAM buffer" are ok */
+struct resource * __devm_request_region_ram(struct device *dev,
+				struct resource *parent, resource_size_t start,
+				resource_size_t n, const char *name)
+{
+	struct region_devres *dr = NULL;
+	struct resource *res;
+
+	dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
+			  GFP_KERNEL);
+	if (!dr)
+		return NULL;
+
+	dr->parent = parent;
+	dr->start = start;
+	dr->n = n;
+
+	res = __request_region(parent, start, n, name, 0);
+	if (res) {
+		goto out;
+	} else {
+		struct resource *conflict;
+
+		res = alloc_resource(GFP_ATOMIC);
+		if (!res)
+			goto fail;
+
+		res->name = name;
+		res->start = start;
+		res->end = start + n;
+		res->flags = IORESOURCE_BUSY;
+
+		conflict = request_resource_conflict(parent, res);
+		if (!conflict)
+			goto out;
+
+		if (strcmp(conflict->name, "RAM buffer"))
+			goto fail_free;
+
+		if (conflict->start <= res->start &&
+		    conflict->end <= res->end) {
+			resource_size_t new_size;
+
+			new_size = res->start - conflict->start;
+			adjust_resource(conflict, conflict->start, new_size);
+		} else if (conflict->start >= res->start &&
+			   conflict->end >= res->end) {
+			resource_size_t new_size;
+
+			new_size = conflict->end - res->end;
+			adjust_resource(conflict, res->start, new_size);
+		}
+
+		conflict = request_resource_conflict(parent, res);
+		if (!conflict)
+			goto out;
+		else {
+			dev_err("failed to adjust RAM buffer for %s\n",
+				res->name);
+			goto fail_free;
+		}
+	}
+
+out:
+	devres_add(dev, dr);
+	return res;
+
+fail_free:
+	free_resource(res);
+fail:
+	devres_free(dr);
+	return res;
+}
+EXPORT_SYMBOL(__devm_request_region_ram);
+
 void __devm_release_region(struct device *dev, struct resource *parent,
 			   resource_size_t start, resource_size_t n)
 {
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux