Skip to contentSkip to conversation

pnp: add PNP resource range checking function

PATCH In review Jesse Barnes 2 participants 5 messages Apr 14, 2009 – Apr 21, 2009

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pnp: add PNP resource range checking function

This patch adds a new export from the ACPI PNP core, is_acpi_pnp_reserved, which is intended for use by drivers to check whether a given range is already reserved (and therefore likely safe to use) or not (indicating that new resource space should probably be allocated).

If it looks reasonable, there's code in arch/x86/pci that could probably be moved over to this as well.

drivers/pnp/pnpacpi/core.c +35 -0
index 2834846..810feff 100644
@@ -27,6 +27,94 @@
 #include "../base.h"
 #include "pnpacpi.h"
 
+/*
+ * Check the given resource against our test range
+ */
+static acpi_status check_pnp_resource(struct acpi_resource *res,
+				      void *data)
+{
+	struct resource *test_res = data;
+	struct acpi_resource_address64 address;
+	acpi_status status;
+
+	if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
+		struct acpi_resource_fixed_memory32 *fixmem32 =
+			&res->data.fixed_memory32;
+		if (!fixmem32)
+			return AE_OK;
+
+		if ((test_res->start >= fixmem32->address) &&
+		    (test_res->end < (fixmem32->address +
+				      fixmem32->address_length))) {
+			test_res->flags = 1;
+			return AE_CTRL_TERMINATE;
+		}
+	}
+	if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
+	    (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
+		return AE_OK;
+
+	status = acpi_resource_to_address64(res, &address);
+	if (ACPI_FAILURE(status) ||
+	   (address.address_length <= 0) ||
+	   (address.resource_type != ACPI_MEMORY_RANGE))
+		return AE_OK;
+
+	if ((test_res->start >= address.minimum) &&
+	    (test_res->end < (address.minimum +

address.address_length))) {
+ test_res->flags = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+/*
+ * Walk the current resource settings and check status
+ */
+static acpi_status find_pnp_resource(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ struct resource *res = context;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS,
+ check_pnp_resource, context);
+
+ if (res->flags)
+ return AE_CTRL_TERMINATE;
+
+ return AE_OK;
+}
+
+/**
+ * is_acpi_pnp_reserved - check whether a given range is reserved
+ * @start: start of range
+ * @end: end of range
+ *
+ * Check the given range (specified by @start and @end) against the current
+ * PNP resource settings.
+ *
+ * RETURNS:
+ * Zero if the range is not currently reserved.
+ * Nonzero if the range is reserved.
+ */
+int is_acpi_pnp_reserved(u64 start, u64 end)
+{
+ struct resource res;
+
+ res.start = start;
+ res.end = end;
+ res.flags = 0;
+
+ acpi_get_devices("PNP0C01", find_pnp_resource, &res, NULL);
+
+ if (!res.flags)
+ acpi_get_devices("PNP0C02", find_pnp_resource, &res,
+ NULL);
+
+ return res.flags;
+}
+EXPORT_SYMBOL(is_acpi_pnp_reserved);
+
static int num = 0;

/* We need only to blacklist devices that have already an acpi driver
that diff --git a/include/linux/pnp.h b/include/linux/pnp.h index ca3c887..2bc9cfc 100644

include/linux/pnp.h +1 -0
@@ -446,6 +446,7 @@ int pnp_start_dev(struct pnp_dev *dev);
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
+int is_acpi_pnp_reserved(u64 start, u64 end);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev *dev);
@@ -476,6 +477,7 @@ static inline int pnp_start_dev(struct pnp_dev

*dev) { return -ENODEV; } static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int is_acpi_pnp_reserved(u64 start, u64 end) { return FALSE; }
/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }

#1 lore raw

PATCH 1/1 i915: enable MCHBAR if needed

Using the new PNP resource checking code, this patch allows the i915 driver to allocate MCHBAR space if needed and use the BAR to determine current memory settings.

Testing & feedback welcome.

drivers/gpu/drm/i915/i915_drv.h +2 -0
index e9de2c2..d34fad9 100644
@@ -143,6 +143,8 @@ typedef struct drm_i915_private {
 	drm_local_map_t hws_map;
 	struct drm_gem_object *hws_obj;
 
+	struct resource mch_res;
+
 	unsigned int cpp;
 	int back_offset;
 	int front_offset;
drivers/gpu/drm/i915/i915_gem_tiling.c +145 -0

175 lines not on this page · raw message

#2 lore raw
In reply to Jesse Barnes
Quoted 5 lines · Jesse Barnes

This patch adds a new export from the ACPI PNP core, is_acpi_pnp_reserved, which is intended for use by drivers to check whether a given range is already reserved (and therefore likely safe to use) or not (indicating that new resource space should probably be allocated).

This doesn't really need to be ACPI-specific, does it? And can't you use the pre-parsed resources in pnp_dev->resources? And wouldn't you just look at all resources for all PNP devices, not just the PNP0C01/2 ones?

Sorry I don't have time to code up an example right now; maybe next week, though, if you remind me :-)

Bjorn

Quoted 127 lines

If it looks reasonable, there's code in arch/x86/pci that could probably be moved over to this as well.

drivers/pnp/pnpacpi/core.c +64 -0
index 2834846..810feff 100644
@@ -27,6 +27,94 @@
 #include "../base.h"
 #include "pnpacpi.h"
 
+/*
+ * Check the given resource against our test range
+ */
+static acpi_status check_pnp_resource(struct acpi_resource *res,
+				      void *data)
+{
+	struct resource *test_res = data;
+	struct acpi_resource_address64 address;
+	acpi_status status;
+
+	if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
+		struct acpi_resource_fixed_memory32 *fixmem32 =
+			&res->data.fixed_memory32;
+		if (!fixmem32)
+			return AE_OK;
+
+		if ((test_res->start >= fixmem32->address) &&
+		    (test_res->end < (fixmem32->address +
+				      fixmem32->address_length))) {
+			test_res->flags = 1;
+			return AE_CTRL_TERMINATE;
+		}
+	}
+	if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
+	    (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
+		return AE_OK;
+
+	status = acpi_resource_to_address64(res, &address);
+	if (ACPI_FAILURE(status) ||
+	   (address.address_length <= 0) ||
+	   (address.resource_type != ACPI_MEMORY_RANGE))
+		return AE_OK;
+
+	if ((test_res->start >= address.minimum) &&
+	    (test_res->end < (address.minimum +
 address.address_length))) {
+		test_res->flags = 1;
+		return AE_CTRL_TERMINATE;
+	}
+	return AE_OK;
+}
+
+/*
+ * Walk the current resource settings and check status
+ */
+static acpi_status find_pnp_resource(acpi_handle handle, u32 lvl,
+				     void *context, void **rv)
+{
+	struct resource *res = context;
+
+	acpi_walk_resources(handle, METHOD_NAME__CRS,
+			    check_pnp_resource, context);
+
+	if (res->flags)
+		return AE_CTRL_TERMINATE;
+
+	return AE_OK;
+}
+
+/**
+ * is_acpi_pnp_reserved - check whether a given range is reserved
+ * @start: start of range
+ * @end: end of range
+ *
+ * Check the given range (specified by @start and @end) against the

current
+ * PNP resource settings.
+ *
+ * RETURNS:
+ * Zero if the range is not currently reserved.
+ * Nonzero if the range is reserved.
+ */

drivers/pnp/pnpacpi/core.c +18 -0
+int is_acpi_pnp_reserved(u64 start, u64 end)
+{
+	struct resource res;
+
+	res.start = start;
+	res.end = end;
+	res.flags = 0;
+
+	acpi_get_devices("PNP0C01", find_pnp_resource, &res, NULL);
+
+	if (!res.flags)
+		acpi_get_devices("PNP0C02", find_pnp_resource, &res,
+				 NULL);
+
+	return res.flags;
+}
+EXPORT_SYMBOL(is_acpi_pnp_reserved);
+
 static int num = 0;
 
 /* We need only to blacklist devices that have already an acpi driver

that diff --git a/include/linux/pnp.h b/include/linux/pnp.h index ca3c887..2bc9cfc 100644

include/linux/pnp.h +1 -0
@@ -446,6 +446,7 @@ int pnp_start_dev(struct pnp_dev *dev);
 int pnp_stop_dev(struct pnp_dev *dev);
 int pnp_activate_dev(struct pnp_dev *dev);
 int pnp_disable_dev(struct pnp_dev *dev);
+int is_acpi_pnp_reserved(u64 start, u64 end);
 
 /* protocol helpers */
 int pnp_is_active(struct pnp_dev *dev);
@@ -476,6 +477,7 @@ static inline int pnp_start_dev(struct pnp_dev
 *dev) { return -ENODEV; } static inline int pnp_stop_dev(struct pnp_dev
 *dev) { return -ENODEV; } static inline int pnp_activate_dev(struct

pnp_dev *dev) { return -ENODEV; } static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int is_acpi_pnp_reserved(u64 start, u64 end) { return FALSE; }
/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }

