===================================================================
@@ -27,13 +27,31 @@
#include <linux/slab.h>
#include "pci.h"
-static void pbus_assign_resources_sorted(const struct pci_bus *bus)
+static void pbus_assign_resources_list(struct resource_list *head)
{
- struct pci_dev *dev;
struct resource *res;
- struct resource_list head, *list, *tmp;
+ struct resource_list *list, *tmp;
int idx;
+ for (list = head->next; list;) {
+ res = list->res;
+ idx = res - &list->dev->resource[0];
+ if (pci_assign_resource(list->dev, idx)) {
+ 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 pci_dev *dev;
+ struct resource_list head;
+
head.next = NULL;
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
@@ -54,18 +72,7 @@ static void pbus_assign_resources_sorted
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)) {
- res->start = 0;
- res->end = 0;
- res->flags = 0;
- }
- tmp = list;
- list = list->next;
- kfree(tmp);
- }
+ pbus_assign_resources_list(&head);
}
void pci_setup_cardbus(struct pci_bus *bus)
@@ -142,9 +149,6 @@ static void pci_setup_bridge(struct pci_
u32 l, bu, lu, io_upper16;
int pref_mem64;
- if (pci_is_enabled(bridge))
- return;
-
dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
bus->secondary, bus->subordinate);
@@ -559,7 +563,8 @@ void __ref pci_bus_assign_resources(cons
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:
@@ -575,6 +580,47 @@ void __ref pci_bus_assign_resources(cons
}
EXPORT_SYMBOL(pci_bus_assign_resources);
+void __ref pci_bridge_assign_resources(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ struct resource_list head;
+
+ if (pci_is_root_bus(bus) ||
+ (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ head.next = NULL;
+ pdev_sort_resources(bridge, &head);
+ pbus_assign_resources_list(&head);
+ pci_bus_assign_resources(bus);
+ pci_setup_bridge(bus);
+}
+EXPORT_SYMBOL(pci_bridge_assign_resources);
+
+void __ref pci_bridge_release_window(struct pci_bus *bus)
+{
+ struct pci_dev *bridge = bus->self;
+ int i;
+
+ if (pci_is_root_bus(bus) ||
+ (bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ for (i = 0; i < 3; i++)
+ if (bus->resource[i]->child)
+ return;
+
+ for (i = 0; i < 3; i++)
+ bus->resource[i]->flags = 0;
+
+ pci_setup_bridge(bus);
+
+ for (i = 0; i < 3; i++)
+ if (bus->resource[i]->parent)
+ release_resource(bus->resource[i]);
+}
+EXPORT_SYMBOL(pci_bridge_release_window);
+
static void pci_bus_dump_res(struct pci_bus *bus)
{
int i;
===================================================================
@@ -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,13 @@ 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"
@@ -293,10 +297,15 @@ static int pciehp_probe(struct pcie_devi
pciehp_get_power_status(slot, &poweron);
if (occupied && pciehp_force)
pciehp_enable_slot(slot);
+
/* If empty slot's power status is on, turn power off */
if (!occupied && poweron && POWER_CTRL(ctrl))
pciehp_power_off_slot(slot);
+ /* If no device is running on the slot, release bridge's I/O window */
+ if (pciehp_realloc && !poweron)
+ pci_bridge_release_window(dev->port->subordinate);
+
return 0;
err_out_free_ctrl_slot:
===================================================================
@@ -97,7 +97,10 @@ int pciehp_configure_device(struct slot
}
pci_bus_size_bridges(parent);
- pci_bus_assign_resources(parent);
+ if (pciehp_realloc)
+ pci_bridge_assign_resources(parent);
+ else
+ pci_bus_assign_resources(parent);
pci_enable_bridges(parent);
pci_bus_add_devices(parent);
return 0;
@@ -153,5 +156,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_window(parent);
+
return rc;
}
===================================================================
@@ -764,6 +764,8 @@ int pci_vpd_truncate(struct pci_dev *dev
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
void pci_bus_assign_resources(const struct pci_bus *bus);
+void pci_bridge_assign_resources(struct pci_bus *bus);
+void pci_bridge_release_window(struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int);
void pci_assign_unassigned_resources(void);
===================================================================
@@ -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...) \