linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Yinghai Lu <yinghai@kernel.org>
To: Jesse Barnes <jbarnes@virtuousgeek.org>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	Tony Luck <tony.luck@intel.com>,
	David Miller <davem@davemloft.net>, x86 <x86@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
	Dominik Brodowski <linux@dominikbrodowski.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arch@vger.kernel.org, Yinghai Lu <yinghai@kernel.org>
Subject: [PATCH -v11 17/30] resources: Add probe_resource()
Date: Sun, 18 Mar 2012 22:42:48 -0700	[thread overview]
Message-ID: <1332135781-13695-18-git-send-email-yinghai@kernel.org> (raw)
In-Reply-To: <1332135781-13695-1-git-send-email-yinghai@kernel.org>

It is changed from busn_res only version, because Bjorn found that version
was not holding resource_lock.
Even it may be ok for busn_res not holding resource_lock.
It would be better to have it to be generic and use lock and we would
use it for other resources.

probe_resource() will try to find specified size or more in parent bus.
If can not find current parent resource, and it will try to expand parents
top.
If still can not find that specified on top, it will try to reduce target size
until find one.

It will return 0, if it find any resource that it could use.

Returned resource already register in the tree.

So caller may still need call resource_replace to put real resource in
the tree.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
---
 include/linux/ioport.h |    7 ++
 kernel/resource.c      |  160 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 162 insertions(+), 5 deletions(-)

diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index e885ba2..20a30df 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -156,6 +156,13 @@ extern int allocate_resource(struct resource *root, struct resource *new,
 						       resource_size_t,
 						       resource_size_t),
 			     void *alignf_data);
+void resource_shrink_parents_top(struct resource *b_res,
+				 long size, struct resource *parent_res);
+struct device;
+int probe_resource(struct resource *b_res,
+			struct device *dev, struct resource *busn_res,
+			resource_size_t needed_size, struct resource **p,
+			int skip_nr, int limit, char *name);
 struct resource *lookup_resource(struct resource *root, resource_size_t start);
 int adjust_resource(struct resource *res, resource_size_t start,
 		    resource_size_t size);
diff --git a/kernel/resource.c b/kernel/resource.c
index 7640b3a..0c9616f 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -521,14 +521,14 @@ out:
  * @alignf: alignment function, optional, called if not NULL
  * @alignf_data: arbitrary data to pass to the @alignf function
  */