#3 lore raw
Quoted 7 lines · On Tue, 14 Apr 2009 16:53:11 -0600 Bjorn Helgaas <[email protected]> wrote:
Quoted 5 lines · Jesse Barnes

This patch adds a new export from the ACPI PNP core, is_acpi_pnp_reserved, which is intended for use by drivers to check whether a given range is already reserved (and therefore likely safe to use) or not (indicating that new resource space should probably be allocated).

Quoted 7 lines

This doesn't really need to be ACPI-specific, does it? And can't you use the pre-parsed resources in pnp_dev->resources? And wouldn't you just look at all resources for all PNP devices, not just the PNP0C01/2 ones?

Sorry I don't have time to code up an example right now; maybe next week, though, if you remind me :-)

Sure, that all sounds reasonable... I'll try to remind you. :)

Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
#4 lore raw
Quoted 15 lines · Jesse Barnes
Quoted 12 lines · On Tue, 14 Apr 2009 16:53:11 -0600 Bjorn Helgaas <[email protected]> wrote:
Quoted 5 lines · Jesse Barnes

This patch adds a new export from the ACPI PNP core, is_acpi_pnp_reserved, which is intended for use by drivers to check whether a given range is already reserved (and therefore likely safe to use) or not (indicating that new resource space should probably be allocated).

