2009-11-28 07:41:57

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 9/9] pci: pciehp second try to get big range for pcie devices -v2


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 <[email protected]>

---
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
@@ -985,13 +985,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);


2009-12-01 01:20:14

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 1/2] pci: pci_bridge_release_res

need to apply this after 9/9 patchset

prepare for pciehp_realloc

it will clear the resource size for bridge

Signed-off-by: Yinghai Lu <[email protected]>

---
drivers/pci/setup-bus.c | 42 ++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 1 +
2 files changed, 43 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
@@ -739,6 +739,48 @@ 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);
+}
+
static void release_children_resource(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
@@ -767,6 +767,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 *);

2009-12-01 01:22:13

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH 2/2] pciehp: add support for bridge resource reallocation -v2


From: Kenji Kaneshige <[email protected]>

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
need to apply this one after 9/9 patchset

Signed-off-by: Kenji Kaneshige <[email protected]>
Signed-off-by: Yinghai Lu <[email protected]>

---
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;
}

2009-12-07 21:42:34

by Patrick Keller

[permalink] [raw]
Subject: Re: [PATCH 1/2] pci: pci_bridge_release_res



On Tue, 2009-12-01 at 01:19 +0000, Yinghai Lu wrote:
> need to apply this after 9/9 patchset
>
> prepare for pciehp_realloc
>
> it will clear the resource size for bridge
>
> Signed-off-by: Yinghai Lu <[email protected]>
>
> ---
> drivers/pci/setup-bus.c | 42 ++++++++++++++++++++++++++++++++++++++++++
> include/linux/pci.h | 1 +
> 2 files changed, 43 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
> @@ -739,6 +739,48 @@ 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);
> +}
> +

Need to add EXPORT_SYMBOL(pci_bridge_release_res); here so the hotplug
kernel module will find this function.

> static void release_children_resource(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
> @@ -767,6 +767,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 *);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2009-12-07 21:58:37

by Yinghai Lu

[permalink] [raw]
Subject: Re: [PATCH 1/2] pci: pci_bridge_release_res

Patrick Keller wrote:
>
> On Tue, 2009-12-01 at 01:19 +0000, Yinghai Lu wrote:
>> need to apply this after 9/9 patchset
>>
>> prepare for pciehp_realloc
>>
>> it will clear the resource size for bridge
>>
>> Signed-off-by: Yinghai Lu <[email protected]>
>>
>> ---
>> drivers/pci/setup-bus.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>> include/linux/pci.h | 1 +
>> 2 files changed, 43 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
>> @@ -739,6 +739,48 @@ 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);
>> +}
>> +
>
> Need to add EXPORT_SYMBOL(pci_bridge_release_res); here so the hotplug
> kernel module will find this function.

thanks, will update that in next round.

YH