-int allocate_resource(struct resource *root, struct resource *new,
+static int __allocate_resource(struct resource *root, struct resource *new,
 		      resource_size_t size, resource_size_t min,
 		      resource_size_t max, resource_size_t align,
 		      resource_size_t (*alignf)(void *,
 						const struct resource *,
 						resource_size_t,
 						resource_size_t),
-		      void *alignf_data)
+		      void *alignf_data, bool lock)
 {
 	int err;
 	struct resource_constraint constraint;
@@ -542,19 +542,33 @@ int allocate_resource(struct resource *root, struct resource *new,
 	constraint.alignf = alignf;
 	constraint.alignf_data = alignf_data;
 
-	if ( new->parent ) {
+	if (new->parent && lock) {
 		/* resource is already allocated, try reallocating with
 		   the new constraints */
 		return reallocate_resource(root, new, size, &constraint);
 	}
 
-	write_lock(&resource_lock);
+	if (lock)
+		write_lock(&resource_lock);
 	err = find_resource(root, new, size, &constraint);
 	if (err >= 0 && __request_resource(root, new))
 		err = -EBUSY;
-	write_unlock(&resource_lock);
+	if (lock)
+		write_unlock(&resource_lock);
 	return err;
 }
+int allocate_resource(struct resource *root, struct resource *new,
+		      resource_size_t size, resource_size_t min,
+		      resource_size_t max, resource_size_t align,
+		      resource_size_t (*alignf)(void *,
+						const struct resource *,
+						resource_size_t,
+						resource_size_t),
+		      void *alignf_data)
+{
+	return __allocate_resource(root, new, size, min, max, align,
+				   alignf, alignf_data, true);
+}
 
 EXPORT_SYMBOL(allocate_resource);
 
@@ -962,6 +976,142 @@ void __release_region(struct resource *parent, resource_size_t start,
 }
 EXPORT_SYMBOL(__release_region);
 
+static void __resource_update_parents_top(struct resource *b_res,
+		 long size, struct resource *parent_res)
+{
+	struct resource *res = b_res;
+
+	if (!size)
+		return;
+
+	while (res) {
+		if (res == parent_res)
+			break;
+		res->end += size;
+		res = res->parent;
+	}
+}
+
+static void __resource_extend_parents_top(struct resource *b_res,
+		 long size, struct resource *parent_res)
+{
+	__resource_update_parents_top(b_res, size, parent_res);
+}
+
+void resource_shrink_parents_top(struct resource *b_res,
+		 long size, struct resource *parent_res)
+{
+	write_lock(&resource_lock);
+	__resource_update_parents_top(b_res, -size, parent_res);
+	write_unlock(&resource_lock);
+}
+
+static resource_size_t __find_res_top_free_size(struct resource *res)
+{
+	resource_size_t n_size;
+	struct resource tmp_res;
+
+	/*
+	 *   find out number below res->end, that we can use at first
+	 *	res->start can not be used.
+	 */
+	n_size = resource_size(res) - 1;
+	memset(&tmp_res, 0, sizeof(struct resource));
+	while (n_size > 0) {
+		int ret;
+
+		ret = __allocate_resource(res, &tmp_res, n_size,
+			res->end - n_size + 1, res->end,
+			1, NULL, NULL, false);
+		if (ret == 0) {
+			__release_resource(&tmp_res);
+			break;
+		}
+		n_size--;
+	}
+
+	return n_size;
+}
+
+int probe_resource(struct resource *b_res,
+			 struct device *dev, struct resource *busn_res,
+			 resource_size_t needed_size, struct resource **p,
+			 int skip_nr, int limit, char *name)
+{
+	int ret = -ENOMEM;
+	resource_size_t n_size;
+	struct resource *parent_res = NULL;
+	resource_size_t tmp = b_res->end + 1;
+
+again:
+	/*
+	 * find biggest range in b_res that we can use in the middle
+	 *  and we can not use some spots from start of b_res.
+	 */
+	n_size = resource_size(b_res);
+	if (n_size > skip_nr)
+		n_size -= skip_nr;
+	else
+		n_size = 0;
+
+	memset(busn_res, 0, sizeof(struct resource));
+	dev_printk(KERN_DEBUG, dev, "find free %s in res: %pR\n", name, b_res);
+	while (n_size >= needed_size) {
+		ret = allocate_resource(b_res, busn_res, n_size,
+				b_res->start + skip_nr, b_res->end,
+				1, NULL, NULL);
+		if (!ret)
+			return ret;
+		n_size--;
+	}
+
+	/* try extend the top of parent bus, find free under top at first */
+	write_lock(&resource_lock);
+	n_size = __find_res_top_free_size(b_res);
+	dev_printk(KERN_DEBUG, dev, "found free %s %ld in res: %pR top\n",
+			name, (unsigned long)n_size, b_res);
+
+	/* can not extend cross local boundary */
+	if ((limit - b_res->end) < (needed_size - n_size))
+		goto reduce_needed_size;
+
+	/* find extended range */
+	memset(busn_res, 0, sizeof(struct resource));
+	parent_res = b_res;
+	while (parent_res) {
+		ret = __allocate_resource(parent_res, busn_res,
+			 needed_size - n_size,
+			 tmp, tmp + needed_size - n_size - 1,
+			 1, NULL, NULL, false);
+		if (!ret) {
+			/* save parent_res, we need it as stopper later */
+			*p = parent_res;
+
+			/* prepare busn_res for return */
+			__release_resource(busn_res);
+			busn_res->start -= n_size;
+
+			/* extend parent bus top*/
+			__resource_extend_parents_top(b_res,
+					 needed_size - n_size, parent_res);
+			__request_resource(b_res, busn_res);
+
+			write_unlock(&resource_lock);
+			return ret;
+		}
+		parent_res = parent_res->parent;
+	}
+
+reduce_needed_size:
+	write_unlock(&resource_lock);
+	/* ret must not be 0 here */
+	needed_size--;
+	if (needed_size)
+		goto again;
+
+	return ret;
+}
+
 /*
  * Managed region resource
  */
-- 
1.7.7


  parent reply	other threads:[~2012-03-19  5:45 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-19  5:42 [PATCH -v11 00/30] PCI: allocate pci bus num range for unassigned bridge busn Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 01/30] x86, PCI: Add print all root info for not using _CRS path Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 02/30] x86, PCI: Allocate temp range array in amd_bus pci_root_info probing Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 03/30] x86, PCI: Merge pcibios_scan_root and pci_scan_bus_on_node Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 04/30] PCI: Add busn_res into struct pci_bus Yinghai Lu
