* [PATCH 1/12] pci: separate pci_setup_bridge to small functions
[not found] <4B2BE9DD.3040504@kernel.org>
@ 2009-12-18 20:54 ` Yinghai Lu
2009-12-18 21:15 ` Linus Torvalds
2009-12-18 20:54 ` [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2 Yinghai Lu
` (10 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:54 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
prepare to use those small functions according to resource type later
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 54 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 8 deletions(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -134,18 +134,12 @@ EXPORT_SYMBOL(pci_setup_cardbus);
config space writes, so it's quite possible that an I/O window of
the bridge will have some undesirable address (e.g. 0) after the
first write. Ditto 64-bit prefetchable MMIO. */
-static void pci_setup_bridge(struct pci_bus *bus)
+static void pci_setup_bridge_io(struct pci_bus *bus)
{
struct pci_dev *bridge = bus->self;
struct resource *res;
struct pci_bus_region region;
- u32 l, bu, lu, io_upper16;
-
- if (pci_is_enabled(bridge))
- return;
-
- dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
- bus->secondary, bus->subordinate);
+ u32 l, io_upper16;
/* Set up the top and bottom of the PCI I/O segment for this bus. */
res = bus->resource[0];
@@ -171,7 +165,14 @@ static void pci_setup_bridge(struct pci_
pci_write_config_dword(bridge, PCI_IO_BASE, l);
/* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
+}
+static void pci_setup_bridge_mmio(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *res;
+ struct pci_bus_region region;
+ u32 l;
/* Set up the top and bottom of the PCI Memory segment
for this bus. */
res = bus->resource[1];
@@ -186,6 +187,14 @@ static void pci_setup_bridge(struct pci_
dev_info(&bridge->dev, " bridge window [mem disabled]\n");
}
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+}
+
+static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource *res;
+ struct pci_bus_region region;
+ u32 l, bu, lu;
/* Clear out the upper 32 bits of PREF limit.
If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
@@ -200,6 +209,7 @@ static void pci_setup_bridge(struct pci_
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
if (res->flags & IORESOURCE_MEM_64) {
+ pref_mem64 = 1;
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
}
@@ -214,10 +224,38 @@ static void pci_setup_bridge(struct pci_
/* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
+}
+
+static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
+{
+ struct pci_dev *bridge = bus->self;
+
+ if (pci_is_enabled(bridge))
+ return;
+
+ dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
+ bus->secondary, bus->subordinate);
+
+ if (type & IORESOURCE_IO)
+ pci_setup_bridge_io(bus);
+
+ if (type & IORESOURCE_MEM)
+ pci_setup_bridge_mmio(bus);
+
+ if (type & IORESOURCE_PREFETCH)
+ pci_setup_bridge_mmio_pref(bus);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
}
+static void pci_setup_bridge(struct pci_bus *bus)
+{
+ unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ __pci_setup_bridge(bus, type);
+}
+
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 1/12] pci: separate pci_setup_bridge to small functions
2009-12-18 20:54 ` [PATCH 1/12] pci: separate pci_setup_bridge to small functions Yinghai Lu
@ 2009-12-18 21:15 ` Linus Torvalds
0 siblings, 0 replies; 23+ messages in thread
From: Linus Torvalds @ 2009-12-18 21:15 UTC (permalink / raw)
To: Yinghai Lu
Cc: Jesse Barnes, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 18 Dec 2009, Yinghai Lu wrote:
>
> prepare to use those small functions according to resource type later
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Ack. looks like a nice cleanup regardless of anything else. I much prefer
having lots of small functions that do one thing and one thing only, and
then one function that is there just to call them.
Linus
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
[not found] <4B2BE9DD.3040504@kernel.org>
2009-12-18 20:54 ` [PATCH 1/12] pci: separate pci_setup_bridge to small functions Yinghai Lu
@ 2009-12-18 20:54 ` Yinghai Lu
2009-12-18 21:24 ` Linus Torvalds
2009-12-18 20:55 ` [PATCH 3/12] pci: don't dump it when bus resource flags is not used Yinghai Lu
` (9 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:54 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
so later we could use it to release small resource before pci assign unassign res
-v2: change name to release_child_resources
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 112 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -209,7 +209,6 @@ static void pci_setup_bridge_mmio_pref(s
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
if (res->flags & IORESOURCE_MEM_64) {
- pref_mem64 = 1;
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
}
@@ -608,6 +607,118 @@ void __ref pci_bus_assign_resources(cons
}
EXPORT_SYMBOL(pci_bus_assign_resources);
+static void release_child_resources(struct resource *r)
+{
+ struct resource *p;
+ resource_size_t size;
+
+ p = r->child;
+ while (p) {
+ release_child_resources(p);
+ release_resource(p);
+ printk(KERN_DEBUG "PCI: release child resource %pR\n", p);
+ /* need to restore size, and keep flags */
+ size = resource_size(p);
+ p->start = 0;
+ p->end = size - 1;
+ p = r->child;
+ }
+}
+
+static void pci_bridge_release_unused_res(struct pci_bus *bus,
+ unsigned long type)
+{
+ int idx;
+ bool changed = false;
+ struct pci_dev *dev;
+ struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ /* for pci bridges res only */
+ dev = bus->self;
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
+ idx++) {
+ r = &dev->resource[idx];
+ if ((r->flags & type_mask) != type)
+ continue;
+ if (!r->parent)
+ continue;
+ /*
+ * if there are children under that, we should release them
+ * all
+ */
+ release_child_resources(r);
+ if (!release_resource(r)) {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "resource %d %pR released\n", idx, r);
+ /* keep the old size */
+ r->end = resource_size(r) - 1;
+ r->start = 0;
+ r->flags = 0;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ if (type & IORESOURCE_PREFETCH) {
+ /* avoiding touch the one without PREF */
+ type = IORESOURCE_PREFETCH;
+ }
+ __pci_setup_bridge(bus, type);
+ }
+}
+
+/*
+ * try to release pci bridge resources that is from leaf bridge,
+ * so we can allocate big new one later
+ * check:
+ * 0: only release the bridge and only the bridge is leaf
+ * 1: release all down side bridge for third shoot
+ */
+static void __ref pci_bus_release_unused_bridge_res(struct pci_bus *bus,
+ unsigned long type,
+ int check_leaf)
+{
+ struct pci_dev *dev;
+ bool is_leaf_bridge = true;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ switch (dev->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ is_leaf_bridge = false;
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ is_leaf_bridge = false;
+ if (!check_leaf)
+ pci_bus_release_unused_bridge_res(b, type,
+ check_leaf);
+ break;
+ }
+ }
+
+ /* The root bus? */
+ if (!bus->self)
+ return;
+
+ switch (bus->self->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ if ((check_leaf && is_leaf_bridge) || !check_leaf)
+ pci_bridge_release_unused_res(bus, type);
+ break;
+ }
+}
+
static void pci_bus_dump_res(struct pci_bus *bus)
{
int i;
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-18 20:54 ` [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2 Yinghai Lu
@ 2009-12-18 21:24 ` Linus Torvalds
2009-12-18 21:43 ` Jesse Barnes
` (2 more replies)
0 siblings, 3 replies; 23+ messages in thread
From: Linus Torvalds @ 2009-12-18 21:24 UTC (permalink / raw)
To: Yinghai Lu
Cc: Jesse Barnes, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 18 Dec 2009, Yinghai Lu wrote:
>
> so later we could use it to release small resource before pci assign unassign res
However, I think this one is wrong.
> +static void release_child_resources(struct resource *r)
> +{
> + struct resource *p;
> + resource_size_t size;
> +
> + p = r->child;
> + while (p) {
> + release_child_resources(p);
> + release_resource(p);
So not only is this releasing resources that aren't necessarily PCI
devices, it's releasing the whole tree - regardless of how they were
allocated and initialized. That makes me nervous to begin with. It's in
the wrong file.
But the locking is crap too!
You need to hold the resource lock for the whole operation - you can't
just walk the resource tree and release them.
And once you do that, then using "release_resrouce()" is the wrong thing,
since it turns into just "__release_resource()" and you notice that that
walks the chain looking for them - which makes it pointless to have
_another_ outer loop that walks the chain to release them!
So you'd need to
- move this to kernel/resource.c
- do it all under 'write_lock(&resource_lock);'
- stop the silly double list loop, and just do it as a single loop that
does
p = old->parent->child;
old->parent = NULL;
while (p) {
struct resource *tmp = p;
p = p->sibling;
.. do whatever you do to free tmp ..
}
and it's much simpler, more efficient, has the rigth locking, and is in
the right place.
That said, it's still unclear if you can ever do this! Why would the PCI
layer be allowed to release ACPI resources int he tree, for example?
So I can see fixing the _implementation_ issues I have like above, but I'd
still be nervous about the whole concept of the patch..
Linus
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-18 21:24 ` Linus Torvalds
@ 2009-12-18 21:43 ` Jesse Barnes
2009-12-19 0:26 ` Yinghai Lu
2009-12-20 23:59 ` Bjorn Helgaas
2 siblings, 0 replies; 23+ messages in thread
From: Jesse Barnes @ 2009-12-18 21:43 UTC (permalink / raw)
To: Linus Torvalds
Cc: Yinghai Lu, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 18 Dec 2009 13:24:41 -0800 (PST)
Linus Torvalds <torvalds@linux-foundation.org> wrote:
> And once you do that, then using "release_resrouce()" is the wrong
> thing, since it turns into just "__release_resource()" and you notice
> that that walks the chain looking for them - which makes it pointless
> to have _another_ outer loop that walks the chain to release them!
>
> So you'd need to
>
> - move this to kernel/resource.c
>
> - do it all under 'write_lock(&resource_lock);'
>
> - stop the silly double list loop, and just do it as a single loop
> that does
>
> p = old->parent->child;
> old->parent = NULL;
> while (p) {
> struct resource *tmp = p;
> p = p->sibling;
>
> .. do whatever you do to free tmp ..
> }
>
> and it's much simpler, more efficient, has the rigth locking, and
> is in the right place.
>
> That said, it's still unclear if you can ever do this! Why would the
> PCI layer be allowed to release ACPI resources int he tree, for
> example?
>
> So I can see fixing the _implementation_ issues I have like above,
> but I'd still be nervous about the whole concept of the patch..
Yeah, if we roll all the way back up through some system resources we
could definitely get into trouble. Stopping the recursion when we hit
a bridge or host bridge may be a good enough heuristic?
Really I guess this is just a half measure. There are a whole set a
fixed resources that are children of the root address space, and we
shouldn't try to free or move them around at all (e.g. ACPI _CRS type
resources). Beyond that though it should be safe to free all the
moveable resources in a tree and try again if a leaf device can't get
its preferred allocation (the whole purpose of this series afaict).
--
Jesse Barnes, Intel Open Source Technology Center
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-18 21:24 ` Linus Torvalds
2009-12-18 21:43 ` Jesse Barnes
@ 2009-12-19 0:26 ` Yinghai Lu
2009-12-19 0:40 ` Linus Torvalds
2009-12-21 0:04 ` Bjorn Helgaas
2009-12-20 23:59 ` Bjorn Helgaas
2 siblings, 2 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-19 0:26 UTC (permalink / raw)
To: Linus Torvalds
Cc: Jesse Barnes, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Linus Torvalds wrote:
>
> On Fri, 18 Dec 2009, Yinghai Lu wrote:
>> so later we could use it to release small resource before pci assign unassign res
>
> However, I think this one is wrong.
>
>> +static void release_child_resources(struct resource *r)
>> +{
>> + struct resource *p;
>> + resource_size_t size;
>> +
>> + p = r->child;
>> + while (p) {
>> + release_child_resources(p);
>> + release_resource(p);
>
> So not only is this releasing resources that aren't necessarily PCI
> devices, it's releasing the whole tree - regardless of how they were
> allocated and initialized. That makes me nervous to begin with. It's in
> the wrong file.
>
> But the locking is crap too!
>
> You need to hold the resource lock for the whole operation - you can't
> just walk the resource tree and release them.
>
> And once you do that, then using "release_resrouce()" is the wrong thing,
> since it turns into just "__release_resource()" and you notice that that
> walks the chain looking for them - which makes it pointless to have
> _another_ outer loop that walks the chain to release them!
>
> So you'd need to
>
> - move this to kernel/resource.c
>
> - do it all under 'write_lock(&resource_lock);'
>
> - stop the silly double list loop, and just do it as a single loop that
> does
>
> p = old->parent->child;
> old->parent = NULL;
> while (p) {
> struct resource *tmp = p;
> p = p->sibling;
>
> .. do whatever you do to free tmp ..
> }
>
> and it's much simpler, more efficient, has the rigth locking, and is in
> the right place.
ok, please check attached is right or not
>
> That said, it's still unclear if you can ever do this! Why would the PCI
> layer be allowed to release ACPI resources int he tree, for example?
>
> So I can see fixing the _implementation_ issues I have like above, but I'd
> still be nervous about the whole concept of the patch..
those code are only called during early stage when pci_assign unassigned, and pcie hotplug under the pcie port.
also that is the pci_try_num is default to 1, and only be changed by pci=try=2 etc. only second try start to call
those functions.
Thanks
Yinghai
Subject: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v3
so later we could use it to release small resource before pci assign unassign res
-v2: change name to release_child_resources according to Jesse
-v3: according to Linus, move release_child_resources to resource.c
also need to put the lock around them all to avoid recursive deep.
(my test case only have one level that need to be released)
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/ioport.h | 1
kernel/resource.c | 30 +++++++++++++++
3 files changed, 125 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -209,7 +209,6 @@ static void pci_setup_bridge_mmio_pref(s
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
if (res->flags & IORESOURCE_MEM_64) {
- pref_mem64 = 1;
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
}
@@ -608,6 +607,100 @@ void __ref pci_bus_assign_resources(cons
}
EXPORT_SYMBOL(pci_bus_assign_resources);
+static void pci_bridge_release_unused_res(struct pci_bus *bus,
+ unsigned long type)
+{
+ int idx;
+ bool changed = false;
+ struct pci_dev *dev;
+ struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+
+ /* for pci bridges res only */
+ dev = bus->self;
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
+ idx++) {
+ r = &dev->resource[idx];
+ if ((r->flags & type_mask) != type)
+ continue;
+ if (!r->parent)
+ continue;
+ /*
+ * if there are children under that, we should release them
+ * all
+ */
+ release_child_resources(r);
+ if (!release_resource(r)) {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "resource %d %pR released\n", idx, r);
+ /* keep the old size */
+ r->end = resource_size(r) - 1;
+ r->start = 0;
+ r->flags = 0;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ if (type & IORESOURCE_PREFETCH) {
+ /* avoiding touch the one without PREF */
+ type = IORESOURCE_PREFETCH;
+ }
+ __pci_setup_bridge(bus, type);
+ }
+}
+
+/*
+ * try to release pci bridge resources that is from leaf bridge,
+ * so we can allocate big new one later
+ * check:
+ * 0: only release the bridge and only the bridge is leaf
+ * 1: release all down side bridge for third shoot
+ */
+static void __ref pci_bus_release_unused_bridge_res(struct pci_bus *bus,
+ unsigned long type,
+ int check_leaf)
+{
+ struct pci_dev *dev;
+ bool is_leaf_bridge = true;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ switch (dev->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ is_leaf_bridge = false;
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ is_leaf_bridge = false;
+ if (!check_leaf)
+ pci_bus_release_unused_bridge_res(b, type,
+ check_leaf);
+ break;
+ }
+ }
+
+ /* The root bus? */
+ if (!bus->self)
+ return;
+
+ switch (bus->self->class >> 8) {
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ default:
+ if ((check_leaf && is_leaf_bridge) || !check_leaf)
+ pci_bridge_release_unused_res(bus, type);
+ break;
+ }
+}
+
static void pci_bus_dump_res(struct pci_bus *bus)
{
int i;
Index: linux-2.6/include/linux/ioport.h
===================================================================
--- linux-2.6.orig/include/linux/ioport.h
+++ linux-2.6/include/linux/ioport.h
@@ -112,6 +112,7 @@ extern struct resource iomem_resource;
extern int request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
+void release_child_resources(struct resource *new);
extern void reserve_region_with_split(struct resource *root,
resource_size_t start, resource_size_t end,
const char *name);
Index: linux-2.6/kernel/resource.c
===================================================================
--- linux-2.6.orig/kernel/resource.c
+++ linux-2.6/kernel/resource.c
@@ -188,6 +188,36 @@ static int __release_resource(struct res
return -EINVAL;
}
+static void __release_child_resources(struct resource *r)
+{
+ struct resource *tmp, *p;
+ resource_size_t size;
+
+ p = r->child;
+ r->child = NULL;
+ while (p) {
+ tmp = p;
+ p = p->sibling;
+
+ tmp->parent = NULL;
+ tmp->sibling = NULL;
+ __release_child_resources(tmp);
+
+ printk(KERN_DEBUG "release child resource %pR\n", tmp);
+ /* need to restore size, and keep flags */
+ size = resource_size(tmp);
+ tmp->start = 0;
+ tmp->end = size - 1;
+ }
+}
+
+void release_child_resources(struct resource *r)
+{
+ write_lock(&resource_lock);
+ __release_child_resources(r);
+ write_unlock(&resource_lock);
+}
+
/**
* request_resource - request and reserve an I/O or memory resource
* @root: root resource descriptor
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-19 0:26 ` Yinghai Lu
@ 2009-12-19 0:40 ` Linus Torvalds
2009-12-19 1:20 ` Yinghai Lu
2009-12-21 0:04 ` Bjorn Helgaas
1 sibling, 1 reply; 23+ messages in thread
From: Linus Torvalds @ 2009-12-19 0:40 UTC (permalink / raw)
To: Yinghai Lu
Cc: Jesse Barnes, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 18 Dec 2009, Yinghai Lu wrote:
>
> ok, please check attached is right or not
>
> +static void __release_child_resources(struct resource *r)
> +{
> + struct resource *tmp, *p;
> + resource_size_t size;
> +
> + p = r->child;
> + r->child = NULL;
> + while (p) {
> + tmp = p;
> + p = p->sibling;
> +
> + tmp->parent = NULL;
> + tmp->sibling = NULL;
> + __release_child_resources(tmp);
> +
> + printk(KERN_DEBUG "release child resource %pR\n", tmp);
> + /* need to restore size, and keep flags */
> + size = resource_size(tmp);
> + tmp->start = 0;
> + tmp->end = size - 1;
> + }
> +}
Ok, this looks mostly right. I do worry about the alignment information:
you lose that thing for any resource that had IORESOURCE_STARTALIGN set
when you do this thing. That's pretty fundamental to the whole resource
code, I suspect we should just finally add a 'alignment' field to the
resource struct, so that alignment doesn't get lost when a resource is
allocated.
(Do a "git grep IORESOURCE_.*ALIGN" to see the kind of stuff I'm talking
about, and look at he PCI 'setup-bus.c' code that sets that STARTALIGN
thing).
So a preliminary ack on the resource.c parts. The rest I'm still a bit
dubious about, and the whole "we've lost alignment on the resources" is
probably indicative of how none of the resource code has ever really been
designed for this kind of "tear down and build back up again" behavior.
Linus
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-19 0:40 ` Linus Torvalds
@ 2009-12-19 1:20 ` Yinghai Lu
0 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-19 1:20 UTC (permalink / raw)
To: Linus Torvalds
Cc: Jesse Barnes, Ingo Molnar, Ivan Kokshaysky, Kenji Kaneshige,
Alex Chiang, Bjorn Helgaas, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Linus Torvalds wrote:
>
> On Fri, 18 Dec 2009, Yinghai Lu wrote:
>> ok, please check attached is right or not
>>
>> +static void __release_child_resources(struct resource *r)
>> +{
>> + struct resource *tmp, *p;
>> + resource_size_t size;
>> +
>> + p = r->child;
>> + r->child = NULL;
>> + while (p) {
>> + tmp = p;
>> + p = p->sibling;
>> +
>> + tmp->parent = NULL;
>> + tmp->sibling = NULL;
>> + __release_child_resources(tmp);
>> +
>> + printk(KERN_DEBUG "release child resource %pR\n", tmp);
>> + /* need to restore size, and keep flags */
>> + size = resource_size(tmp);
>> + tmp->start = 0;
>> + tmp->end = size - 1;
>> + }
>> +}
>
> Ok, this looks mostly right. I do worry about the alignment information:
> you lose that thing for any resource that had IORESOURCE_STARTALIGN set
> when you do this thing. That's pretty fundamental to the whole resource
> code, I suspect we should just finally add a 'alignment' field to the
> resource struct, so that alignment doesn't get lost when a resource is
> allocated.
>
> (Do a "git grep IORESOURCE_.*ALIGN" to see the kind of stuff I'm talking
> about, and look at he PCI 'setup-bus.c' code that sets that STARTALIGN
> thing).
>
> So a preliminary ack on the resource.c parts. The rest I'm still a bit
> dubious about, and the whole "we've lost alignment on the resources" is
> probably indicative of how none of the resource code has ever really been
> designed for this kind of "tear down and build back up again" behavior.
arch/powerpc/kernel/pci_of_scan.c: flags |= IORESOURCE_SIZEALIGN;
drivers/pci/probe.c: res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
drivers/pci/probe.c: IORESOURCE_SIZEALIGN;
drivers/pci/setup-bus.c: b_res->flags |= IORESOURCE_STARTALIGN;
drivers/pci/setup-bus.c: b_res->flags |= IORESOURCE_STARTALIGN;
drivers/pci/setup-bus.c: b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
drivers/pci/setup-bus.c: b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
drivers/pci/setup-bus.c: b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
drivers/pci/setup-bus.c: b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
drivers/pci/setup-bus.c: b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
drivers/pci/setup-res.c: res->flags &= ~IORESOURCE_STARTALIGN;
drivers/staging/b3dfg/b3dfg.c: != (IORESOURCE_MEM | IORESOURCE_SIZEALIGN)) {
include/linux/ioport.h:#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
include/linux/ioport.h:#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
kernel/resource.c: switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) {
kernel/resource.c: case IORESOURCE_SIZEALIGN:
kernel/resource.c: case IORESOURCE_STARTALIGN:
looks like IORESOURCE_SIZEALIGN is only used by bridge.
and next round. pbus_size_mem will add that back again.
YH
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-19 0:26 ` Yinghai Lu
2009-12-19 0:40 ` Linus Torvalds
@ 2009-12-21 0:04 ` Bjorn Helgaas
2009-12-21 1:56 ` Yinghai Lu
1 sibling, 1 reply; 23+ messages in thread
From: Bjorn Helgaas @ 2009-12-21 0:04 UTC (permalink / raw)
To: Yinghai Lu
Cc: Linus Torvalds, Jesse Barnes, Ingo Molnar, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 2009-12-18 at 16:26 -0800, Yinghai Lu wrote:
> Subject: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v3
>
> so later we could use it to release small resource before pci assign unassign res
>
> -v2: change name to release_child_resources according to Jesse
> -v3: according to Linus, move release_child_resources to resource.c
> also need to put the lock around them all to avoid recursive deep.
> (my test case only have one level that need to be released)
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>
> ---
> drivers/pci/setup-bus.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-
> include/linux/ioport.h | 1
> kernel/resource.c | 30 +++++++++++++++
> 3 files changed, 125 insertions(+), 1 deletion(-)
>
> Index: linux-2.6/drivers/pci/setup-bus.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/setup-bus.c
> +++ linux-2.6/drivers/pci/setup-bus.c
> @@ -209,7 +209,6 @@ static void pci_setup_bridge_mmio_pref(s
> l = (region.start >> 16) & 0xfff0;
> l |= region.end & 0xfff00000;
> if (res->flags & IORESOURCE_MEM_64) {
> - pref_mem64 = 1;
> bu = upper_32_bits(region.start);
> lu = upper_32_bits(region.end);
> }
> @@ -608,6 +607,100 @@ void __ref pci_bus_assign_resources(cons
> }
> EXPORT_SYMBOL(pci_bus_assign_resources);
>
> +static void pci_bridge_release_unused_res(struct pci_bus *bus,
> + unsigned long type)
> +{
> + int idx;
> + bool changed = false;
> + struct pci_dev *dev;
> + struct resource *r;
> + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
> + IORESOURCE_PREFETCH;
> +
> + /* for pci bridges res only */
> + dev = bus->self;
> + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
I *think* this magic "3" refers to the three possible windows supported
by PCI bridges (I/O, memory, prefetchable memory). I asked you before
about using something more descriptive here; do you have any ideas? I
think even PCI_BRIDGE_RESOURCE_NUM (4) would be better, because I think
that's the number of bridge windows we support (CardBus bridges have
four windows, regular PCI bridges only have three). For regular PCI
bridges, that fourth window should be NULL, so it could easily be
skipped here.
> + idx++) {
> + r = &dev->resource[idx];
> + if ((r->flags & type_mask) != type)
> + continue;
> + if (!r->parent)
> + continue;
> + /*
> + * if there are children under that, we should release them
> + * all
> + */
> + release_child_resources(r);
Sorry for my ignorance here, but is it possible there's a driver using
any of these child devices?
> + if (!release_resource(r)) {
> + dev_printk(KERN_DEBUG, &dev->dev,
> + "resource %d %pR released\n", idx, r);
> + /* keep the old size */
> + r->end = resource_size(r) - 1;
> + r->start = 0;
> + r->flags = 0;
> + changed = true;
> + }
> + }
> +
> + if (changed) {
> + if (type & IORESOURCE_PREFETCH) {
> + /* avoiding touch the one without PREF */
> + type = IORESOURCE_PREFETCH;
> + }
Again, it's probably perfectly obvious why we need to leave the
non-prefetchable window untouched, but I don't know the reason. Can you
add a comment about why that's important?
> + __pci_setup_bridge(bus, type);
> + }
> +}
> +
> +/*
> + * try to release pci bridge resources that is from leaf bridge,
> + * so we can allocate big new one later
> + * check:
> + * 0: only release the bridge and only the bridge is leaf
> + * 1: release all down side bridge for third shoot
> + */
> +static void __ref pci_bus_release_unused_bridge_res(struct pci_bus *bus,
> + unsigned long type,
> + int check_leaf)
> +{
> + struct pci_dev *dev;
> + bool is_leaf_bridge = true;
> +
> + list_for_each_entry(dev, &bus->devices, bus_list) {
> + struct pci_bus *b = dev->subordinate;
> + if (!b)
> + continue;
> +
> + switch (dev->class >> 8) {
> + case PCI_CLASS_BRIDGE_CARDBUS:
> + is_leaf_bridge = false;
> + break;
> +
> + case PCI_CLASS_BRIDGE_PCI:
> + default:
> + is_leaf_bridge = false;
> + if (!check_leaf)
> + pci_bus_release_unused_bridge_res(b, type,
> + check_leaf);
> + break;
> + }
> + }
> +
> + /* The root bus? */
> + if (!bus->self)
> + return;
> +
> + switch (bus->self->class >> 8) {
> + case PCI_CLASS_BRIDGE_CARDBUS:
> + break;
> +
> + case PCI_CLASS_BRIDGE_PCI:
Sorry for my ignorance again. Why do we have to treat CardBus bridges
so much differently? I realize their windows are programmed a bit
differently, but I don't know what the conceptual difference is as far
as a bridge window being too small to accomodate all downstream devices.
> + default:
> + if ((check_leaf && is_leaf_bridge) || !check_leaf)
> + pci_bridge_release_unused_res(bus, type);
> + break;
> + }
> +}
> +
> static void pci_bus_dump_res(struct pci_bus *bus)
> {
> int i;
Bjorn
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-21 0:04 ` Bjorn Helgaas
@ 2009-12-21 1:56 ` Yinghai Lu
0 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-21 1:56 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Linus Torvalds, Jesse Barnes, Ingo Molnar, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Bjorn Helgaas wrote:
> On Fri, 2009-12-18 at 16:26 -0800, Yinghai Lu wrote:
>> Subject: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v3
>>
>> so later we could use it to release small resource before pci assign unassign res
>>
>> -v2: change name to release_child_resources according to Jesse
>> -v3: according to Linus, move release_child_resources to resource.c
>> also need to put the lock around them all to avoid recursive deep.
>> (my test case only have one level that need to be released)
>>
>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>>
>> ---
>> drivers/pci/setup-bus.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-
>> include/linux/ioport.h | 1
>> kernel/resource.c | 30 +++++++++++++++
>> 3 files changed, 125 insertions(+), 1 deletion(-)
>>
>> Index: linux-2.6/drivers/pci/setup-bus.c
>> ===================================================================
>> --- linux-2.6.orig/drivers/pci/setup-bus.c
>> +++ linux-2.6/drivers/pci/setup-bus.c
>> @@ -209,7 +209,6 @@ static void pci_setup_bridge_mmio_pref(s
>> l = (region.start >> 16) & 0xfff0;
>> l |= region.end & 0xfff00000;
>> if (res->flags & IORESOURCE_MEM_64) {
>> - pref_mem64 = 1;
>> bu = upper_32_bits(region.start);
>> lu = upper_32_bits(region.end);
>> }
>> @@ -608,6 +607,100 @@ void __ref pci_bus_assign_resources(cons
>> }
>> EXPORT_SYMBOL(pci_bus_assign_resources);
>>
>> +static void pci_bridge_release_unused_res(struct pci_bus *bus,
>> + unsigned long type)
>> +{
>> + int idx;
>> + bool changed = false;
>> + struct pci_dev *dev;
>> + struct resource *r;
>> + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
>> + IORESOURCE_PREFETCH;
>> +
>> + /* for pci bridges res only */
>> + dev = bus->self;
>> + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
>
> I *think* this magic "3" refers to the three possible windows supported
> by PCI bridges (I/O, memory, prefetchable memory). I asked you before
> about using something more descriptive here; do you have any ideas? I
> think even PCI_BRIDGE_RESOURCE_NUM (4) would be better, because I think
> that's the number of bridge windows we support (CardBus bridges have
> four windows, regular PCI bridges only have three). For regular PCI
> bridges, that fourth window should be NULL, so it could easily be
> skipped here.
ok. will try to use PCI_BRIDGE_RESOURCE_NUM
>
>> + idx++) {
>> + r = &dev->resource[idx];
>> + if ((r->flags & type_mask) != type)
>> + continue;
>> + if (!r->parent)
>> + continue;
>> + /*
>> + * if there are children under that, we should release them
>> + * all
>> + */
>> + release_child_resources(r);
>
> Sorry for my ignorance here, but is it possible there's a driver using
> any of these child devices?
Good question!.
this function is only being called
1. during pci_assign unassgined resources. during first...so no driver using those...
2. during loading pciehp device under that pcie port are assigned pci resource. at that time no resource are claimed for those devices.
>
>> + if (!release_resource(r)) {
>> + dev_printk(KERN_DEBUG, &dev->dev,
>> + "resource %d %pR released\n", idx, r);
>> + /* keep the old size */
>> + r->end = resource_size(r) - 1;
>> + r->start = 0;
>> + r->flags = 0;
>> + changed = true;
>> + }
>> + }
>> +
>> + if (changed) {
>> + if (type & IORESOURCE_PREFETCH) {
>> + /* avoiding touch the one without PREF */
>> + type = IORESOURCE_PREFETCH;
>> + }
>
> Again, it's probably perfectly obvious why we need to leave the
> non-prefetchable window untouched, but I don't know the reason. Can you
> add a comment about why that's important?
only release related type.
for example: the device under that bridge, didn't get pref mmio correctly assigned,
will only try to release bridge's pref mmio window instead of release mmio window at
same time.
>
>> + __pci_setup_bridge(bus, type);
>> + }
>> +}
>> +
>> +/*
>> + * try to release pci bridge resources that is from leaf bridge,
>> + * so we can allocate big new one later
>> + * check:
>> + * 0: only release the bridge and only the bridge is leaf
>> + * 1: release all down side bridge for third shoot
>> + */
>> +static void __ref pci_bus_release_unused_bridge_res(struct pci_bus *bus,
>> + unsigned long type,
>> + int check_leaf)
>> +{
>> + struct pci_dev *dev;
>> + bool is_leaf_bridge = true;
>> +
>> + list_for_each_entry(dev, &bus->devices, bus_list) {
>> + struct pci_bus *b = dev->subordinate;
>> + if (!b)
>> + continue;
>> +
>> + switch (dev->class >> 8) {
>> + case PCI_CLASS_BRIDGE_CARDBUS:
>> + is_leaf_bridge = false;
>> + break;
>> +
>> + case PCI_CLASS_BRIDGE_PCI:
>> + default:
>> + is_leaf_bridge = false;
>> + if (!check_leaf)
>> + pci_bus_release_unused_bridge_res(b, type,
>> + check_leaf);
>> + break;
>> + }
>> + }
>> +
>> + /* The root bus? */
>> + if (!bus->self)
>> + return;
>> +
>> + switch (bus->self->class >> 8) {
>> + case PCI_CLASS_BRIDGE_CARDBUS:
>> + break;
>> +
>> + case PCI_CLASS_BRIDGE_PCI:
>
> Sorry for my ignorance again. Why do we have to treat CardBus bridges
> so much differently? I realize their windows are programmed a bit
> differently, but I don't know what the conceptual difference is as far
> as a bridge window being too small to accomodate all downstream devices.
i didn't have those cardbus stuff around, and have no way to test them.
and looks like some special code for card bus etc handling. so could leave other
guys to play them later.
thanks for closely reading through the code.
Yinghai
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2
2009-12-18 21:24 ` Linus Torvalds
2009-12-18 21:43 ` Jesse Barnes
2009-12-19 0:26 ` Yinghai Lu
@ 2009-12-20 23:59 ` Bjorn Helgaas
2 siblings, 0 replies; 23+ messages in thread
From: Bjorn Helgaas @ 2009-12-20 23:59 UTC (permalink / raw)
To: Linus Torvalds
Cc: Yinghai Lu, Jesse Barnes, Ingo Molnar, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 2009-12-18 at 13:24 -0800, Linus Torvalds wrote:
>
> On Fri, 18 Dec 2009, Yinghai Lu wrote:
> >
> > so later we could use it to release small resource before pci assign unassign res
>
> However, I think this one is wrong.
>
> > +static void release_child_resources(struct resource *r)
> > +{
> > + struct resource *p;
> > + resource_size_t size;
> > +
> > + p = r->child;
> > + while (p) {
> > + release_child_resources(p);
> > + release_resource(p);
>
> So not only is this releasing resources that aren't necessarily PCI
> devices, it's releasing the whole tree - regardless of how they were
> allocated and initialized. ...
Help me fill in my mental picture of these resources ... This function
just takes a struct resource, so it doesn't know whether it's a PCI,
ACPI, or other resource. But in Yinghai's usage, I think we do know
that we're starting with a PCI resource. In that case, is it possible
that some child is a non-PCI resource?
The picture in my mind is that once we are downstream of a PCI host
bridge, all child resources must be PCI, and they must all conform to
the forwarding rules for PCI bridges and so on. I know there are PCI
devices with BARs at non-standard places, so Linux wouldn't know about
those resources (and that worries me a bit when we're talking about
reprogramming a bridge window that might be upstream of such a device).
But if Linux *did* learn about those non-standard resources via a quirk
or something, I would still think of those as PCI resources, not ACPI or
something else.
Anyway, I'd like to correct my mental picture if it's mistaken.
Bjorn
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 3/12] pci: don't dump it when bus resource flags is not used
[not found] <4B2BE9DD.3040504@kernel.org>
2009-12-18 20:54 ` [PATCH 1/12] pci: separate pci_setup_bridge to small functions Yinghai Lu
2009-12-18 20:54 ` [PATCH 2/12] pci: add pci_bridge_release_unused_res and pci_bus_release_unused_bridge_res -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2 Yinghai Lu
` (8 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
mean it is not used, so skip it.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -725,7 +725,8 @@ static void pci_bus_dump_res(struct pci_
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
struct resource *res = bus->resource[i];
- if (!res || !res->end)
+
+ if (!res || !res->end || !res->flags)
continue;
dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res);
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2
[not found] <4B2BE9DD.3040504@kernel.org>
` (2 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 3/12] pci: don't dump it when bus resource flags is not used Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-20 23:45 ` Bjorn Helgaas
2009-12-18 20:55 ` [PATCH 5/12] pci: update leaf bridge res to get more big range in pci assign unssign -v3 Yinghai Lu
` (7 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
so later we can do sth with those failed one
-v2: store start, end, flags aside. so could keep res cleared when assign
failed. and make following assignment of its children do not go wild
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 62 insertions(+), 4 deletions(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -27,7 +27,52 @@
#include <linux/slab.h>
#include "pci.h"
-static void pbus_assign_resources_sorted(const struct pci_bus *bus)
+struct resource_list_x {
+ struct resource_list_x *next;
+ struct resource *res;
+ struct pci_dev *dev;
+ resource_size_t start;
+ resource_size_t end;
+ unsigned long flags;
+};
+
+static void add_to_failed_list(struct resource_list_x *head,
+ struct pci_dev *dev, struct resource *res)
+{
+ struct resource_list_x *list = head;
+ struct resource_list_x *ln = list->next;
+ struct resource_list_x *tmp;
+
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp) {
+ pr_warning("add_to_failed_list: kmalloc() failed!\n");
+ return;
+ }
+
+ tmp->next = ln;
+ tmp->res = res;
+ tmp->dev = dev;
+ tmp->start = res->start;
+ tmp->end = res->end;
+ tmp->flags = res->flags;
+ list->next = tmp;
+}
+
+static void free_failed_list(struct resource_list_x *head)
+{
+ struct resource_list_x *list, *tmp;
+
+ for (list = head->next; list;) {
+ tmp = list;
+ list = list->next;
+ kfree(tmp);
+ }
+
+ head->next = NULL;
+}
+
+static void pbus_assign_resources_sorted(const struct pci_bus *bus,
+ struct resource_list_x *fail_head)
{
struct pci_dev *dev;
struct resource *res;
@@ -58,6 +103,13 @@ static void pbus_assign_resources_sorted
res = list->res;
idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) {
+ if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+ /*
+ * device need to keep flags and size
+ * for next try
+ */
+ add_to_failed_list(fail_head, list->dev, res);
+ }
res->start = 0;
res->end = 0;
res->flags = 0;
@@ -575,19 +627,20 @@ void __ref pci_bus_size_bridges(struct p
}
EXPORT_SYMBOL(pci_bus_size_bridges);
-void __ref pci_bus_assign_resources(const struct pci_bus *bus)
+static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
+ struct resource_list_x *fail_head)
{
struct pci_bus *b;
struct pci_dev *dev;
- pbus_assign_resources_sorted(bus);
+ pbus_assign_resources_sorted(bus, fail_head);
list_for_each_entry(dev, &bus->devices, bus_list) {
b = dev->subordinate;
if (!b)
continue;
- pci_bus_assign_resources(b);
+ __pci_bus_assign_resources(b, fail_head);
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
@@ -605,6 +658,11 @@ void __ref pci_bus_assign_resources(cons
}
}
}
+
+void __ref pci_bus_assign_resources(const struct pci_bus *bus)
+{
+ __pci_bus_assign_resources(bus, NULL);
+}
EXPORT_SYMBOL(pci_bus_assign_resources);
static void release_child_resources(struct resource *r)
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2
2009-12-18 20:55 ` [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2 Yinghai Lu
@ 2009-12-20 23:45 ` Bjorn Helgaas
2009-12-21 1:44 ` Yinghai Lu
0 siblings, 1 reply; 23+ messages in thread
From: Bjorn Helgaas @ 2009-12-20 23:45 UTC (permalink / raw)
To: Yinghai Lu
Cc: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
On Fri, 2009-12-18 at 12:55 -0800, Yinghai Lu wrote:
>
> so later we can do sth with those failed one
>
> -v2: store start, end, flags aside. so could keep res cleared when assign
> failed. and make following assignment of its children do not go wild
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>
> ---
> drivers/pci/setup-bus.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 62 insertions(+), 4 deletions(-)
>
> Index: linux-2.6/drivers/pci/setup-bus.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/setup-bus.c
> +++ linux-2.6/drivers/pci/setup-bus.c
> @@ -27,7 +27,52 @@
> #include <linux/slab.h>
> #include "pci.h"
>
> -static void pbus_assign_resources_sorted(const struct pci_bus *bus)
> +struct resource_list_x {
> + struct resource_list_x *next;
> + struct resource *res;
> + struct pci_dev *dev;
> + resource_size_t start;
> + resource_size_t end;
> + unsigned long flags;
> +};
> +
> +static void add_to_failed_list(struct resource_list_x *head,
> + struct pci_dev *dev, struct resource *res)
> +{
> + struct resource_list_x *list = head;
> + struct resource_list_x *ln = list->next;
> + struct resource_list_x *tmp;
> +
> + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
> + if (!tmp) {
> + pr_warning("add_to_failed_list: kmalloc() failed!\n");
> + return;
> + }
> +
> + tmp->next = ln;
> + tmp->res = res;
> + tmp->dev = dev;
> + tmp->start = res->start;
> + tmp->end = res->end;
> + tmp->flags = res->flags;
> + list->next = tmp;
> +}
> +
> +static void free_failed_list(struct resource_list_x *head)
> +{
> + struct resource_list_x *list, *tmp;
> +
> + for (list = head->next; list;) {
> + tmp = list;
> + list = list->next;
> + kfree(tmp);
> + }
> +
> + head->next = NULL;
> +}
This patch adds a call to add_to_failed_list(), but no call to
free_failed_list(), so at first glance, this patch appears to introduce
a leak. I see that it actually doesn't because you pass around a NULL
'fail_head', so you never actually call add_to_failed_list(), but it
would make more sense if you added the alloc and matching free in a
single patch.
> +static void pbus_assign_resources_sorted(const struct pci_bus *bus,
> + struct resource_list_x *fail_head)
> {
> struct pci_dev *dev;
> struct resource *res;
> @@ -58,6 +103,13 @@ static void pbus_assign_resources_sorted
> res = list->res;
> idx = res - &list->dev->resource[0];
> if (pci_assign_resource(list->dev, idx)) {
> + if (fail_head && !pci_is_root_bus(list->dev->bus)) {
> + /*
> + * device need to keep flags and size
> + * for next try
> + */
> + add_to_failed_list(fail_head, list->dev, res);
> + }
> res->start = 0;
> res->end = 0;
> res->flags = 0;
> @@ -575,19 +627,20 @@ void __ref pci_bus_size_bridges(struct p
> }
> EXPORT_SYMBOL(pci_bus_size_bridges);
>
> -void __ref pci_bus_assign_resources(const struct pci_bus *bus)
> +static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
> + struct resource_list_x *fail_head)
> {
> struct pci_bus *b;
> struct pci_dev *dev;
>
> - pbus_assign_resources_sorted(bus);
> + pbus_assign_resources_sorted(bus, fail_head);
>
> list_for_each_entry(dev, &bus->devices, bus_list) {
> b = dev->subordinate;
> if (!b)
> continue;
>
> - pci_bus_assign_resources(b);
> + __pci_bus_assign_resources(b, fail_head);
>
> switch (dev->class >> 8) {
> case PCI_CLASS_BRIDGE_PCI:
> @@ -605,6 +658,11 @@ void __ref pci_bus_assign_resources(cons
> }
> }
> }
> +
> +void __ref pci_bus_assign_resources(const struct pci_bus *bus)
> +{
> + __pci_bus_assign_resources(bus, NULL);
> +}
> EXPORT_SYMBOL(pci_bus_assign_resources);
>
> static void release_child_resources(struct resource *r)
>
>
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2
2009-12-20 23:45 ` Bjorn Helgaas
@ 2009-12-21 1:44 ` Yinghai Lu
0 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-21 1:44 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Bjorn Helgaas wrote:
> On Fri, 2009-12-18 at 12:55 -0800, Yinghai Lu wrote:
>> so later we can do sth with those failed one
>>
>> -v2: store start, end, flags aside. so could keep res cleared when assign
>> failed. and make following assignment of its children do not go wild
>>
>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>>
>> ---
>> drivers/pci/setup-bus.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 62 insertions(+), 4 deletions(-)
>>
>> Index: linux-2.6/drivers/pci/setup-bus.c
>> ===================================================================
>> --- linux-2.6.orig/drivers/pci/setup-bus.c
>> +++ linux-2.6/drivers/pci/setup-bus.c
>> @@ -27,7 +27,52 @@
>> #include <linux/slab.h>
>> #include "pci.h"
>>
>> -static void pbus_assign_resources_sorted(const struct pci_bus *bus)
>> +struct resource_list_x {
>> + struct resource_list_x *next;
>> + struct resource *res;
>> + struct pci_dev *dev;
>> + resource_size_t start;
>> + resource_size_t end;
>> + unsigned long flags;
>> +};
>> +
>> +static void add_to_failed_list(struct resource_list_x *head,
>> + struct pci_dev *dev, struct resource *res)
>> +{
>> + struct resource_list_x *list = head;
>> + struct resource_list_x *ln = list->next;
>> + struct resource_list_x *tmp;
>> +
>> + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
>> + if (!tmp) {
>> + pr_warning("add_to_failed_list: kmalloc() failed!\n");
>> + return;
>> + }
>> +
>> + tmp->next = ln;
>> + tmp->res = res;
>> + tmp->dev = dev;
>> + tmp->start = res->start;
>> + tmp->end = res->end;
>> + tmp->flags = res->flags;
>> + list->next = tmp;
>> +}
>> +
>> +static void free_failed_list(struct resource_list_x *head)
>> +{
>> + struct resource_list_x *list, *tmp;
>> +
>> + for (list = head->next; list;) {
>> + tmp = list;
>> + list = list->next;
>> + kfree(tmp);
>> + }
>> +
>> + head->next = NULL;
>> +}
>
> This patch adds a call to add_to_failed_list(), but no call to
> free_failed_list(), so at first glance, this patch appears to introduce
> a leak. I see that it actually doesn't because you pass around a NULL
> 'fail_head', so you never actually call add_to_failed_list(), but it
> would make more sense if you added the alloc and matching free in a
> single patch.
free_failed_list will free them all.
YH
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 5/12] pci: update leaf bridge res to get more big range in pci assign unssign -v3
[not found] <4B2BE9DD.3040504@kernel.org>
` (3 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 4/12] pci: add failed_list to record failed one for pci_bus_assign_resources -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 6/12] pci: don't shrink bridge resources Yinghai Lu
` (6 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
BIOS separate IO range between several IOHs, and on some slots, BIOS assign the resource to the bridge, but stop
assigning resource to the device under that bridge, because the device need big resource.
1. pci assign unassign and record the failed device resource.
2. clear the BIOS assigned resource of the parent bridge of fail device
3. go back and call pci assign unsigned
4. if it still fail, will go up more bridges. and clear and try again.
use pci_try_num to control back track bridge levels.
-v2: update it with resource_list_x
-v3: make pci_try_num default to 1. and when pci_try_num is set to more than 1
will check it with max_depth, and adjust that to make sure it is bigger enough
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/pci.c | 5 ++
drivers/pci/pci.h | 2
drivers/pci/setup-bus.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 123 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -808,11 +808,69 @@ static void pci_bus_dump_resources(struc
}
}
+static int __init pci_bus_get_depth(struct pci_bus *bus)
+{
+ int depth = 0;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ int ret;
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ ret = pci_bus_get_depth(b);
+ if (ret + 1 > depth)
+ depth = ret + 1;
+ }
+
+ return depth;
+}
+static int __init pci_get_max_depth(void)
+{
+ int depth = 0;
+ struct pci_bus *bus;
+
+ list_for_each_entry(bus, &pci_root_buses, node) {
+ int ret;
+
+ ret = pci_bus_get_depth(bus);
+ if (ret > depth)
+ depth = ret;
+ }
+
+ return depth;
+}
+
+/*
+ * first try will not touch pci bridge res
+ * second try will clear small leaf bridge res
+ * third try will clear related bridge: some aggressive
+ */
+int pci_try_num = 1;
void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
+ int tried_times = 0;
+ int check_leaf = 1;
+ struct resource_list_x head, *list;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+ unsigned long failed_type;
+ int max_depth = pci_get_max_depth();
+ head.next = NULL;
+
+ if (pci_try_num > 1) {
+ if (max_depth + 1 > pci_try_num)
+ pci_try_num = max_depth + 1;
+ }
+
+ printk(KERN_DEBUG "PCI: max depth: %d pci_try_num: %d\n",
+ max_depth, pci_try_num);
+
+again:
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) {
@@ -820,7 +878,64 @@ pci_assign_unassigned_resources(void)
}
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node) {
- pci_bus_assign_resources(bus);
+ __pci_bus_assign_resources(bus, &head);
+ }
+ tried_times++;
+
+ /* any device complain? */
+ if (!head.next)
+ goto enable_and_dump;
+ failed_type = 0;
+ for (list = head.next; list;) {
+ failed_type |= list->flags;
+ list = list->next;
+ }
+ /*
+ * io port are tight, don't try extra
+ * or if reach the limit, don't want to try more
+ */
+ failed_type &= type_mask;
+ if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
+ free_failed_list(&head);
+ goto enable_and_dump;
+ }
+
+ printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
+ tried_times + 1);
+
+ /* third times and later will not check if it is leaf */
+ if ((tried_times + 1) > 2)
+ check_leaf = 0;
+
+ /*
+ * Try to release leaf bridge's resources that doesn't fit resource of
+ * child device under that bridge
+ */
+ for (list = head.next; list;) {
+ bus = list->dev->bus;
+ pci_bus_release_unused_bridge_res(bus, list->flags & type_mask,
+ check_leaf);
+ list = list->next;
+ }
+ /* retore size and flags */
+ for (list = head.next; list;) {
+ struct resource *res = list->res;
+
+ res->start = list->start;
+ res->end = list->end;
+ res->flags = list->flags;
+ if (list->dev->subordinate)
+ res->flags = 0;
+
+ list = list->next;
+ }
+ free_failed_list(&head);
+
+ goto again;
+
+enable_and_dump:
+ /* Depth last, update the hardware. */
+ list_for_each_entry(bus, &pci_root_buses, node) {
pci_enable_bridges(bus);
}
Index: linux-2.6/drivers/pci/pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/pci.c
+++ linux-2.6/drivers/pci/pci.c
@@ -2816,6 +2816,11 @@ static int __init pci_setup(char *str)
pci_no_aer();
} else if (!strcmp(str, "nodomains")) {
pci_no_domains();
+ } else if (!strncmp(str, "try=", 4)) {
+ int try_num = memparse(str + 4, &str);
+
+ if (try_num > 0 && try_num < 16)
+ pci_try_num = try_num;
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
Index: linux-2.6/drivers/pci/pci.h
===================================================================
--- linux-2.6.orig/drivers/pci/pci.h
+++ linux-2.6/drivers/pci/pci.h
@@ -203,6 +203,8 @@ static inline int pci_ari_enabled(struct
return bus->self && bus->self->ari_enabled;
}
+extern int pci_try_num;
+
#ifdef CONFIG_PCI_QUIRKS
extern int pci_is_reassigndev(struct pci_dev *dev);
resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 6/12] pci: don't shrink bridge resources
[not found] <4B2BE9DD.3040504@kernel.org>
` (4 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 5/12] pci: update leaf bridge res to get more big range in pci assign unssign -v3 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 7/12] pci: introduce pci_assign_unassigned_bridge_resources -v2 Yinghai Lu
` (5 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
when we are clearing leaf bridge resource and try to get big one, we could shrink the bridge if
there is no resource under it.
let check with old resource size and make sure we are trying to get big one.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -390,7 +390,7 @@ static void pbus_size_io(struct pci_bus
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
- unsigned long size = 0, size1 = 0;
+ unsigned long size = 0, size1 = 0, old_size;
if (!b_res)
return;
@@ -415,17 +415,18 @@ static void pbus_size_io(struct pci_bus
}
if (size < min_size)
size = min_size;
+ old_size = resource_size(b_res);
+ if (old_size == 1)
+ old_size = 0;
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
size = ALIGN(size + size1, 4096);
+ if (size < old_size)
+ size = old_size;
if (!size) {
- if (b_res->start || b_res->end)
- dev_info(&bus->self->dev, "disabling bridge window "
- "%pR to [bus %02x-%02x] (unused)\n", b_res,
- bus->secondary, bus->subordinate);
b_res->flags = 0;
return;
}
@@ -441,7 +442,7 @@ static int pbus_size_mem(struct pci_bus
unsigned long type, resource_size_t min_size)
{
struct pci_dev *dev;
- resource_size_t min_align, align, size;
+ resource_size_t min_align, align, size, old_size;
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@@ -491,6 +492,11 @@ static int pbus_size_mem(struct pci_bus
}
if (size < min_size)
size = min_size;
+ old_size = resource_size(b_res);
+ if (old_size == 1)
+ old_size = 0;
+ if (size < old_size)
+ size = old_size;
align = 0;
min_align = 0;
@@ -507,10 +513,6 @@ static int pbus_size_mem(struct pci_bus
}
size = ALIGN(size, min_align);
if (!size) {
- if (b_res->start || b_res->end)
- dev_info(&bus->self->dev, "disabling bridge window "
- "%pR to [bus %02x-%02x] (unused)\n", b_res,
- bus->secondary, bus->subordinate);
b_res->flags = 0;
return 1;
}
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 7/12] pci: introduce pci_assign_unassigned_bridge_resources -v2
[not found] <4B2BE9DD.3040504@kernel.org>
` (5 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 6/12] pci: don't shrink bridge resources Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 8/12] pci: pciehp clean flow in pciehp_configure_device Yinghai Lu
` (4 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
for pciehp to use it later
pci_setup_bridge() will not check enabled for the slot bridge, otherwise
update res is not updated to bridge BAR. that is bridge is enabled already for
port service.
-v2: update it with resource_list_x
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---
include/linux/pci.h | 1
2 files changed, 90 insertions(+), 4 deletions(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -71,6 +71,50 @@ static void free_failed_list(struct reso
head->next = NULL;
}
+static void pdev_assign_resources_sorted(struct pci_dev *dev,
+ struct resource_list_x *fail_head)
+{
+ struct resource *res;
+ struct resource_list head, *list, *tmp;
+ int idx;
+ u16 class = dev->class >> 8;
+
+ head.next = NULL;
+
+ /* Don't touch classless devices or host bridges or ioapics. */
+ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
+ return;
+
+ /* Don't touch ioapic devices already enabled by firmware */
+ if (class == PCI_CLASS_SYSTEM_PIC) {
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ return;
+ }
+
+ pdev_sort_resources(dev, &head);
+
+ for (list = head.next; list;) {
+ res = list->res;
+ idx = res - &list->dev->resource[0];
+ if (pci_assign_resource(list->dev, idx)) {
+ if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+ /*
+ * device need to keep flags and size
+ * for second try
+ */
+ add_to_failed_list(fail_head, list->dev, res);
+ }
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ }
+ tmp = list;
+ list = list->next;
+ kfree(tmp);
+ }
+}
static void pbus_assign_resources_sorted(const struct pci_bus *bus,
struct resource_list_x *fail_head)
{
@@ -281,9 +325,6 @@ static void __pci_setup_bridge(struct pc
{
struct pci_dev *bridge = bus->self;
- if (pci_is_enabled(bridge))
- return;
-
dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
bus->secondary, bus->subordinate);
@@ -646,7 +687,8 @@ static void __ref __pci_bus_assign_resou
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
- pci_setup_bridge(b);
+ if (!pci_is_enabled(dev))
+ pci_setup_bridge(b);
break;
case PCI_CLASS_BRIDGE_CARDBUS:
@@ -667,6 +709,34 @@ void __ref pci_bus_assign_resources(cons
}
EXPORT_SYMBOL(pci_bus_assign_resources);
+static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
+ struct resource_list_x *fail_head)
+{
+ struct pci_bus *b;
+
+ pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+
+ b = bridge->subordinate;
+ if (!b)
+ return;
+
+ __pci_bus_assign_resources(b, fail_head);
+
+ switch (bridge->class >> 8) {
+ case PCI_CLASS_BRIDGE_PCI:
+ pci_setup_bridge(b);
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ pci_setup_cardbus(b);
+ break;
+
+ default:
+ dev_info(&bridge->dev, "not setting up bridge for bus "
+ "%04x:%02x\n", pci_domain_nr(b), b->number);
+ break;
+ }
+}
static void release_child_resources(struct resource *r)
{
struct resource *p;
@@ -946,3 +1016,18 @@ enable_and_dump:
pci_bus_dump_resources(bus);
}
}
+
+void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
+{
+ struct pci_bus *bus;
+ struct pci_bus *parent = bridge->subordinate;
+ int retval;
+
+ pci_bus_size_bridges(parent);
+ pci_clear_master(bridge);
+ __pci_bridge_assign_resources(bridge, NULL);
+ retval = pci_reenable_device(bridge);
+ pci_set_master(bridge);
+ pci_enable_bridges(parent);
+}
+EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -771,6 +771,7 @@ void pci_bus_assign_resources(const stru
void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
+void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pdev_enable_device(struct pci_dev *);
void pdev_sort_resources(struct pci_dev *, struct resource_list *);
int pci_enable_resources(struct pci_dev *, int mask);
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 8/12] pci: pciehp clean flow in pciehp_configure_device
[not found] <4B2BE9DD.3040504@kernel.org>
` (6 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 7/12] pci: introduce pci_assign_unassigned_bridge_resources -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 9/12] pci: pciehp second try to get big range for pcie devices -v2 Yinghai Lu
` (3 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
move out bus_size_bridges and assign resources out of pciehp_add_bridge()
and at last do them all together one time including slot bridge, to avoid to
call assign resources several times, when there are several bridges under the
slot bridge.
use pci_assign_nassigned_bridge_resources
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/hotplug/pciehp_pci.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
Index: linux-2.6/drivers/pci/hotplug/pciehp_pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_pci.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_pci.c
@@ -53,17 +53,15 @@ static int __ref pciehp_add_bridge(struc
busnr = pci_scan_bridge(parent, dev, busnr, pass);
if (!dev->subordinate)
return -1;
- pci_bus_size_bridges(dev->subordinate);
- pci_bus_assign_resources(parent);
- pci_enable_bridges(parent);
- pci_bus_add_devices(parent);
+
return 0;
}
int pciehp_configure_device(struct slot *p_slot)
{
struct pci_dev *dev;
- struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate;
+ struct pci_dev *bridge = p_slot->ctrl->pcie->port;
+ struct pci_bus *parent = bridge->subordinate;
int num, fn;
struct controller *ctrl = p_slot->ctrl;
@@ -96,12 +94,25 @@ int pciehp_configure_device(struct slot
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
pciehp_add_bridge(dev);
}
+ pci_dev_put(dev);
+ }
+
+ pci_assign_unassigned_bridge_resources(bridge);
+
+ for (fn = 0; fn < 8; fn++) {
+ dev = pci_get_slot(parent, PCI_DEVFN(0, fn));
+ if (!dev)
+ continue;
+ if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+ pci_dev_put(dev);
+ continue;
+ }
pci_configure_slot(dev);
pci_dev_put(dev);
}
- pci_bus_assign_resources(parent);
pci_bus_add_devices(parent);
+
return 0;
}
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 9/12] pci: pciehp second try to get big range for pcie devices -v2
[not found] <4B2BE9DD.3040504@kernel.org>
` (7 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 8/12] pci: pciehp clean flow in pciehp_configure_device Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 10/12] pci: pci_bridge_release_res -v2 Yinghai Lu
` (2 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
handle the case the slot bridge that doesn't get pre-allocated big enough res
from FW.
for example pcie devices need 256M, but the bridge only get preallocated 2M...
-v2: use resource_list_x
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -1021,13 +1021,60 @@ void pci_assign_unassigned_bridge_resour
{
struct pci_bus *bus;
struct pci_bus *parent = bridge->subordinate;
+ bool second_tried = false;
+ struct resource_list_x head, *list;
int retval;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+ head.next = NULL;
+
+again:
pci_bus_size_bridges(parent);
pci_clear_master(bridge);
- __pci_bridge_assign_resources(bridge, NULL);
+ __pci_bridge_assign_resources(bridge, &head);
retval = pci_reenable_device(bridge);
pci_set_master(bridge);
pci_enable_bridges(parent);
+
+ /* any device complain? */
+ if (!head.next)
+ return;
+
+ if (second_tried) {
+ /* still fail, don't need to try more */
+ free_failed_list(&head);
+ return;
+ }
+
+ second_tried = true;
+ printk(KERN_DEBUG "PCI: second try to assign unassigned res\n");
+
+ /*
+ * Try to release leaf bridge's resources that doesn't fit resource of
+ * child device under that bridge
+ */
+ for (list = head.next; list;) {
+ unsigned long flags = list->flags;
+
+ bus = list->dev->bus;
+ pci_bus_release_unused_bridge_res(bus, flags & type_mask, 0);
+ list = list->next;
+ }
+ /* retore size and flags */
+ for (list = head.next; list;) {
+ struct resource *res = list->res;
+
+ res->start = list->start;
+ res->end = list->end;
+ res->flags = list->flags;
+ if (list->dev->subordinate)
+ res->flags = 0;
+
+ list = list->next;
+ }
+ free_failed_list(&head);
+
+ goto again;
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 10/12] pci: pci_bridge_release_res -v2
[not found] <4B2BE9DD.3040504@kernel.org>
` (8 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 9/12] pci: pciehp second try to get big range for pcie devices -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 11/12] pciehp: add support for bridge resource reallocation -v2 Yinghai Lu
2009-12-18 20:55 ` [PATCH 12/12] pci: set PCI_PREF_RANGE_TYPE_64 in pci_bridge_check_ranges Yinghai Lu
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
prepare for pciehp_realloc
it will clear the resource size for bridge
-v2: patrick Keller pointed out need to export it...
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 1 +
2 files changed, 44 insertions(+)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -737,6 +737,49 @@ static void __ref __pci_bridge_assign_re
break;
}
}
+
+void pci_bridge_release_res(struct pci_bus *bus)
+{
+ int idx;
+ bool changed = false;
+ struct pci_dev *dev;
+ struct resource *r;
+
+ /* The root bus? */
+ if (!bus->self)
+ return;
+
+ /* for pci bridges res only */
+ dev = bus->self;
+ if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3;
+ idx++) {
+ r = &dev->resource[idx];
+ if (!r->parent)
+ continue;
+
+ /* if there are children under that, we should not release it */
+ if (r->child)
+ continue;
+
+ if (!release_resource(r)) {
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "resource %d %pR released\n", idx, r);
+ /* old size is not kept */
+ r->start = 0;
+ r->end = 0;
+ r->flags = 0;
+ changed = true;
+ }
+ }
+
+ if (changed)
+ pci_setup_bridge(bus);
+}
+EXPORT_SYMBOL_GPL(pci_bridge_release_res);
+
static void release_child_resources(struct resource *r)
{
struct resource *p;
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -770,6 +770,7 @@ int pci_vpd_truncate(struct pci_dev *dev
void pci_bus_assign_resources(const struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
+void pci_bridge_release_res(struct pci_bus *bus);
void pci_assign_unassigned_resources(void);
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pdev_enable_device(struct pci_dev *);
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 11/12] pciehp: add support for bridge resource reallocation -v2
[not found] <4B2BE9DD.3040504@kernel.org>
` (9 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 10/12] pci: pci_bridge_release_res -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
2009-12-18 20:55 ` [PATCH 12/12] pci: set PCI_PREF_RANGE_TYPE_64 in pci_bridge_check_ranges Yinghai Lu
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
With this patch, pciehp driver try to clear PCI bridge resources to
parent bridge (root port or switch downstream port) of the slot
so we can shrink pci bridge resource for those port
This feature is enabled when 'pciehp_realloc' option is specified.
-v2: make it could be appiled after Yinghai patchset that touch pci bridge resource
also remove poweron check, because pci_bridge_release_res will check child at first
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/hotplug/pciehp.h | 1 +
drivers/pci/hotplug/pciehp_core.c | 7 +++++++
drivers/pci/hotplug/pciehp_pci.c | 4 ++++
3 files changed, 12 insertions(+)
Index: linux-2.6/drivers/pci/hotplug/pciehp.h
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp.h
+++ linux-2.6/drivers/pci/hotplug/pciehp.h
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode;
extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
+extern int pciehp_realloc;
extern struct workqueue_struct *pciehp_wq;
#define dbg(format, arg...) \
Index: linux-2.6/drivers/pci/hotplug/pciehp_core.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_core.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_core.c
@@ -41,6 +41,7 @@ int pciehp_debug;
int pciehp_poll_mode;
int pciehp_poll_time;
int pciehp_force;
+int pciehp_realloc;
struct workqueue_struct *pciehp_wq;
#define DRIVER_VERSION "0.4"
@@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644);
module_param(pciehp_poll_mode, bool, 0644);
module_param(pciehp_poll_time, int, 0644);
module_param(pciehp_force, bool, 0644);
+module_param(pciehp_realloc, bool, 0644);
MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_realloc, "Realloc resources for slot's parent bridge");
#define PCIE_MODULE_NAME "pciehp"
@@ -297,6 +300,10 @@ static int pciehp_probe(struct pcie_devi
if (!occupied && poweron && POWER_CTRL(ctrl))
pciehp_power_off_slot(slot);
+ /* Release I/O window of the slots's parent bridge */
+ if (pciehp_realloc)
+ pci_bridge_release_res(dev->port->subordinate);
+
return 0;
err_out_free_ctrl_slot:
Index: linux-2.6/drivers/pci/hotplug/pciehp_pci.c
===================================================================
--- linux-2.6.orig/drivers/pci/hotplug/pciehp_pci.c
+++ linux-2.6/drivers/pci/hotplug/pciehp_pci.c
@@ -166,5 +166,9 @@ int pciehp_unconfigure_device(struct slo
pci_dev_put(temp);
}
+ /* Release I/O window of the slots's parent bridge */
+ if (pciehp_realloc)
+ pci_bridge_release_res(parent);
+
return rc;
}
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 12/12] pci: set PCI_PREF_RANGE_TYPE_64 in pci_bridge_check_ranges
[not found] <4B2BE9DD.3040504@kernel.org>
` (10 preceding siblings ...)
2009-12-18 20:55 ` [PATCH 11/12] pciehp: add support for bridge resource reallocation -v2 Yinghai Lu
@ 2009-12-18 20:55 ` Yinghai Lu
11 siblings, 0 replies; 23+ messages in thread
From: Yinghai Lu @ 2009-12-18 20:55 UTC (permalink / raw)
To: Jesse Barnes, Ingo Molnar, Linus Torvalds, Ivan Kokshaysky,
Kenji Kaneshige, Alex Chiang, Bjorn Helgaas
Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
make pci_bridge_check_ranges() to store the PCI_PREF_RANGE_TYPE_64 in addition
to IORESOURCE_MEM_64. just like pci_read_bridge_bases()
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
drivers/pci/setup-bus.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Index: linux-2.6/drivers/pci/setup-bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/setup-bus.c
+++ linux-2.6/drivers/pci/setup-bus.c
@@ -383,8 +383,10 @@ static void pci_bridge_check_ranges(stru
}
if (pmem) {
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64)
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64){
b_res[2].flags |= IORESOURCE_MEM_64;
+ b_res[2].flags |= PCI_PREF_RANGE_TYPE_64;
+ }
}
/* double check if bridge does support 64 bit pref */
^ permalink raw reply [flat|nested] 23+ messages in thread