This doesn't really need to be ACPI-specific, does it? And can't you use the pre-parsed resources in pnp_dev->resources? And wouldn't you just look at all resources for all PNP devices, not just the PNP0C01/2 ones?

Quoted 4 lines
Quoted 2 lines

Sorry I don't have time to code up an example right now; maybe next week, though, if you remind me :-)

Sure, that all sounds reasonable... I'll try to remind you. :)

Here's the sort of thing I was thinking (untested).

---
 drivers/pnp/resource.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
drivers/pnp/resource.c +17 -0
index f604061..6665562 100644
@@ -638,6 +638,23 @@ int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
 }
 EXPORT_SYMBOL(pnp_possible_config);
 
+int pnp_range_reserved(resource_size_t start, resource_size_t end)
+{
+	struct pnp_dev *dev;
+	struct pnp_resource *pnp_res;
+	resource_size_t *dev_start, *dev_end;
+
+	pnp_for_each_dev(dev) {
+		list_for_each_entry(pnp_res, &dev->resources, list) {
+			dev_start = &pnp_res->res.start;
+			dev_end   = &pnp_res->res.end;
+			if (ranged_conflict(&start, &end, dev_start, dev_end))
+				return 1;
+		}
+	}
+	return 0;
+}
+
 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
 static int __init pnp_setup_reserve_irq(char *str)
 {