diff mbox

[2/2] pciehp: add support for bridge resource reallocation

Message ID 4B0D148C.6020302@jp.fujitsu.com (mailing list archive)
State RFC, archived
Headers show

Commit Message

Kenji Kaneshige Nov. 25, 2009, 11:27 a.m. UTC
None
diff mbox

Patch

Index: 20091125/drivers/pci/setup-bus.c
===================================================================
--- 20091125.orig/drivers/pci/setup-bus.c
+++ 20091125/drivers/pci/setup-bus.c
@@ -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;
Index: 20091125/drivers/pci/hotplug/pciehp_core.c
===================================================================
--- 20091125.orig/drivers/pci/hotplug/pciehp_core.c
+++ 20091125/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,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:
Index: 20091125/drivers/pci/hotplug/pciehp_pci.c
===================================================================
--- 20091125.orig/drivers/pci/hotplug/pciehp_pci.c
+++ 20091125/drivers/pci/hotplug/pciehp_pci.c
@@ -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;
 }
Index: 20091125/include/linux/pci.h
===================================================================
--- 20091125.orig/include/linux/pci.h
+++ 20091125/include/linux/pci.h
@@ -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);
Index: 20091125/drivers/pci/hotplug/pciehp.h
===================================================================
--- 20091125.orig/drivers/pci/hotplug/pciehp.h
+++ 20091125/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...)						\