2012-04-30 23:25   ` Bjorn Helgaas
2012-05-01  0:32     ` Yinghai Lu
2012-05-01  4:02       ` Bjorn Helgaas
2012-05-01  6:27         ` Yinghai Lu
2012-05-01 15:40           ` Bjorn Helgaas
2012-05-01 19:28             ` Yinghai Lu
2012-05-02  5:07               ` Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 05/30] PCI: Add busn_res operation functions Yinghai Lu
2012-04-30 23:29   ` Bjorn Helgaas
2012-05-01  0:34     ` Yinghai Lu
2012-05-01  7:19       ` Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 06/30] PCI: Release busn_res when removing bus Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 07/30] PCI: Insert busn_res in pci_create_root_bus() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 08/30] PCI: Checking busn_res in pci_scan_root_bus() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 09/30] PCI: Add default busn_resource Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 10/30] PCI: Add default busn_res for pci_scan_bus() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 11/30] x86, PCI: Add busn_res into resources list for acpi path Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 12/30] x86, PCI: Put busn resource in pci_root_info for not using _CRS path Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 13/30] PCI, ia64: Register busn_res for root buses Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 14/30] PCI, sparc: " Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 15/30] PCI, powerpc: " Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 16/30] PCI, parisc: " Yinghai Lu
2012-03-19  5:42 ` Yinghai Lu [this message]
2012-05-01 23:57   ` [PATCH -v11 17/30] resources: Add probe_resource() Bjorn Helgaas
2012-05-02  5:19     ` Yinghai Lu
2012-05-02  7:01       ` Yinghai Lu
2012-05-02 15:14         ` Bjorn Helgaas
2012-03-19  5:42 ` [PATCH -v11 18/30] resources: Replace registered resource in tree Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 19/30] PCI: Add pci_bus_extend/shrink_top() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 20/30] PCI: Probe safe range that we can use for unassigned bridge Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 21/30] PCI: Add pci_bus_replace_busn_res() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 22/30] PCI: Allocate bus range instead of use max blindly Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 23/30] PCI: Strict checking of valid range for bridge Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 24/30] PCI: Kill pci_fixup_parent_subordinate_busnr() Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 25/30] PCI: Seperate child bus scanning to two passes overall Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 26/30] pcmcia: Remove workaround for fixing pci parent bus subordinate Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 27/30] PCI: Double checking setting for bus register and bus struct Yinghai Lu
2012-03-19  5:42 ` [PATCH -v11 28/30] PCI, pciehp: Remove not needed bus number range checking Yinghai Lu
2012-03-19  5:43 ` [PATCH -v11 29/30] PCI: More strict checking of valid range for bridge Yinghai Lu
2012-03-19  5:43 ` [PATCH -v11 30/30] PCI: Don't shrink too much for hotplug bridge Yinghai Lu
2012-05-02 21:22 ` [PATCH -v11 00/30] PCI: allocate pci bus num range for unassigned bridge busn Bjorn Helgaas
2012-05-03  9:08   ` Yinghai Lu
2012-05-03 23:47     ` Bjorn Helgaas
2012-05-04 20:07       ` Yinghai Lu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1332135781-13695-18-git-send-email-yinghai@kernel.org \
    --to=yinghai@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=benh@kernel.crashing.org \
    --cc=bhelgaas@google.com \
    --cc=davem@davemloft.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=jbarnes@virtuousgeek.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux@dominikbrodowski.net \
    --cc=tony.luck@intel.com \
    --cc=torvalds@linux-foundation.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).