aboutsummaryrefslogtreecommitdiffstats
path: root/pci
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-01-17 17:29:22 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-17 17:29:22 -0800
commitf88df26c66503b2782e54f6d08a227313710baed (patch)
treea16409f1ed0c2352dd52d2af6f1e2c995780c0c2 /pci
parente86084aa82842642c723e5eee6cb67716cb61b43 (diff)
downloadpatches-f88df26c66503b2782e54f6d08a227313710baed.tar.gz
4 pci patches
Diffstat (limited to 'pci')
-rw-r--r--pci/pci-hotplug-acpiphp-handle-dock-bridges.patch330
-rw-r--r--pci/pci-hotplug-convert-semaphores-to-mutex.patch34
-rw-r--r--pci/pci-quirk-for-ibm-dock-ii-cardbus-controllers.patch54
-rw-r--r--pci/pci-really-fix-parent-s-subordinate-busnr.patch33
-rw-r--r--pci/pci-return-max-reserved-busnr.patch58
5 files changed, 501 insertions, 8 deletions
diff --git a/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch b/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch
new file mode 100644
index 0000000000000..6e828b9da83ec
--- /dev/null
+++ b/pci/pci-hotplug-acpiphp-handle-dock-bridges.patch
@@ -0,0 +1,330 @@
+From kristen.c.accardi@intel.com Tue Jan 17 16:54:09 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: PCI Hotplug: acpiphp: handle dock bridges
+Cc: <len.brown@intel.com>, <pavel@ucw.cz>
+Date: Tue, 17 Jan 2006 16:56:59 -0800
+Message-Id: <1137545819.19858.47.camel@whizzy>
+
+This patch will modify the acpiphp driver to handle docking and undocking
+events and hot adding of the PCI devices on the dock station. It currently
+has a workaround for a problem with acpi where the
+acpi threads will deadlock and never return from executing the _DCK method.
+As a workaround, I spawn a separate thread to do the dock. In addition,
+I've found that some _DCK methods do some bad things, so have implemented
+a fixups section for after docking that will no doubt grow as more laptops
+get tested. This patch CONFLICTS with some acpi plugins that try to do
+their own docking support (such as ibm_acpi), so you cannot use this driver
+and the conflicting driver simultaneously.
+
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/pci/hotplug/acpiphp.h | 2
+ drivers/pci/hotplug/acpiphp_glue.c | 207 ++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 204 insertions(+), 5 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h
+@@ -188,6 +188,7 @@ struct acpiphp_attention_info
+ #define SLOT_POWEREDON (0x00000001)
+ #define SLOT_ENABLED (0x00000002)
+ #define SLOT_MULTIFUNCTION (0x00000004)
++#define SLOT_DOCKING (0x00000008)
+
+ /* function flags */
+
+@@ -197,6 +198,7 @@ struct acpiphp_attention_info
+ #define FUNC_HAS_PS1 (0x00000020)
+ #define FUNC_HAS_PS2 (0x00000040)
+ #define FUNC_HAS_PS3 (0x00000080)
++#define FUNC_HAS_DCK (0x00000100)
+
+ /* function prototypes */
+
+--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp_glue.c
++++ gregkh-2.6/drivers/pci/hotplug/acpiphp_glue.c
+@@ -55,12 +55,14 @@
+ static LIST_HEAD(bridge_list);
+
+ #define MY_NAME "acpiphp_glue"
+-
++static struct work_struct dock_task;
++static int enable_device(struct acpiphp_slot *slot);
+ static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+ static void handle_hotplug_event_func (acpi_handle, u32, void *);
+ static void acpiphp_sanitize_bus(struct pci_bus *bus);
+ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
+-
++static void dock(void *data);
++static unsigned int get_slot_status(struct acpiphp_slot *slot);
+
+ /*
+ * initialization & terminatation routines
+@@ -118,6 +120,30 @@ is_ejectable_slot(acpi_handle handle, u3
+ }
+
+
++static acpi_status handle_dock(struct acpiphp_func *func, int dock)
++{
++ acpi_status status;
++ struct acpi_object_list arg_list;
++ union acpi_object arg;
++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
++
++ dbg("%s: enter\n", __FUNCTION__);
++
++ /* _DCK method has one argument */
++ arg_list.count = 1;
++ arg_list.pointer = &arg;
++ arg.type = ACPI_TYPE_INTEGER;
++ arg.integer.value = dock;
++ status = acpi_evaluate_object(func->handle, "_DCK",
++ &arg_list, &buffer);
++ if (ACPI_FAILURE(status))
++ err("%s: failed to dock!!\n", MY_NAME);
++
++ return status;
++}
++
++
++
+ /* callback routine to register each ACPI PCI slot object */
+ static acpi_status
+ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+@@ -210,6 +236,12 @@ register_slot(acpi_handle handle, u32 lv
+ slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+ }
+
++ /* install dock notify handler */
++ if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) {
++ newfunc->flags |= FUNC_HAS_DCK;
++ INIT_WORK(&dock_task, dock, slot);
++ }
++
+ /* install notify handler */
+ status = acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+@@ -681,6 +713,88 @@ static int acpiphp_configure_ioapics(acp
+ return 0;
+ }
+
++/*
++ * the _DCK method can do funny things... and sometimes not
++ * hah-hah funny.
++ */
++static void post_dock_fixups(struct acpiphp_slot *slot,
++ struct acpiphp_func *func)
++{
++ struct pci_bus *bus = slot->bridge->pci_bus;
++ u32 buses;
++
++ /* fixup bad _DCK function that rewrites
++ * secondary bridge on slot
++ */
++ pci_read_config_dword(bus->self,
++ PCI_PRIMARY_BUS,
++ &buses);
++
++ if (((buses >> 8) & 0xff) != bus->secondary) {
++ buses = (buses & 0xff000000)
++ | ((unsigned int)(bus->primary) << 0)
++ | ((unsigned int)(bus->secondary) << 8)
++ | ((unsigned int)(bus->subordinate) << 16);
++ pci_write_config_dword(bus->self,
++ PCI_PRIMARY_BUS,
++ buses);
++ }
++}
++
++
++static int acpiphp_bus_add(struct acpiphp_func *func)
++{
++ acpi_handle phandle;
++ struct acpi_device *device, *pdevice;
++ int ret_val;
++
++ acpi_get_parent(func->handle, &phandle);
++ if (acpi_bus_get_device(phandle, &pdevice)) {
++ dbg("no parent device, assuming NULL\n");
++ pdevice = NULL;
++ }
++ ret_val = acpi_bus_add(&device, pdevice, func->handle,
++ ACPI_BUS_TYPE_DEVICE);
++ if (ret_val)
++ dbg("cannot add bridge to acpi list\n");
++
++ /*
++ * try to start anyway. We could have failed to add
++ * simply because this bus had previously been added
++ * on another dock. Don't bother with the return value
++ * we just keep going.
++ */
++ ret_val = acpi_bus_start(device);
++
++ return ret_val;
++}
++
++
++
++static void dock(void *data)
++{
++ struct list_head *l;
++ struct acpiphp_func *func;
++ struct acpiphp_slot *slot = data;
++
++ down(&slot->crit_sect);
++ list_for_each(l, &slot->funcs) {
++ func = list_entry(l, struct acpiphp_func, sibling);
++ if (func->flags & FUNC_HAS_DCK) {
++ handle_dock(func, 1);
++ post_dock_fixups(slot, func);
++ slot->flags |= SLOT_POWEREDON;
++ if (get_slot_status(slot) == ACPI_STA_ALL) {
++ enable_device(slot);
++ }
++ }
++ }
++ slot->flags &= (~SLOT_DOCKING);
++ up(&slot->crit_sect);
++}
++
++
++
+ static int power_on_slot(struct acpiphp_slot *slot)
+ {
+ acpi_status status;
+@@ -705,6 +819,19 @@ static int power_on_slot(struct acpiphp_
+ } else
+ break;
+ }
++
++ if (func->flags & FUNC_HAS_DCK) {
++ dbg("%s: executing _DCK\n", __FUNCTION__);
++ slot->flags |= SLOT_DOCKING;
++ /*
++ * FIXME - work around for acpi. Right
++ * now if we call _DCK from this thread,
++ * we block forever.
++ */
++ schedule_work(&dock_task);
++ retval = -1;
++ goto err_exit;
++ }
+ }
+
+ /* TBD: evaluate _STA to check if the slot is enabled */
+@@ -730,7 +857,11 @@ static int power_off_slot(struct acpiphp
+
+ list_for_each (l, &slot->funcs) {
+ func = list_entry(l, struct acpiphp_func, sibling);
+-
++ if (func->flags & FUNC_HAS_DCK) {
++ dbg("%s: undock commencing\n", __FUNCTION__);
++ handle_dock(func, 0);
++ dbg("%s: undock complete\n", __FUNCTION__);
++ }
+ if (func->flags & FUNC_HAS_PS3) {
+ status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+@@ -752,6 +883,63 @@ static int power_off_slot(struct acpiphp
+
+
+ /**
++ * get_func - given pci_dev & slot, get the matching acpiphp_func
++ * @slot: slot to be scanned.
++ * @dev: pci_dev to match
++ *
++ * This function will check the list of acpiphp functions for
++ * this slot and return the one that represents the given
++ * pci_dev structure.
++ */
++static struct acpiphp_func * get_func(struct acpiphp_slot *slot,
++ struct pci_dev *dev)
++{
++ struct list_head *l;
++ struct acpiphp_func *func;
++ struct pci_bus *bus = slot->bridge->pci_bus;
++
++ list_for_each (l, &slot->funcs) {
++ func = list_entry(l, struct acpiphp_func, sibling);
++ if (pci_get_slot(bus, PCI_DEVFN(slot->device,
++ func->function)) == dev)
++ return func;
++ }
++ return NULL;
++}
++
++
++
++/** acpiphp_max_busnr - find the max reserved busnr for this bus
++ * @bus: the bus to scan
++ */
++static unsigned char
++acpiphp_max_busnr(struct pci_bus *bus)
++{
++ struct list_head *tmp;
++ unsigned char max, n;
++
++ /*
++ * pci_bus_max_busnr will return the highest
++ * reserved busnr for all these children.
++ * that is equivalent to the bus->subordinate
++ * value. We don't want to use the parent's
++ * bus->subordinate value because it could have
++ * padding in it.
++ */
++ max = bus->secondary;
++
++ list_for_each(tmp, &bus->children) {
++ n = pci_bus_max_busnr(pci_bus_b(tmp));
++ if (n > max)
++ max = n;
++ }
++ return max;
++}
++
++
++
++
++/**
+ * enable_device - enable, configure a slot
+ * @slot: slot to be enabled
+ *
+@@ -788,7 +976,7 @@ static int enable_device(struct acpiphp_
+ goto err_exit;
+ }
+
+- max = bus->secondary;
++ max = acpiphp_max_busnr(bus);
+ for (pass = 0; pass < 2; pass++) {
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (PCI_SLOT(dev->devfn) != slot->device)
+@@ -796,8 +984,12 @@ static int enable_device(struct acpiphp_
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
+ max = pci_scan_bridge(bus, dev, max, pass);
+- if (pass && dev->subordinate)
++ if (pass && dev->subordinate) {
+ pci_bus_size_bridges(dev->subordinate);
++ func = get_func(slot, dev);
++ if (func)
++ acpiphp_bus_add(func);
++ }
+ }
+ }
+ }
+@@ -1231,6 +1423,11 @@ static void handle_hotplug_event_func(ac
+
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ /* request device eject */
++ if (func->slot->flags & SLOT_DOCKING) {
++ /* ignore if we are in the middle of docking */
++ dbg("eject request in the middle of a dock\n");
++ break;
++ }
+ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
+ if (!(acpiphp_disable_slot(func->slot)))
+ acpiphp_eject_slot(func->slot);
diff --git a/pci/pci-hotplug-convert-semaphores-to-mutex.patch b/pci/pci-hotplug-convert-semaphores-to-mutex.patch
index 3f00c231d51dc..a40cbb1b8fa9e 100644
--- a/pci/pci-hotplug-convert-semaphores-to-mutex.patch
+++ b/pci/pci-hotplug-convert-semaphores-to-mutex.patch
@@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/pci/hotplug/acpiphp.h | 3 -
- drivers/pci/hotplug/acpiphp_glue.c | 12 ++--
+ drivers/pci/hotplug/acpiphp_glue.c | 16 +++---
drivers/pci/hotplug/cpqphp.h | 3 -
drivers/pci/hotplug/cpqphp_core.c | 14 ++---
drivers/pci/hotplug/cpqphp_ctrl.c | 56 ++++++++++-----------
@@ -34,7 +34,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/hotplug/shpchp.h | 3 -
drivers/pci/hotplug/shpchp_ctrl.c | 98 ++++++++++++++++++-------------------
drivers/pci/hotplug/shpchp_hpc.c | 2
- 13 files changed, 143 insertions(+), 137 deletions(-)
+ 13 files changed, 145 insertions(+), 139 deletions(-)
--- gregkh-2.6.orig/drivers/pci/hotplug/acpiphp.h
+++ gregkh-2.6/drivers/pci/hotplug/acpiphp.h
@@ -66,7 +66,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
#include "../pci.h"
#include "pci_hotplug.h"
-@@ -188,7 +188,7 @@ register_slot(acpi_handle handle, u32 lv
+@@ -214,7 +214,7 @@ register_slot(acpi_handle handle, u32 lv
slot->device = device;
slot->sun = sun;
INIT_LIST_HEAD(&slot->funcs);
@@ -75,7 +75,25 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
slot->next = bridge->slots;
bridge->slots = slot;
-@@ -1401,7 +1401,7 @@ int acpiphp_enable_slot(struct acpiphp_s
+@@ -777,7 +777,7 @@ static void dock(void *data)
+ struct acpiphp_func *func;
+ struct acpiphp_slot *slot = data;
+
+- down(&slot->crit_sect);
++ mutex_lock(&slot->crit_sect);
+ list_for_each(l, &slot->funcs) {
+ func = list_entry(l, struct acpiphp_func, sibling);
+ if (func->flags & FUNC_HAS_DCK) {
+@@ -790,7 +790,7 @@ static void dock(void *data)
+ }
+ }
+ slot->flags &= (~SLOT_DOCKING);
+- up(&slot->crit_sect);
++ mutex_unlock(&slot->crit_sect);
+ }
+
+
+@@ -1598,7 +1598,7 @@ int acpiphp_enable_slot(struct acpiphp_s
{
int retval;
@@ -84,7 +102,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* wake up all functions */
retval = power_on_slot(slot);
-@@ -1413,7 +1413,7 @@ int acpiphp_enable_slot(struct acpiphp_s
+@@ -1610,7 +1610,7 @@ int acpiphp_enable_slot(struct acpiphp_s
retval = enable_device(slot);
err_exit:
@@ -93,7 +111,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
return retval;
}
-@@ -1424,7 +1424,7 @@ int acpiphp_disable_slot(struct acpiphp_
+@@ -1621,7 +1621,7 @@ int acpiphp_disable_slot(struct acpiphp_
{
int retval = 0;
@@ -102,7 +120,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
/* unconfigure all functions */
retval = disable_device(slot);
-@@ -1437,7 +1437,7 @@ int acpiphp_disable_slot(struct acpiphp_
+@@ -1634,7 +1634,7 @@ int acpiphp_disable_slot(struct acpiphp_
goto err_exit;
err_exit:
@@ -1182,7 +1200,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
p_slot->is_a_board = 1;
-@@ -915,27 +915,27 @@ int shpchp_disable_slot (struct slot *p_
+@@ -925,27 +925,27 @@ int shpchp_disable_slot (struct slot *p_
return -ENODEV;
/* Check to see if (latch closed, card present, power on) */
diff --git a/pci/pci-quirk-for-ibm-dock-ii-cardbus-controllers.patch b/pci/pci-quirk-for-ibm-dock-ii-cardbus-controllers.patch
new file mode 100644
index 0000000000000..008a53a89228e
--- /dev/null
+++ b/pci/pci-quirk-for-ibm-dock-ii-cardbus-controllers.patch
@@ -0,0 +1,54 @@
+From kristen.c.accardi@intel.com Tue Jan 17 16:54:13 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: PCI: quirk for IBM Dock II cardbus controllers
+Cc: <len.brown@intel.com>, <pavel@ucw.cz>
+Date: Tue, 17 Jan 2006 16:57:04 -0800
+Message-Id: <1137545824.19858.49.camel@whizzy>
+
+The IBM Dock II cardbus bridges require some extra configuration
+before Yenta is loaded in order to setup the Interrupts to be
+routed properly.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/pci/quirks.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- gregkh-2.6.orig/drivers/pci/quirks.c
++++ gregkh-2.6/drivers/pci/quirks.c
+@@ -1239,6 +1239,33 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IN
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_pcie_pxh);
+
+
++/*
++ * Fixup the cardbus bridges on the IBM Dock II docking station
++ */
++static void __devinit quirk_ibm_dock2_cardbus(struct pci_dev *dev)
++{
++ u32 val;
++
++ /*
++ * tie the 2 interrupt pins to INTA, and configure the
++ * multifunction routing register to handle this.
++ */
++ if ((dev->subsystem_vendor == PCI_VENDOR_ID_IBM) &&
++ (dev->subsystem_device == 0x0148)) {
++ printk(KERN_INFO "PCI: Found IBM Dock II Cardbus Bridge "
++ "applying quirk\n");
++ pci_read_config_dword(dev, 0x8c, &val);
++ val = ((val & 0xffffff00) | 0x1002);
++ pci_write_config_dword(dev, 0x8c, val);
++ pci_read_config_dword(dev, 0x80, &val);
++ val = ((val & 0x00ffff00) | 0x2864c077);
++ pci_write_config_dword(dev, 0x80, val);
++ }
++}
++
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420,
++ quirk_ibm_dock2_cardbus);
++
+ static void __devinit quirk_netmos(struct pci_dev *dev)
+ {
+ unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
diff --git a/pci/pci-really-fix-parent-s-subordinate-busnr.patch b/pci/pci-really-fix-parent-s-subordinate-busnr.patch
new file mode 100644
index 0000000000000..58bbbb0d33129
--- /dev/null
+++ b/pci/pci-really-fix-parent-s-subordinate-busnr.patch
@@ -0,0 +1,33 @@
+From kristen.c.accardi@intel.com Tue Jan 17 16:54:14 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: PCI: really fix parent's subordinate busnr
+Cc: <len.brown@intel.com>, <pavel@ucw.cz>
+Date: Tue, 17 Jan 2006 16:57:01 -0800
+Message-Id: <1137545822.19858.48.camel@whizzy>
+
+After you find the maximum value of the subordinate buses below the child
+bus, you must fix the parent's subordinate bus number again, otherwise
+it may be too small.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/pci/probe.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- gregkh-2.6.orig/drivers/pci/probe.c
++++ gregkh-2.6/drivers/pci/probe.c
+@@ -537,6 +537,11 @@ int __devinit pci_scan_bridge(struct pci
+ pci_fixup_parent_subordinate_busnr(child, max);
+ /* Now we can scan all subordinate buses... */
+ max = pci_scan_child_bus(child);
++ /*
++ * now fix it up again since we have found
++ * the real value of max.
++ */
++ pci_fixup_parent_subordinate_busnr(child, max);
+ } else {
+ /*
+ * For CardBus bridges, we leave 4 bus numbers
diff --git a/pci/pci-return-max-reserved-busnr.patch b/pci/pci-return-max-reserved-busnr.patch
new file mode 100644
index 0000000000000..074134e4737c9
--- /dev/null
+++ b/pci/pci-return-max-reserved-busnr.patch
@@ -0,0 +1,58 @@
+From kristen.c.accardi@intel.com Tue Jan 17 16:54:10 2006
+From: Kristen Accardi <kristen.c.accardi@intel.com>
+Subject: PCI: return max reserved busnr
+Cc: <len.brown@intel.com>, <pavel@ucw.cz>
+Date: Tue, 17 Jan 2006 16:56:56 -0800
+Message-Id: <1137545816.19858.46.camel@whizzy>
+
+Change the semantics of this call to return the max reserved
+bus number instead of just the max assigned bus number.
+
+Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/pci/pci.c | 5 +++--
+ include/linux/pci.h | 1 +
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/pci/pci.c
++++ gregkh-2.6/drivers/pci/pci.c
+@@ -19,7 +19,6 @@
+ #include <asm/dma.h> /* isa_dma_bridge_buggy */
+ #include "pci.h"
+
+-#if 0
+
+ /**
+ * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
+@@ -34,7 +33,7 @@ pci_bus_max_busnr(struct pci_bus* bus)
+ struct list_head *tmp;
+ unsigned char max, n;
+
+- max = bus->number;
++ max = bus->subordinate;
+ list_for_each(tmp, &bus->children) {
+ n = pci_bus_max_busnr(pci_bus_b(tmp));
+ if(n > max)
+@@ -42,7 +41,9 @@ pci_bus_max_busnr(struct pci_bus* bus)
+ }
+ return max;
+ }
++EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
+
++#if 0
+ /**
+ * pci_max_busnr - returns maximum PCI bus number
+ *
+--- gregkh-2.6.orig/include/linux/pci.h
++++ gregkh-2.6/include/linux/pci.h
+@@ -516,6 +516,7 @@ int pci_scan_bridge(struct pci_bus *bus,
+ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
+ void *userdata);
+ int pci_cfg_space_size(struct pci_dev *dev);
++unsigned char pci_bus_max_busnr(struct pci_bus* bus);
+
+ /* kmem_cache style wrapper around pci_alloc_consistent() */
+